clear all;

numberOfPoints = 2; % number of user selected points
sampleRadius = 32;  % radius of subImage around selected point
pickPoints = 0;     % switch to pick points or to use default points

% read in all the images and square them
image1 = double(imread('canyon1-2.png'));
image1sq = image1.^2;
size1h = size(image1, 1);
size1w = size(image1, 2);

image2 = double(imread('canyon2-2.png'));
image2sq = image2.^2;
size2h = size(image2, 1);
size2w = size(image2, 2);

userX = []; % user selected points in first image
userY = []; % user selected points in first image

if (pickPoints)
    % display unaltered image
    figure('Name', 'Raw Images', 'Position', [0 0 1200 400]);
    subplot(1, 2, 1); imagesc(image1); axis square; colormap gray; xlabel('Select Points To Match In This Image'); hold on;
    subplot(1, 2, 2); imagesc(image2); axis square; colormap gray; xlabel('Second Image'); hold on;



    % for number of points loops and stores inputted points in array

    for i = 1:numberOfPoints
       [tempy, tempx] = ginput(1);
       tempx = round(tempx);
       tempy = round(tempy);
       userX = [userX ; tempx];
       userY = [userY ; tempy];
       plot(tempy, tempx, 'r+');
       t = text(tempy + 10, tempx, num2str(i));
       set(t, 'Color', [1 0 0]);
    end
else
   userX = [150 200 150];
   userY = [150 200 200];  
end

% userX = [400 500];
% userY = [400 500];

% attempt to find matching point for each point in second image
% find by taking sub image around selected point, and using minimum
% squared error template matching
% if matching point is found, mark it with an x

Xoffset1 = [];  % list of x coordinates of points in image1
Xoffset2 = [];  % list of x coordinates of points in image2
Yoffset1 = [];  % list of y coordinates of points in image1
Yoffset2 = [];  % list of y coordinates of points in image2

image1F = fft2(image1);
image2F = fft2(image2);

image1sqF = fft2(image1sq);
image2sqF = fft2(image2sq);

mask = zeros(size1h, size1w);
mask(1:sampleRadius, 1:sampleRadius) = 1.0;
maskF = fft2(mask);

for i = 1:numberOfPoints

    % fix this!  both coordinates have to match for some reason
    % examples -> userX(i) == userY(i).  Why?
    subImage = image1(userX(i):(userX(i) + sampleRadius - 1), userY(i):(userY(i) + sampleRadius - 1));

    totsq = sum(sum(subImage.^2));

    subImagePad = zeros(size1h, size1w);
    subImagePad(1:sampleRadius, 1:sampleRadius) = subImage;

    subImgF = fft2(subImagePad);

    cc1F = image1F.*conj(subImgF);
    cc2F = image2F.*conj(subImgF);

    cc1 = abs(ifft2(cc1F));
    cc2 = abs(ifft2(cc2F));

    cct1 = abs(ifft2(image1sqF.*conj(maskF))) - 2 * cc1 + totsq;
    cct2 = abs(ifft2(image2sqF.*conj(maskF))) - 2 * cc2 + totsq;

    [m1, indx1] = min(cct1(:))
    [m2, indx2] = min(cct2(:))

    [xoff1, yoff1] = ind2sub(size(cct1), indx1)
    [xoff2, yoff2] = ind2sub(size(cct2), indx2)
    
    Xoffset1 = [Xoffset1; xoff1];
    Xoffset2 = [Xoffset2; xoff2];
    Yoffset1 = [Yoffset1; yoff1];
    Yoffset2 = [Yoffset2; yoff2];
    
     clear cc1;
     clear cc2;
    clear cct1;
    clear cct2;
    clear cc1F;
    clear cc2F;

end

clear image1F;
clear image2F;

figure('Name', 'Resulting Matched Locations', 'Position', [0 0 700 300]);
subplot(1,2,1); imagesc(image1); axis square; colormap gray;
hold on;

for i = 1:numberOfPoints
    plot(Yoffset1(i), Xoffset1(i), 'rx');
    t = text(Yoffset1(i) + 10, Xoffset1(i), num2str(i));
    set(t, 'Color', [1 0 0]);
end

hold off;

subplot(1,2,2); imagesc(image2); axis square; colormap gray;
hold on;
for i = 1:numberOfPoints
    plot(Yoffset2, Xoffset2, 'rx');
    t = text(Yoffset2(i) + 10, Xoffset2(i), num2str(i));
    set(t, 'Color', [1 0 0]);
end
hold off;

% At this point, we have identified numberOfPoints points on
% image1, and found the matching point in image2

% we want to find the transformation matrix based on these points
% that will transform second image to match the first image

image1pts = [Xoffset1 ; Yoffset1];
matA = [Xoffset2' Yoffset2'; Yoffset2' -Xoffset2'; ones(numberOfPoints, 1)' zeros(numberOfPoints, 1)';zeros(numberOfPoints, 1)' ones(numberOfPoints, 1)']';

% solve linear equation
 tempA = matA \ image1pts;
% 
oldA = [tempA(1) -tempA(2) tempA(4); tempA(2) tempA(1) tempA(3); 0 0 1]

p2 = [Xoffset1'; Yoffset1'; ones(numberOfPoints, 1)'];
p1 = [Xoffset2'; Yoffset2'; ones(numberOfPoints, 1)'];

newA = 2 * inv(p1*p1'+p1*p1')*(p1 * p2')
A = newA';
temp = A(2,3);
A(2,3) = A(1,3);
A(1,3) = temp;
A(1,2) = -A(1,2);
A(2,1) = -A(2,1);
A = A
%A = (p1 * p2') * inv(p1 * p1');


% now we apply the transformation to the corners
% of image2 to create a new image to hold the transformed image2
corners = A * [1 1 size2w size2w; 1 size2h 1 size2h; 1 1 1 1];
[newX, newY] = ndgrid(min([corners(1,:) 0]) : max([corners(1,:) size1w]), min([corners(2,:) 0]) : max([corners(2,:) size1h]));
[newW newH] = size(newX);

% transform image2
newImage2 = A \ [newX(:) newY(:) ones(newW * newH, 1)]';

% interpolate new image
clear transformedImage2;

tempX = reshape(newImage2(1,:), newW, newH)';
tempY = reshape(newImage2(2,:), newW, newH)';
transformedImage = interp2(image2, tempX, tempY, '*bilinear');

newImageOffset = round([max([corners(1,:) 0]) max([corners(2,:) 0])]);

finalImage(1 : newH, 1 :newW) = transformedImage;
%finalImage(27 : 27 + newH - 1, 125 : 125 + newW -1) = transformedImage;

finalSize = [1 size1h 1 size1w];

if (tempA(3,1) < 0)
    finalSize(1,1) = -round(tempA(3,1));
    finalSize(1,2) = -round(tempA(3,1)) + size1h - 1;
end
if (tempA(4,1) < 0)
    finalSize(1,3) = -round(tempA(4,1));
    finalSize(1,4) = -round(tempA(4,1)) + size1w - 1;
end

%    finalImage(finalSize(1,1):finalSize(1,2), finalSize(1,3):finalSize(1,4)) = image1;


finalImage(1:size1h, 1:size1w) = image1;

%transformedImage(1 : size1h, 1 : size1w) = image1;

figure('Name', 'Stitched Image', 'Position', [0 0 350 350]);
imagesc(finalImage); axis equal; colormap gray
