Commit 47ace827 authored by Daniel Bourgault's avatar Daniel Bourgault
Browse files

The cdoe can now deal with GCPs with eleation. Plus the code now comes with m_map.

parent 13a4218a
...@@ -33,20 +33,18 @@ dH = 0.0; ...@@ -33,20 +33,18 @@ dH = 0.0;
dtheta = 20.0; dtheta = 20.0;
% Order of the polynomial correction (0, 1 or 2) % Order of the polynomial correction (0, 1 or 2)
polyOrder = 1; polyOrder = 0;
% To save memory calculation can be done in single precision. % To save memory calculation can be done in single precision.
% For higher precision set the variable 'precision' to 'double'; % For higher precision set the variable 'precision' to 'double';
precision = 'double'; precision = 'double';
% Ground Control Points (GCP). % Ground Control Points (GCP).
% The data must come right after the gcpData = true % The data must come right after the gcpData = true
gcpData = true; gcpData = true;
360 829 -70.561367 47.303783 360 829 -70.561367 47.303783 0
54 719 -70.54500 47.335 54 719 -70.54500 47.335 0
99 661 -70.505 47.375 99 661 -70.505 47.375 0
452 641 -70.435 47.389 452 641 -70.435 47.389 0
429 633 -70.418 47.408 429 633 -70.418 47.408 0
816 644 -70.393 47.368 816 644 -70.393 47.368 0
\ No newline at end of file \ No newline at end of file
...@@ -45,18 +45,18 @@ precision = 'double'; ...@@ -45,18 +45,18 @@ precision = 'double';
% Ground Control Points (GCP). % Ground Control Points (GCP).
gcpData = true; gcpData = true;
2999 226 0.500 0.00 2999 226 0.500 0.00 0
1694 220 1.500 0.00 1694 220 1.500 0.00 0
528 677 2.290 0.50 528 677 2.290 0.50 0
289 1231 2.290 1.00 289 1231 2.290 1.00 0
3819 686 0.000 0.50 3819 686 0.000 0.50 0
4018 1266 0.000 1.00 4018 1266 0.000 1.00 0
2566 1235 0.890 0.99 2566 1235 0.890 0.99 0
3806 2118 0.255 1.56 3806 2118 0.255 1.56 0
4131 1580 0.000 1.23 4131 1580 0.000 1.23 0
521 2548 1.910 1.82 521 2548 1.910 1.82 0
248 2328 2.060 1.71 248 2328 2.060 1.71 0
14 1868 2.290 1.46 14 1868 2.290 1.46 0
......
...@@ -4,7 +4,7 @@ function errGeoFit = g_error_geofit(cv,imgWidth,imgHeight,xp,yp,ic,jc,... ...@@ -4,7 +4,7 @@ function errGeoFit = g_error_geofit(cv,imgWidth,imgHeight,xp,yp,ic,jc,...
hfovGuess,lambdaGuess,phiGuess,HGuess,thetaGuess,... hfovGuess,lambdaGuess,phiGuess,HGuess,thetaGuess,...
dhfov,dlambda,dphi,dH,dtheta,... dhfov,dlambda,dphi,dH,dtheta,...
LON0,LAT0,... LON0,LAT0,...
i_gcp,j_gcp,lon_gcp,lat_gcp,... i_gcp,j_gcp,lon_gcp0,lat_gcp0,h_gcp,...
theOrder,field); theOrder,field);
...@@ -20,7 +20,6 @@ end ...@@ -20,7 +20,6 @@ end
[LON LAT] = g_pix2ll(xp,yp,imgWidth,imgHeight,ic,jc,... [LON LAT] = g_pix2ll(xp,yp,imgWidth,imgHeight,ic,jc,...
hfov,lambda,phi,theta,H,LON0,LAT0,field); hfov,lambda,phi,theta,H,LON0,LAT0,field);
% Calculate the error between ground control points (GCPs) % Calculate the error between ground control points (GCPs)
% and image control points once georectified. % and image control points once georectified.
% %
...@@ -35,8 +34,11 @@ ngcp = length(i_gcp); ...@@ -35,8 +34,11 @@ ngcp = length(i_gcp);
ngcpFinite = 0; ngcpFinite = 0;
errGeoFit = 0.0; errGeoFit = 0.0;
for k = 1:ngcp % Project the GCPs onto the water surface given their elevation
[lon_gcp,lat_gcp] = g_proj_GCP(LON0,LAT0,H,lon_gcp0,lat_gcp0,h_gcp,field);
for k = 1:ngcp
% Calculate the distance (i.e. error) between GCP and rectificed ICPs. % Calculate the distance (i.e. error) between GCP and rectificed ICPs.
distance = g_dist(lon_gcp(k),lat_gcp(k),LON(k),LAT(k),field); distance = g_dist(lon_gcp(k),lat_gcp(k),LON(k),LAT(k),field);
...@@ -63,17 +65,3 @@ if abs(phi - phiGuess) > dphi; errGeoFit = inf; end ...@@ -63,17 +65,3 @@ if abs(phi - phiGuess) > dphi; errGeoFit = inf; end
if abs(H - HGuess) > dH; errGeoFit = inf; end if abs(H - HGuess) > dH; errGeoFit = inf; end
if abs(theta - thetaGuess) > dtheta; errGeoFit = inf; end if abs(theta - thetaGuess) > dtheta; errGeoFit = inf; end
%fprintf('\n')
%fprintf('Field of view (fov): %f\n',hfov)
%fprintf('Dip angle (lambda): %f\n',lambda)
%fprintf('Tilt angle (phi): %f\n',phi)
%fprintf('Camera altitude (H): %f\n',H)
%fprintf('View angle from North (theta): %f\n',theta)
%fprintf('RMS error (m): %f\n',errGeoFit)
%fprintf('\n')
%figure(100)
%hold on;
%plot(errGeoFit);
...@@ -61,7 +61,6 @@ vfov = 2*atand(tand(hfov/2)/aspectRatio); ...@@ -61,7 +61,6 @@ vfov = 2*atand(tand(hfov/2)/aspectRatio);
fx = (imgWidth/2)/tand(hfov/2); fx = (imgWidth/2)/tand(hfov/2);
fy = (imgHeight/2)/tand(vfov/2); fy = (imgHeight/2)/tand(vfov/2);
% Subtract the principal point % Subtract the principal point
x_p = xp - x_c + (jc); x_p = xp - x_c + (jc);
y_p = yp - y_c + (ic); y_p = yp - y_c + (ic);
......
function [lon_gcp,lat_gcp] = g_proj_GCP(LON0,LAT0,H,lon_gcp0,lat_gcp0,h_gcp,field)
%G_PROJ_GCP
%
% This function projects the GCPs that have an elevation greater than 0
% onto the water level of zero elevation. This is a trick in order to be
% able to deal with GCPs that have elevation. The principle can be
% illustrated in 1D like this. Consider the position x of a GCP that has an
% elevation h. Then, the projection (xp) of this GCP onto the plane that has
% zero elevation and along a line that joins the camera position of elevation
% H and the GCP is given by:
%
% xp = x * (H - h)/H
%
% INPUTS:
%
% LON0: The longitiude of the camera
% LAT0: The latitude of the camera
% H: The elevation of the camera
% lon_gcp0: The longitudes of the GCPs
% lat_gcp0: The latitudes of the GCPs
% h_gcp: The elevations of the GCPs
%
% OUTPUTS:
% lon_gcp: The projected longitudes of the GCPs
% lat_gcp: The projected latitudes of the GCPs
%
n_gcp = length(h_gcp);
for i = 1:n_gcp
if field == true
% The calculation for the distance between the GCPs and the camera
% is done on an elliptical earth and this takes a long calculation
% with the command m_idist from the m_map package. Therefore, the
% calculation is done only on the GCPs with no elevation, hence
% the 'if' condition here.
if h_gcp(i) > 0
[range,a12,a21] = m_idist(LON0,LAT0,lon_gcp0(i),lat_gcp0(i));
proj_factor = H/(H-h_gcp(i));
new_range = range*proj_factor;
[lon_gcp(i),lat_gcp(i),a21] = m_fdist(LON0,LAT0,a12,new_range);
lon_gcp(i) = lon_gcp(i) - 360;
else
% If there's no elevation, then there's nothing to do.
lon_gcp(i) = lon_gcp0(i);
lat_gcp(i) = lat_gcp0(i);
end
else
% For lab situations where positions are provided in meters rather
% than in latitude longitude the calculation is simpler.
dx = lon_gcp0(i) - LON0;
dy = lat_gcp0(i) - LAT0;
range = sqrt(dx^2 + dy^2);
proj_factor = H/(H-h_gcp(i));
new_range = range*proj_factor;
beta = atan2(dy,dx);
lon_gcp(i) = new_range*cos(beta) + LON0;
lat_gcp(i) = new_range*sin(beta) + LAT0;
end
end
\ No newline at end of file
...@@ -5,122 +5,150 @@ function g_rect ...@@ -5,122 +5,150 @@ function g_rect
% instructions. % instructions.
% %
% Inputs: % Inputs:
% The function G_RECT reads an input parameter file that contains all % The function G_RECT reads an input parameter file that contains all
% information required to perfrorm a georectification of a given image. % information required to perfrorm a georectification of a given image.
% The format of this parameter file is detailed on-line on the G_RECT % The format of this parameter file is detailed on-line on the G_RECT
% Wiki page. % Wiki page.
% %
% Outputs: % Outputs:
% The function G_RECT creates an output file that contains the following % The function G_RECT creates an output file that contains the following
% variables: % variables:
% %
% imgFname: The reference image for the georectification. % imgFname: The reference image for the georectification.
% %
% firstImgFname: The first image of a sequence of images to which the % firstImgFname: The first image of a sequence of images to which the
% georectification could be applied to. This is really % georectification could be applied to. This is really
% just a comment. % just a comment.
% %
% lastImgFname: The last image of a sequence of images to which the % lastImgFname: The last image of a sequence of images to which the
% georectification could be applied to. This is really % georectification could be applied to. This is really
% just a comment. % just a comment.
% %
% LON: The main matrix that contain the longitude of each % LON: The main matrix that contain the longitude of each
% pixel of the referecne image (imgFname). Note that % pixel of the referecne image (imgFname). Note that
% if the package is used to rectify lab images this % if the package is used to rectify lab images this
% matrix rather contains the distance in meters from % matrix rather contains the distance in meters from
% a predefined x-origin. % a predefined x-origin.
% %
% LAT: Same as LON but for the latitude. % LAT: Same as LON but for the latitude.
% %
% LON0: A scalar for the longitude of the camera or, in the % LON0: A scalar for the longitude of the camera or, in the
% case of a lab setup its cartesian coordinate in meters. % case of a lab setup its cartesian coordinate in meters.
% %
% LAT0: Same as LON0 but for the latitude. % LAT0: Same as LON0 but for the latitude.
% %
% lon_gcp: A vector containing the longitude of each ground % lon0_gcp: A vector containing the longitude of each ground
% control points (GCP). For the lab case this is the % control points (GCP). For the lab case this is the
% cartesian coordinate in meters. % cartesian coordinate in meters. These GCPs may have
% % elevations.
%
% lat0_gcp: Same as lon_gcp for latitude.
%
% lon_gcp: A vector containing the longitude of each ground
% control points (GCP) projected onto the water level
% i.e. at 0 m of elevation. For the lab case this is
% the cartesian coordinate in meters.
%
% lat_gcp: Same as lon_gcp for latitude. % lat_gcp: Same as lon_gcp for latitude.
% %
% h_gcp: The elevation in meter of the GCPs. The elevation is
% 0 m if taken at water level.
%
% i_gcp: The horizontal index of the image ground control % i_gcp: The horizontal index of the image ground control
% points. % points.
% %
% j_gcp: The vertical index of the image ground control % j_gcp: The vertical index of the image ground control
% points. % points.
% %
% hfov: The camera horizontal field of view [degree]. % hfov: The camera horizontal field of view [degree].
% %
% phi: Camera tilt angle [degree]. % phi: Camera tilt angle [degree].
% %
% lambda: Camera dip angle [degree].
%
% H: The camera altitude relative to the water [m]. % H: The camera altitude relative to the water [m].
% %
% theta: View angle clockwise from North [degree]. % theta: View angle clockwise from North [degree].
% %
%
% errGeoFit: The rms error of the georectified image after % errGeoFit: The rms error of the georectified image after
% geometrical transformation [m]. % geometrical transformation [m].
% %
% errPolyFit: The rms error of the georectified image after % errPolyFit: The rms error of the georectified image after
% geometrical transformation and the polynomial % geometrical transformation and the polynomial
% correction [m]. % correction [m].
% %
% precision: Calculation can be done in single or double % precision: Calculation can be done in single or double
% precisions as defined by the user in the parameter % precisions as defined by the user in the parameter
% file. With today's computers this is now obsolete % file. With today's computers this is now obsolete
% and calculations can always be done in double % and calculations can always be done in double
% precision. % precision.
% %
% Delta: The effective resolution of the georectified image.
% %
% Other m-files required: Works best with the m_map package for % Other m-files required: Works best with the m_map package for
% visualization. % visualization.
% Subfunctions: all functions contained within the G_RECT folder. % Subfunctions: all functions contained within the G_RECT folder.
% %
% Author: Daniel Bourgault % Author: Daniel Bourgault
% Institut des sciences de la mer de Rimouski % Institut des sciences de la mer de Rimouski
% email: daniel_bourgault@uqar.ca % email: daniel_bourgault@uqar.ca
% Website: https://srwebpolr01.uqar.ca/g_rect/ % Website: https://srwebpolr01.uqar.ca/g_rect/
% February 2013 % February 2013
% %
% %%
% The minimization is repeated nMinimize times where each time a random % The minimization is repeated nMinimize times where each time a random
% combination of the initial guesses is chosen within the given % combination of the initial guesses is chosen within the given
% uncertainties provided by the user. This is becasue the algorithm often % uncertainties provided by the user. This is becasue the algorithm often
% converges toward a local minimum. The repetition is used to increase chances % converges toward a local minimum. The repetition is used to increase chances
% that the minimum found is a true minimum within the uncertainties provided. % that the minimum found is a true minimum within the uncertainties provided.
nMinimize = 50; nMinimize = 50;
%% Read the parameter file %% Read the parameter file
% Count the number of header lines before the ground control points (GCPs) % Count the number of header lines before the ground control points (GCPs)
% The GCPs start right after the variable gcpData is set to true. % The GCPs start right after the variable gcpData is set to true.
display(' '); display(' ');
display(' Welcome to g_rect: a package for georectifying oblique images on a flat ocean'); display(' Welcome to g_rect: a package for georectifying oblique images on a flat ocean');
display(' Authors: Daniel Bourgault and Rich Pawlowicz'); display(' Authors: Daniel Bourgault and Rich Pawlowicz');
display(' '); display(' ');
inputFname = input(' Enter the filename for the input parameters: ','s'); inputFname = input(' Enter the filename for the input parameters: ','s');
fid = fopen(inputFname); fid = fopen(inputFname);
nHeaderLine = 0; nHeaderLine = 0;
gcpData = false; gcpData = false;
% Read and execute each line of the parameter file until gcpData = true % Read and execute each line of the parameter file until gcpData = true
% after which the GCP data appear and are read below with the importdata % after which the GCP data appear and are read below with the importdata
% function. % function.
while gcpData == false while gcpData == false
eval(fgetl(fid)); eval(fgetl(fid));
nHeaderLine = nHeaderLine + 1; nHeaderLine = nHeaderLine + 1;
end end
fclose(fid); fclose(fid);
%% Import the GCP data (4 column) at the end of the parameter file %% Import the GCP data at the end of the parameter file
gcp = importdata(inputFname,' ',nHeaderLine) gcp = importdata(inputFname,' ',nHeaderLine);
i_gcp = gcp.data(:,1); i_gcp = gcp.data(:,1);
j_gcp = gcp.data(:,2); j_gcp = gcp.data(:,2);
lon_gcp = gcp.data(:,3); lon_gcp0 = gcp.data(:,3);
lat_gcp = gcp.data(:,4); lat_gcp0 = gcp.data(:,4);
ngcp = length(i_gcp); h_gcp = gcp.data(:,5);
%%
% Check if the elevation of the GCPs are not too high and above
% a certain fraction (gamma) of the camera height. If so, stop.
gamma = 0.75;
i_bad = find(h_gcp > gamma*(H+dH));
if length(i_bad) > 0
display([' ']);
display([' WARNING:']);
for i = 1:length(i_bad)
display([' The elevation of GCP #',num2str(i_bad(i)),' is greater than ',num2str(gamma),'*(H+dH).']);
end
display([' FIX AND RERUN.']);
return
end
ngcp = length(i_gcp);
% Get the image size % Get the image size
imgInfo = imfinfo(imgFname); imgInfo = imfinfo(imgFname);
...@@ -128,12 +156,11 @@ imgWidth = imgInfo.Width; ...@@ -128,12 +156,11 @@ imgWidth = imgInfo.Width;
imgHeight = imgInfo.Height; imgHeight = imgInfo.Height;
if precision == 'single' if precision == 'single'
imgWidth = single(imgWidth); imgWidth = single(imgWidth);
imgHeight = single(imgHeight); imgHeight = single(imgHeight);
end end
%% Display information
%% Display information
fprintf('\n') fprintf('\n')
fprintf(' INPUT PARAMETERS\n') fprintf(' INPUT PARAMETERS\n')
fprintf(' Image filename: (imgFname):........... %s\n',imgFname) fprintf(' Image filename: (imgFname):........... %s\n',imgFname)
...@@ -168,22 +195,23 @@ imagesc(imread(imgFname)); ...@@ -168,22 +195,23 @@ imagesc(imread(imgFname));
colormap(gray); colormap(gray);
hold on hold on
for i = 1:ngcp for i = 1:ngcp
plot(i_gcp(i),j_gcp(i),'r.'); plot(i_gcp(i),j_gcp(i),'r.');
text(i_gcp(i),j_gcp(i),num2str(i),'color','r','horizontalalignment','right'); text(i_gcp(i),j_gcp(i),[num2str(i),'(',num2str(h_gcp(i)),')'],...
'color','r',...
'horizontalalignment','right',...
'fontsize',16);
end end
title('Ground Control Points','color','r'); title('Ground Control Points Number (elevation in meters)','color','r');
print -dpng -r300 image1.png print -dpng -r300 image1.png
fprintf('\n') fprintf('\n')
ok = input('Is it ok to proceed with the rectification (y/n): ','s'); ok = input('Is it ok to proceed with the rectification (y/n): ','s');
if ok ~= 'y' if ok ~= 'y'
return return
%break
end end
%% %%
nUnknown = 0; nUnknown = 0;
if dhfov > 0.0; nUnknown = nUnknown+1; end if dhfov > 0.0; nUnknown = nUnknown+1; end
if dlambda > 0.0; nUnknown = nUnknown+1; end if dlambda > 0.0; nUnknown = nUnknown+1; end
...@@ -192,154 +220,153 @@ if dH > 0.0; nUnknown = nUnknown+1; end ...@@ -192,154 +220,153 @@ if dH > 0.0; nUnknown = nUnknown+1; end
if dtheta > 0.0; nUnknown = nUnknown+1; end if dtheta > 0.0; nUnknown = nUnknown+1; end
if nUnknown > ngcp if nUnknown > ngcp
fprintf('\n') fprintf('\n')
fprintf('WARNING: \n'); fprintf('WARNING: \n');
fprintf(' The number of GCPs is < number of unknown parameters.\n'); fprintf(' The number of GCPs is < number of unknown parameters.\n');
fprintf(' Program stopped.\n'); fprintf(' Program stopped.\n');
%break return
return
end end
% Check for consistencies between number of GCPs and order of the polynomial % Check for consistencies between number of GCPs and order of the polynomial
% correction % correction
ngcp = length(i_gcp); ngcp = length(i_gcp);
if ngcp < 3*polyOrder if ngcp < 3*polyOrder
fprintf('\n') fprintf('\n')
fprintf('WARNING: \n'); fprintf('WARNING: \n');
fprintf(' The number of GCPs is inconsistent with the order of the polynomial correction.\n'); fprintf(' The number of GCPs is inconsistent with the order of the polynomial correction.\n');
fprintf(' ngcp should be >= 3*polyOrder.\n'); fprintf(' ngcp should be >= 3*polyOrder.\n');
fprintf(' Polynomial correction will not be applied.\n'); fprintf(' Polynomial correction will not be applied.\n');
polyCorrection = false; polyCorrection = false;
else else
polyCorrection = true; polyCorrection = true;
end end
if polyOrder == 0 if polyOrder == 0
polyCorrection = false; polyCorrection = false;
end end
%% This is the main section for the minimization algorithm %% This is the main section for the minimization algorithm
if nUnknown > 0 if nUnknown > 0
% Options for the fminsearch function. May be needed for some particular % Options for the fminsearch function. May be needed for some particular
% problems but in general the default values should work fine. % problems but in general the default values should work fine.
%options=optimset('MaxFunEvals',100000,'MaxIter',100000); %options=optimset('MaxFunEvals',100000,'MaxIter',100000);
%options=optimset('MaxFunEvals',100000,'MaxIter',100000,'TolX',1.d-12,'TolFun',1.d-12); %options=optimset('MaxFunEvals',100000,'MaxIter',100000,'TolX',1.d-12,'TolFun',1.d-12);
options = []; options = [];
% Only feed the minimization algorithm with the GCPs. xp and yp are the
% image coordinate of these GCPs.
xp = i_gcp;
yp = j_gcp;
% Only feed the minimization algorithm with the GCPs. xp and yp are the % This is the call to the minimization
% image coordinate of these GCPs. bestErrGeoFit = Inf;
xp = i_gcp;
yp = j_gcp; % Save inital guesses in new variables.
hfovGuess = hfov;
% This is the call to the minimization lambdaGuess = lambda;
bestErrGeoFit = Inf; phiGuess = phi;
HGuess = H;
% Save inital guesses in new variables. thetaGuess = theta;
hfovGuess = hfov;
lambdaGuess = lambda; for iMinimize = 1:nMinimize
phiGuess = phi;