仿射变换能够保持图像的“平直性”,包括旋转,缩放,平移,错切操作。一般而言,仿射变换矩阵为2*3的矩阵,第三列的元素起着平移的作用,前面两列的数字对角线上是缩放,其余为旋转或者错切的作用。透视变换原理及实现请看我下篇博客。
设仿射变换矩阵T = [a11,a12,a13 ; a21,a22,a23]; 图像上fixed points坐标为(Xk,Yk);moving points坐标为(xk,yk),其中k=1,2,...,n。
为了求解该仿射变换矩阵T的6个未知参数,理论上至少需要6个方程联立求解,即需要3组点集对,n>=3,当n>3时用最小二乘法求解未知参数。并且这三组点不共线。
数学展开式如下图:
下面根据上面公式给出实现代码,图像使用最近邻插值。
%% 读取原图像
clear ;
close all;
src=rgb2gray(imread('lena.png'));
imshow(src);
%% method1,用3组点集对图像进行仿射变换,调用matlab系统函数
fixedPoints = [1,1; 1,100;100,100];
movingPoints = [20,20; 120,80; 160,200];
tic;
tform = fitgeotrans(movingPoints,fixedPoints,'affine');
dst_img = imwarp(src,tform);
t_sys = toc;
figure;imshowpair(src,dst_img,'montage');
title(['系统函数的仿射变换图像,耗时(s):',num2str(t_sys)])
%% method2,用3组点集对图像进行仿射变换,解方程求变换矩阵
% T = [a11,a12,a13;a21,a22,a33];
% 满足fixed_pt_matrix = T*moving_pt_matrix;
tic;
fixed_pt_matrix = fixedPoints';
moving_pt_matrix = [movingPoints';ones(1,size(movingPoints,1))];
T = fixed_pt_matrix/moving_pt_matrix;
width = size(src,2);
height = size(src,1);
[moving_pt_x,moving_pt_y] = meshgrid(1:width,1:height);
coridate_affine = T*[moving_pt_x(:)';% 对原来图像所有坐标点变换到新平面上
moving_pt_y(:)';
ones(1,width*height)];
x_temp = coridate_affine(1,:);
y_temp = coridate_affine(2,:);
fixed_pt_x = reshape(x_temp,...
size(moving_pt_x))+...
abs(min(x_temp))+1;
fixed_pt_y = reshape(y_temp,...
size(moving_pt_y))+...
abs(min(y_temp))+1;
fixed_pt_x = round(fixed_pt_x);
fixed_pt_y = round(fixed_pt_y);
dst_affine_img = zeros(round(max(y_temp)-min(y_temp))+1,...
round(max(x_temp)-min(x_temp))+1);
for i = 1:height
for j = 1:width
dst_affine_img(fixed_pt_y(i,j),fixed_pt_x(i,j)) = src(i,j);
end
end
t_manual = toc;
figure;imshowpair(src,uint8(dst_affine_img),'montage');
title(['计算的仿射变换图像,耗时(s):',num2str(t_manual)])
%% 插值处理
[index_i,index_j] = find(dst_affine_img);
for i = 1:size(dst_affine_img,1)
for j = 1:size(dst_affine_img,2)
[min_distance,index_near] = min(sqrt((i-index_i).^2+(j-index_j).^2));
if dst_affine_img(i,j)==0 && min_distance<=1
dst_affine_img(i,j) = dst_affine_img(index_i(index_near),index_j(index_near));
end
end
end
figure; imshowpair(src,uint8(dst_affine_img),'montage');
title('插值后图像')
再看一个对点集的简单测试,T = [1,1,0;2,1,0];
%% 坐标点的仿射变换
[pt_x,pt_y] = meshgrid(1:10);
pt_x = pt_x(:);
pt_y = pt_y(:);
figure;subplot(211);plot(pt_x,pt_y,'ro');grid on;
title('原始点集')
dst_pt = zeros(length(pt_x),2);
tf_affine = [1,1,0;2,1,0];
for i = 1:length(pt_x)
dst = tf_affine*[pt_x(i),pt_y(i),1]';
dst_pt(i,:) = [dst(1),dst(2)];
end
subplot(212);plot(dst_pt(:,1),dst_pt(:,2),'bo');grid on
title('仿射后点集')