搜索空间
搜索空间包括空间变换范围和空间变换方式两部分。最常用的空间变换方式为仿射变换,它可以实现平移、旋转和按比例缩放。
平移变换
-
实现原理:将图像中所有的像素按照给定的平移量水平、垂直方向移动。
设(x_0,y_0)为原图像上的点,图像水平平移量为t_x,垂直平移量为t_y,则平移后点(x_0,y_0)坐标变为(x_1,y_1)。示意图如下
即,
{ x 1 = x 0 + t x y 1 = y 0 + t y \left\{ \begin{array}{c} x_1=x_0+t_x\\ y_1=y_0+t_y\\ \end{array} \right. {x1=x0+txy1=y0+ty
用矩阵表示为
[ x 1 y 1 1 ] = [ x 0 y 0 1 ] [ 1 0 0 0 1 0 t x t y 1 ] \left[ \begin{matrix} x_1& y_1& 1\\ \end{matrix} \right] =\left[ \begin{matrix} x_0& y_0& 1\\ \end{matrix} \right] \left[ \begin{matrix} 1& 0& 0\\ 0& 1& 0\\ t_x& t_y& 1\\ \end{matrix} \right] [x1y11]=[x0y01]⎣⎡10tx01ty001⎦⎤
对上面矩阵求逆可以得到反向变换
[ x 0 y 0 1 ] = [ x 1 y 1 1 ] [ 1 0 0 0 1 0 − t x − t y 1 ] \left[ \begin{matrix} x_0& y_0& 1\\ \end{matrix} \right] =\left[ \begin{matrix} x_1& y_1& 1\\ \end{matrix} \right] \left[ \begin{matrix} 1& 0& 0\\ 0& 1& 0\\ -t_x& -t_y& 1\\ \end{matrix} \right] [x0y01]=[x1y11]⎣⎡10−tx01−ty001⎦⎤
其对应坐标方程为
{ x 0 = x 1 − t x y 0 = y 1 − t y \left\{ \begin{array}{c} x_0=x_1-t_x\\ y_0=y_1-t_y\\ \end{array} \right. {x0=x1−txy0=y1−ty -
对于新图像中的点,如果该点的灰度值在原始图像中没有可以,可以直接设置为0或255。相反,原图像的部分像素点可能没有包含在新图像中,也就是原图像中点被移出了显示区域。如果不希望丢失被移出的部分的图像,可以将新图像的宽|增大t_x|,高增大|t_y|。
-
代码实现:
OldImage = imread('ex.png');
x= -20,y=70; % 上移20,右移70
imshow(mat2gray(OldImage));
[nrows,ncols] = size(OldImage);%获取原图像的尺寸
width = nrows;
height = ncols;
NewImage = uint8(zeros(width,height));
T = [1,0,0;0,1,0;x,y,1];
tform = maketform('affine',T);
tx = zeros(width,height);%正向坐标值
ty = zeros(width,height);
for i = 1:width
for j = 1:height
tx(i,j) = i; % tx 保存各位置的横坐标
ty(i,j) = j; % ty 保存各位置的纵坐标
end
end
[w,z] = tforminv(tform,tx,ty); % 反向坐标值
for i = 1:width
for j =1:height
source_x = w(i,j);
source_y = z(i,j);
if (source_x>=width-1 || source_y>=height-1 ||double(uint16(source_x))<=0 || double(uint16(source_y))<=0) %疑问[为啥不是width+1 height+1]
NewImage(i,j) = 0; % 新图像的点不在原图像中,直接赋值0
else
if (source_x/double(uint16(source_x))==1.0)&&(source_y/double(uint16(source_y))==1.0)
% 整数点中的值直接将原图像中的值赋值给新图像
NewImage(i,j) = OldImage(int16(source_x),int16(source_y));
else
% 不在整数点位置,采用双线性插值给新图像赋值
a = double(uint16(source_x));
b = double(uint16(source_y));
x11 = double(OldImage(a,b)); % x11 x12 x21 x22都是灰度值
x12 = double(OldImage(a,b+1));
x21 = double(OldImage(a+1,b));
x22 = double(OldImage(a+1,b+1));
NewImage(i,j)= uint8((b+1-source_y)*((source_x-a)*x21+(a+1-source_x)*x11)+...
(source_y-b)*((source_x-a)*x22+...
(a+1-source_x)*x12));
% 这个双线性插值是先在行方向插值,再在列方向插值,所以上面形式。
end
end
end
end
I = NewImage;
figure,imshow(mat2gray(I))
-
以上为参考书实现方式
关于上述代码中双线性插值部分代码的理解。参考草稿图,NewImage(i,j)对应原图像中的点S,S点坐标在代码中为(source_x,source_y),其周围的四个整数点分别为A(a,b),B(a,b+1),C(a+1,b),D(a+1,b+1)。先利用A、D点插值计算S1的灰度值,利用B、C点插值计算S2的灰度值,然后利用S1和S2计算出S的灰度值。
下图为代码中对应的计算过程。
【这里我有个疑问是代码中(source_x,source_y)转化为uint16后,不一定是左上角那个点吧?】 -
下面是自己写的简易实现【目前没发现啥问题】
img = imread('ex.png');
oldImg = double(img);
figure,imshow(oldImg);
tx = -5; % 从结果来看,tx是上下平移,tx大于0则向下
ty =70; % ty是左右平移,ty大于0则向右平移
[width,height] = size(img);
newImg = zeros(width,height);
for i= 1:width
for j=1:height
newX = round(i+tx);
newY = round(j+ty);
if (newX<=width)&&(newY<=height)&&(newX>0)&&(newY>0) %不能等于0,从1开始
newImg(newX,newY)=oldImg(i,j);
end
end
end
figure,imshow(newImg)
- 实现效果:原图
当平移x=-20,y=70时:
y=70右移70,x=-20上移20。
参考资料:
- 《图像配准技术及其MATLAB编程实现》
- 原始图片“囧”来源网络图片下载链接