www.gusucode.com > map 案例源码 matlab代码程序 > map/mapexreg.m

    %% Georeferencing an Image to an Orthotile Base Layer
%
% This example shows how to register an image to an earth coordinate system
% and create a new "georeferenced" image.  It requires Image Processing
% Toolbox(TM) in addition to Mapping Toolbox(TM).
%
% In this example, all georeferenced data are in the same earth coordinate
% system, the Massachusetts State Plane system (using the North American
% Datum of 1983 in units of meters). This defines our "map coordinates."
% The georeferenced data include an orthoimage base layer and a vector road
% layer.
%
% The data set to be georeferenced is a digital aerial photograph covering
% parts of the village of West Concord, Massachusetts, collected in early
% spring, 1997.

% Copyright 1996-2014 The MathWorks, Inc. 

%% Step 1: Render Orthoimage Base Tiles in Map Coordinates
%
% The orthoimage base layer is structured into 4000-by-4000 pixel tiles,
% with each pixel covering exactly one square meter in map coordinates.
% Each tile is stored as a TIFF image with a world file. The aerial
% photograph of West Concord overlaps two tiles in the orthoimage base
% layer. (For convenience, this example actually works with two 2000-by-2000
% sub-tiles extracted from the larger 4000-by-4000 originals.  They
% have the same pixel size, but cover only the area of interest.)

%%
% Read the two orthophoto base tiles required to cover the extent of the
% aerial image. 

[baseImage1,cmap1] = imread('concord_ortho_w.tif');
[baseImage2,cmap2] = imread('concord_ortho_e.tif');

%%
% Read the worldfiles for the two tiles

currentFormat = get(0,'format');
format short g
R1 = worldfileread('concord_ortho_w.tfw','planar',size(baseImage1))
R2 = worldfileread('concord_ortho_e.tfw','planar',size(baseImage2))

%%
% Display the images in their correct spatial positions.

mapshow(baseImage1,cmap1,R1)
ax1 = gca; 
mapshow(ax1,baseImage2,cmap2,R2)
title('Map View, Massachusetts State Plane Coordinates');
xlabel('Easting (meters)');
ylabel('Northing (meters)');

%% Step 2: Register Aerial Photograph to Map Coordinates
%
% This step uses functions |cpselect|, |cpstruct2pairs|, |fitgeotrans|, and
% |imwarp|, and method |projective2d/transformPointsForward|, from the
% Image Processing together with map raster reference objects from Mapping
% Toolbox.  Together, they enable georegistration based on control point
% pairs that relate the aerial photograph to the orthoimage base layer.

%%
% Read the aerial photo.
inputImage = imread('concord_aerial_sw.jpg');
figure
imshow(inputImage)
title('Unregistered Aerial Photograph')

%%
% Both orthophoto images are indexed images but |cpselect| only takes
% grayscale images, so convert them to grayscale.
baseGray1 = im2uint8(ind2gray(baseImage1,cmap1));
baseGray2 = im2uint8(ind2gray(baseImage2,cmap2));

%%
% Downsample the images by a factor of 2, then pick two separate sets of
% control point pairs: one for points in the aerial image that appear in the
% first tile, and another for points that appear in the second tile.  Save
% the control point pairs to the base workspace as control point structures
% named cpstruct1 and cpstruct2.

n = 2; % downsample by a factor n
load mapexreg.mat % load some points that were already picked

%%
% Optionally, edit or add to the pre-picked points using |cpselect|.  Note
% that you need to work separately on the control points for each orthotile.
% 
%  cpselect(inputImage(1:n:end,1:n:end,1),...
%           baseGray1(1:n:end,1:n:end),cpstruct1);
% 
%  cpselect(inputImage(1:n:end,1:n:end,1),...
%           baseGray2(1:n:end,1:n:end),cpstruct2); 

