仿射变换、透视变换、图像配准

目录

一,仿射变换

1,前向映射

2,反向映射

二,常见的仿射变换

1,恒等变换

2,尺度变换(缩放)

3,旋转变换​

4,平移变换

5,偏移变换

三,透视投影

四,透视变换

五,图像配准

六,Opencv 配准+变换

七,其他变换

1,双线性变换

2,实现双线性变换和透视变换


一,仿射变换

仿射变换、透视变换、图像配准_第1张图片

仿射变换的映射方式有两种,前向映射和反向映射。

1,前向映射

扫描原图的每个像素(v,w),变换后的值填入对应的(x,y)处。

对于多个像素点映射到同一个(x,y)的情况,不太好处理,所以反向映射更有效。

2,反向映射

扫描变换后图像的每个像素(x,y),根据逆变换找到原图中对应的(v,w)

大概率找到的不是整点,所以需要使用图像插值 https://blog.csdn.net/nameofcsdn/article/details/118281568

二,常见的仿射变换

1,恒等变换

2,尺度变换(缩放)

仿射变换、透视变换、图像配准_第2张图片

3,旋转变换

4,平移变换

5,偏移变换

垂直偏移变换:

水平偏移变换:

三,透视投影

把三维图像透视投影到二维平面:

x' = x/z , y' = y/z

如,有3个垂直于z轴的正方形,分别是:

{6<=x<=12,6<=y<=12,z=1}、{6<=x<=12,6<=y<=12,z=2}、{6<=x<=12,6<=y<=12,z=3}

那么投影之后得到的正方形如图:

仿射变换、透视变换、图像配准_第3张图片

这么看着没什么感觉,但是如果旋转180度,再添加2条透视线:

仿射变换、透视变换、图像配准_第4张图片

显然,原点O就是透视点,对应z=∞的点。

四,透视变换

透视变换就是,把一个平面图形在三维空间中做仿射变换,然后再做透视投影变成平面图形。

三维仿射变换:

其中w可以取任意不为0的数,如w=1

然后透视投影:

仿射变换、透视变换、图像配准_第5张图片

注意到,这9个变量同时放大缩小是不影响的,所以不妨设a33 = 1,那么就剩下8个未知数。

仿射变换、透视变换、图像配准_第6张图片

五,图像配准

输入两幅图片,已知一副图像是另外一副图像变换得到,通过计算反推出变换。

常用的方法就是根据特征点,代入图像变换的公式求解。

特征点的最少数目,取决于变换的方式。而特征点越多,自然配准越容易,越准确。

PS:只有部分重合的图片,也能做配准,如全景照片就是配准之后拼接起来的。

六,Opencv 配准+变换

从未知数的数量来看,仿射变换有6个未知数,透视变换有8个未知数。

所以确定一个仿射变换需要3个点的前后坐标值,确定一个透视变换需要4个点的前后坐标值。

从几何意义来看,仿射变换是平面操作,所以需要3个点,透视变换是空间操作,所以需要4个点。

Opencv里面提供了仿射变换和透视变换的配准和变换的接口,先提供点的坐标匹配,根据坐标匹配自动配准,得到变换公式的对象,再用这个对象对整个图像进行变换。

仿射变换:(这里是旋转的示例)

image = cv2.imread("D:/im.jpg", 0)
image = cv2.resize(image,(500,500))
cv2.imshow("img",image)
p_src = numpy.float32([[0, 0],[0, 500],[500, 0]])
p_dst = numpy.float32([[300, 0],[0, 400],[700, 300]])
trans = cv2.getAffineTransform(p_src,p_dst)
image2 = cv2.warpAffine(image,trans,(700,700))
cv2.imshow("img2",image2)
cv2.waitKey(0)

变换结果:

透视变换:

image = cv2.imread("D:/im.jpg", 0)
image = cv2.resize(image,(500,500))
cv2.imshow("img",image)
p_src = numpy.float32([[0, 0],[0, 500],[500, 0],[500,500]])
p_dst = numpy.float32([[0, 0],[0, 500],[250, 0],[500,500]])
trans = cv2.getPerspectiveTransform(p_src,p_dst)
image2 = cv2.warpPerspective(image,trans,(500,500))
cv2.imshow("img2",image2)
cv2.waitKey(0)

变换结果: 

七,其他变换

1,双线性变换

显然这个也是需要4个点才能确定变换。

书中的这个式子卡住了我很久,因为我一直想不通这是什么变换,于是我举了一个简单的例子:

把正方形{(0,0)(0,500)(500,0){500,500}}变换为梯形{(0,0)(0,250)(500,0){500,500}}

如果是透视,那么变换就是x=500u/(1000-u), y=500v/(1000-u)

如果是双线性变换,那么就是x=u, y=v(u+500)/1000

2,实现双线性变换和透视变换

代码:

image = cv2.imread("D:/im.jpg", 0)
image = cv2.resize(image,(500,500))
cv2.imshow("img",image)
image2 = image.copy()
image3 = image.copy()
for i in range(image.shape[0]):
    for j in range(image.shape[1]):
        image2[i, j] = 0
        image3[i, j] = 0
for i in range(image.shape[0]):
    for j in range(image.shape[1]):
        image2[int(i * 500 / (1000 - i)) % image.shape[0], int(j * 500 / (1000 - i)) % image.shape[1]] = image[i, j]
        image3[i,int(j*(i+500)/1000)%image.shape[1]] = image[i,j]
cv2.imshow("image2",image2) #透视
cv2.imshow("image3",image3) #双线性
cv2.waitKey(0)

运行:

 可以看出来,图2是透视,物体在图片中的高度位置有变化,直线还是直线,

图3是双线性变换,高度没有变化,直线变得不直了。

PS:自己写的透视变换有点粗糙,中间有些黑线,如果是反向映射的话应该就不会这样了:

image = cv2.imread("D:/im.jpg", 0)
image = cv2.resize(image,(500,500))
cv2.imshow("img",image)
image2 = image.copy()
image3 = image.copy()
for i in range(image.shape[0]):
    for j in range(image.shape[1]):
        image2[i, j] = 0
        image3[i, j] = 0
for i in range(image.shape[0]):
    for j in range(image.shape[1]):
        j2 = int(j * 1000 / (i + 500))
        if j2 >= 500:
            image2[i, j] = 0
        else:
            image2[i,j] = image[int(i * 1000 / (i + 500)) % image.shape[0], j2]
        image3[i,int(j*(i+500)/1000)%image.shape[1]] = image[i,j]
cv2.imshow("image2",image2) #透视
cv2.imshow("image3",image3) #双线性
cv2.waitKey(0)

你可能感兴趣的:(计算机视觉)