function [t1,t2] = estimateUncalibratedRectification(...
  f,matched_points1,matched_points2,imageSize)
%estimateUncalibratedRectification Uncalibrated stereo rectification.
%   [T1,T2] = estimateUncalibratedRectification(
%     F,MATCHED_POINTS1,MATCHED_POINTS2,IMAGESIZE) returns projective 
%   transformations for rectifying stereo images. This function does not
%   require either intrinsic nor extrinsic camera parameters.
% 
%     MATCHED_POINTS1 and MATCHED_POINTS2 are the coordinates of
%     corresponding points in the stereo images I1 and I2, respectively.
%     Each row of MATCHED_POINTS1 or MATCHED_POINTS2 has the format of
%     [x,y] which determines the location of a point. Both
%     MATCHED_POINTS1 and MATCHED_POINTS2 are M-by-2 matrices, where M is
%     the number of points.
% 
%     F is a 3-by-3 fundamental matrix for the stereo images. If P1, a
%     point in I1, corresponds to P2, a point in I2, then 
%     [P2,1] * F * [P1,1]' = 0.
% 
%     IMAGESIZE is the size of I2, and is in the format returned by
%     the function SIZE. 
% 
%     T1 and T2 are 3-by-3 matrices describing the projective
%     transformations for I1 and I2, respectively.
% 
%   Note that applying T1 (or T2) to I1 (or I2) may result in an undesired
%   distortion, if the epipole is located within I1 (or I2). You can use
%   function isEpipoleInImage to check if the epipole is inside the image.
% 
%   Class Support
%   -------------
%   F must be double or single. MATCHED_POINTS1, MATCHED_POINTS2, and
%   IMAGESIZE must be double, single, or integer. T1 and T2 have the same
%   class as F.
% 
%   Example 1
%   ---------
%   % Load the stereo images and convert them to double precision.
%   I1 = imread('yellowstone_left.png');
%   I2 = imread('yellowstone_right.png');
% 
%   % Load the points which are already matched.
%   load yellowstone_matched_points;
% 
%   % Compute the fundamental matrix from the corresponding points.
%   f= estimateFundamentalMatrix(matched_points1, matched_points2,...
%     'Method', 'Norm8Point');
% 
%   % Display the original stereo images, corresponding points, and 
%   % epipolar lines.
%   cvexShowStereoImages('Original image 1', 'Original image 2', ...
%     I1, I2, matched_points1, matched_points2, f);
% 
%   % Compute the rectification transformations.
%   [t1, t2] = estimateUncalibratedRectification(f,...
%     matched_points1, matched_points2, size(I2));
% 
%   if isEpipoleInImage(f, size(I1)) || isEpipoleInImage(f', size(I2))
%     error(['For the rectification to succeed, the epipoles must be',...
%       'outside the images.']);
%   end
% 
%   % Rectify the stereo images using the projective transformations t1 and
%   % t2 and display the resulting images, corresponding points, and 
%   % epipolar lines.
%   cvexShowStereoImages('Rectified image 1', 'Rectified image 2',...
%     I1, I2, matched_points1, matched_points2, f, t1, t2);
%
%   Example 2
%   ---------
%   % Automatically register and rectify stereo images. This example
%   % detects corners in stereo images, matches the corners, computes
%   % the fundamental matrix, and then rectifies the images. 
%   % <a href="matlab:web(fullfile(matlabroot,'toolbox','vision','visiondemos','html','videorectification.html'))">View example</a>
% 
% See also estimateFundamentalMatrix, isEpipoleInImage,
%   vision.CornerDetector, extractFeatures, matchFeatures, 
%   vision.GeometricTransformer
% 
% References:
%   R. Hartley, A. Zisserman, "Multiple View Geometry in Computer Vision,"
%   Cambridge University Press, 2003.

% Copyright 2010 The MathWorks, Inc.
% $Revision: 1.1.6.4 $  $Date: 2011/04/02 01:28:58 $

%--------------------------------------------------------------------------
% Check the inputs.
%--------------------------------------------------------------------------
isXY = cvstGetCoordsChoice('fcnEstimateUncalibratedRectification');
checkInputs(f, matched_points1, matched_points2, imageSize, isXY);

%--------------------------------------------------------------------------
% Compute the projective transformations.
%--------------------------------------------------------------------------
[t1, t2] = cvalgEstimateUncalibratedRectification(f, ...
  matched_points1, matched_points2, imageSize, isXY);

%==========================================================================
function checkInputs(f, matched_points1, matched_points2, imageSize, isXY)
%--------------------------------------------------------------------------
% Check the Fundamental matrix
%--------------------------------------------------------------------------
validateattributes(f, {'double', 'single'}, ...
  {'2d', 'nonsparse', 'nonempty', 'real', 'size', [3,3]},...
  mfilename, 'F');

%--------------------------------------------------------------------------
% Check the image size
%--------------------------------------------------------------------------
validateattributes(imageSize, {'single', 'double', 'int8', 'int16', ...
  'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64'}, ...
  {'vector', 'nonsparse', 'nonempty', 'real', 'positive', 'integer'},...
  mfilename, 'IMAGESIZE');

if length(imageSize) < 2
  error('vision:estimateUncalibratedRectification:invalidImageSize', ...
    'Expected IMAGESIZE to be a vector of two or more elements.');
end

%--------------------------------------------------------------------------
% Check the points
%--------------------------------------------------------------------------
checkPts('MATCHED_POINTS1', matched_points1, isXY);
checkPts('MATCHED_POINTS2', matched_points2, isXY);

if isXY
  if size(matched_points1, 1) ~= size(matched_points2, 1)
    error('vision:estimateUncalibratedRectification:invalidPtsNumCol', ...
      ['Expected MATCHED_POINTS1 and MATCHED_POINTS2 to have the same '...
      'number of rows.']);
  end
else
  if size(matched_points1, 2) ~= size(matched_points2, 2)
    error('vision:estimateUncalibratedRectification:invalidPtsNumCol', ...
      ['Expected MATCHED_POINTS1 and MATCHED_POINTS2 to have the same '...
      'number of columns.']);
  end
end

%==========================================================================
function checkPts(name, value, isXY)
if isXY
  ptsSize = [NaN, 2];
else
  ptsSize = [2, NaN];
end

validateattributes(value, {'single', 'double', 'int8', 'int16', ...
  'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64'}, ...
  {'2d', 'nonsparse', 'nonempty', 'real', 'size', ptsSize},...
  mfilename, name);