%%
% This tool helps you pick pairs of corresponding control points. Control
% points are landmarks that you can find in both images, like a road
% intersection, or a natural feature. Three pairs of control points have
% already been picked for each orthophoto tile. If you want to proceed with
% these points, go to Step 3: Infer and apply geometric transformation. If
% you want to add some additional pairs of points, do so by identifying
% landmarks and clicking on the images. Save control points by choosing the
% *File* menu, then the *Save Points to Workspace* option. Save the points,
% overwriting variables |cpstruct1| and |cpstruct2|.

%% Step 3: Infer and Apply Geometric Transformation
% Extract control point pairs from the control point structures.
[input1,base1] = cpstruct2pairs(cpstruct1);
[input2,base2] = cpstruct2pairs(cpstruct2);

%%
% Account for downsampling by factor n.
input1 = n*input1 - 1;
input2 = n*input2 - 1;
base1 = n*base1 - 1;
base2 = n*base2 - 1;

%%
% Transform base image coordinates into map (State Plane) coordinates.
[x1, y1] = intrinsicToWorld(R1, base1(:,1), base1(:,2));
[x2, y2] = intrinsicToWorld(R2, base2(:,1), base2(:,2));

%%
% Combine the two sets of control points and infer a projective
% transformation. (The projective transformation should be a reasonable
% choice, since the aerial image is from a frame camera and the terrain in
% this area is fairly gentle.)
input = [input1; input2];
spatial = [x1 y1; x2 y2];

tform = fitgeotrans(input,spatial,'projective')

%%
% Compute and plot (2D) residuals.
residuals = transformPointsForward(tform, input) - spatial;
figure
plot(residuals(:,1),residuals(:,2),'+')
title('Control Point Residuals');
xlabel('Easting offset (meters)');
ylabel('Northing offset (meters)');
xlim([-4 4])
ylim([-4 4])
axis equal

%%
% Predict corner locations for the registered image, in map coordinates,
% and connect them to show the image outline.
mInput = size(inputImage,1);
nInput = size(inputImage,2);

inputCorners = 0.5 ...
    + [0        0;
       0        mInput; 
       nInput   mInput;
       nInput   0;
       0        0];
            
outputCornersSpatial = transformPointsForward(tform, inputCorners);

outputCornersX = outputCornersSpatial(:,1);
outputCornersY = outputCornersSpatial(:,2);

figure(ax1.Parent)
line(outputCornersX,outputCornersY,'Color','w')

%%
% Calculate the average pixel size of the input image (in map units). 

pixelSize = [hypot( ...
    outputCornersX(2) - outputCornersX(1), ...
    outputCornersY(2) - outputCornersY(1)) / mInput, ...
 hypot( ...
    outputCornersX(4) - outputCornersX(5), ...
    outputCornersY(4) - outputCornersY(5)) / nInput]

%%
% Variable |pixelSize| gives a starting point from which to select a width
% and height for the pixels in our georegistered output image.  In
% principle we could select any size at all for our output pixels. However,
% if we make them too small we waste memory and computation time, ending up
% with a big (many rows and columns) blurry image.  If we make them too
% big, we risk aliasing the image as well as needlessly discarding 
% information in the original image.  In general we also want our pixels to
% be square.  A reasonable heuristic is to select a pixel size that is
% slightly larger than |max(pixelSize)| and is a "reasonable" number (i.e.,
% 0.95 or 1.0 rather than 0.9096).  Here we chose 1, which means that each
% pixel in our georegistered image will cover one square meter on the
% ground.  It's "nice" to have georegistered images that align along
% integer map coordinates for display and analysis.
outputPixelSize = 1;

%%
% Choose world limits that are integer multiples of the output pixel size.

xWorldLimits = outputPixelSize ...
    * [floor(min(outputCornersX) / outputPixelSize), ...
        ceil(max(outputCornersX) / outputPixelSize)]

yWorldLimits = outputPixelSize ...
    * [floor(min(outputCornersY) / outputPixelSize), ...
        ceil(max(outputCornersY) / outputPixelSize)]
    
