数字图像处理(二)图像配准

图像配准即对于内容大致相同,但在角度,大小或是其他几何位置上有所偏差的两张或几张图像进行坐标变换。使得这些图像矫正到同一规整的大小,角度,坐标上。

图像配准对于图像拼接,制作全景图像,进行环境识别等方面有很大的用处。其原理简单,使用矩阵运算转换速度也很快,在选取映射点合适的情况下,配准效果很好。具体的转化方法如下:

配准算法

以图像A为标准配准图像B

在图像A中选取n个像素点: \[ p_1(x_1,y_1,1),p_2(x_2,y_2,1),...,p_n(x_n,y_n,1) \] 构成一个坐标矩阵 \[ P=\begin{bmatrix}x_1 &x_2 &...&x_n\\y_1&y_2&...&y_n\\1&1&...&1\end{bmatrix} \] 在图像B中选取与这n个点对应的n个像素点: \[ q_1(x_1,y_1),q_2(x_2,y_2),...,q_n(x_n,y_n) \] 构成另一个坐标矩阵 \[ Q=\begin{bmatrix}x_1 &x_2 &...&x_n\\y_1&y_2&...&y_n\\1&1&...&1\end{bmatrix} \]

如果图像B可以通过图像A平移,旋转,缩放得到,那么存在一个转换矩阵H使得: \[ Q=HP \] 那么如果可以计算出转换矩阵H,就可以利用上述公式的变形: \[ H^{-1}Q=P \] 将每个图像B中的像素点映射到图像A相应位置处,从而获得以图像A为模板配准的图像B

如何求出转换矩阵H?

通过之前在图像A和图像B中已经选取出的点集P和Q,我们不难发现 \[ H=QP^{-1} \]

由于P不是方阵,因而无法对其进行求逆,在这里为求伪逆

至此,我们已经得到了图像配准的基本流程:

  • 在模板图像和待配准图像中选取相互对应的点集$ P \(和\)Q$
  • 通过公式\(H=QP^{-1}\)求出转换矩阵\(H\)
  • 通过转换矩阵将待配准图像映射到模板图像上

配准示例

例如:以图像A为模板配准图像B Image A 图像B 在其中选取七个点,分布为:

这里采用画图进行选点,画图显示的坐标与(x,y)坐标是正好相反的,在进行坐标记录时需要注意。

选点(图像A) \[ P=\begin{bmatrix}1448&1694&1756&383&2290&2035&2150\\1308&1198&2744&2516&933&2693&1968\\1&1&1&1&1&1&1\end{bmatrix} \]

\[ Q=\begin{bmatrix}1042&1252&1708&323&1761&1966&1890\\1077&907&2387&2519&498&2265&1535\\1&1&1&1&1&1&1\end{bmatrix} \]

求出的转换矩阵: \[ H=QP^{-1}=\begin{bmatrix}0.9668&0.2565&693.0275\\-0.2570&0.9671&184.1373\\0.0000&0.0000&1.0000\end{bmatrix} \] 通过转换矩阵对图像B进行转换,最终得到的结果如下: 配准后的图像B

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import cv2 as cv
import numpy as np
import math
#np.set_printoptions(threshold=np.inf)

imgA=cv.imread("Image A.jpg?x-oss-process=style/webp")
imgB=cv.imread("Image B.jpg?x-oss-process=style/webp")
point_A=np.array([[1448,1694,1756,383,2290,2035,2150],[1308,1198,2744,2516,933,2693,1968],[1,1,1,1,1,1,1]])
point_B=np.array([[1042,1252,1708,323,1761,1966,1890],[1077,907,2387,2519,498,2265,1535],[1,1,1,1,1,1,1]])
H=np.dot(point_B,np.linalg.pinv(point_A))
print(H)
shape_A=imgA.shape
shape_B=imgB.shape
result,mistake=np.zeros(shape_A),np.zeros(shape_A)
result=result.astype(np.uint8)
mistake=mistake.astype(np.uint8)
for i in range(shape_A[0]):
for j in range(shape_A[1]):
address=np.dot(H,np.array([i,j,1]))
address=address.astype(np.int)
if address[0]>0 and address[0]<shape_B[0] and address[1]>0 and address[1]<shape_B[1]:
result[i][j]=imgB[address[0]][address[1]]
mistake[i][j]=imgA[i][j]-result[i][j]
cv.namedWindow("test",cv.WINDOW_NORMAL)
cv.imshow("test",mistake)
cv.waitKey(0)
cv.imwrite("result.jpg?x-oss-process=style/webp",result)
cv.imwrite("mistake.jpg?x-oss-process=style/webp",mistake)

结束语

图像配准的算法比较简单,选取好坐标点之后通过配准的计算方法得到的结果很好。但此次图像配准在选点时为手动选点,如果要大批量进行图像配准或实时配准则需要进行自动选点,此时,如何让程序选取出合适并且相互对应的点集成为了图像配准的难点所在。