%%
% Display a bounding box for the registered image.
line(xWorldLimits([1 1 2 2 1]),yWorldLimits([2 1 1 2 2]),'Color','red')

%%
% The dimensions of the registered image will be as follows:

mOutput = diff(yWorldLimits) / outputPixelSize
nOutput = diff(xWorldLimits) / outputPixelSize

%%
% Create an Image Processing Toolbox referencing object for the registered
% image.

R = imref2d([mOutput nOutput],xWorldLimits,yWorldLimits)

%%
% The Mapping Toolbox counterpart to Rregistered is a map raster reference
% object.
Rmap = maprasterref('RasterSize',R.ImageSize, ...
    'XWorldLimits',R.XWorldLimits,'YWorldLimits',R.YWorldLimits, ...
    'ColumnsStartFrom','north')

%%
% Apply the geometric transformation using |imwarp|. Flip its output so
% that the columns run from north to south.
registered = flipud(imwarp(inputImage, tform, 'OutputView', R));
figure
imshow(registered)

format(currentFormat)

%%
% You can write the registered image as a TIFF with a world file, thereby
% georeferencing it to our map coordinates.
%
%  imwrite(registered,'concord_aerial_sw_reg.tif');
%  worldfilewrite(Rmap,getworldfilename('concord_aerial_sw_reg.tif'));

%% Step 4: Display the Registered Image in Map Coordinates
%
% Display the registered image on the same (map coordinate) axes as the
% orthoimage base tiles. The registered image does not completely fill its
% bounding box, so it includes null-filled triangles.  Create an alpha data
% mask to make these fill areas render as transparent.
alphaData = registered(:,:,1);
alphaData(alphaData~=0) = 255;

figure
mapshow(baseImage1,cmap1,R1)
ax2 = gca; 
mapshow(ax2,baseImage2,cmap2,R2)
title('Map View, Massachusetts State Plane Coordinates');
xlabel('Easting (meters)');
ylabel('Northing (meters)');

mInput = mapshow(ax2,registered,Rmap);
mInput.AlphaData = alphaData;

%%
% You can assess the registration by looking at features that span both
% the registered image and the orthophoto images. 

%% Step 5: Overlay Vector Road Layer (from Shapefile) 
%
% Use |shapeinfo| and |shaperead| to learn about the attributes of the
% vector road layer. Render the roads on the same axes and the base tiles
% and registered image.

roadsfile = 'concord_roads.shp';
roadinfo = shapeinfo(roadsfile);
roads = shaperead(roadsfile);

%%
% Create symbolization based on the CLASS attribute (the type of road). Note
% that very minor roads have CLASS values equal to 6, so don't display them.
roadspec = makesymbolspec('Line',{'CLASS',6,'Visible','off'});

mapshow(ax2,roads,'SymbolSpec',roadspec,'Color','cyan')

%% 
% Observe that the |roads| line up quite well with the roads in the
% images. Two obvious linear features in the images are not roads but
% railroads. The linear feature that trends roughly east-west and crosses
% both base tiles is the Fitchburg Commuter Rail Line of the Massachusetts
% Bay Transportation Agency. The linear feature that trends roughly
% northwest-southeast is the former Framingham-Lowell secondary line.


%% Credits
% concord_orthow_w.tif, concord_ortho_e.tif, concord_roads.shp:
%
%    Office of Geographic and Environmental Information (MassGIS),
%    Commonwealth of Massachusetts  Executive Office of Environmental Affairs
%    http://www.state.ma.us/mgis
%
%    For more information, run: 
%    
%    >> type concord_ortho.txt
%    >> type concord_roads.txt
%
% concord_aerial_sw.jpg
%
%    Visible color aerial photograph courtesy of mPower3/Emerge.
%
%    For more information, run: 
%    
%    >> type concord_aerial_sw.txt
%