证件照片的矫正

会议上的方法有问题

会议上提出:先由用户通过交互的方式,大致找出边缘,再由程序确定出真正的边缘,然后将歪斜的证件图片的较长的长(a)和宽(b)取出,组成一个a X b的矩形,将原图片的像素点映射到新的图像上

交互的问题

参照现有产品“扫描全能王”:

  1. 如使用普通模式,需要用户利用给出的“框”,框选证件的边缘。其中,这一步操作会用到“磁吸”的效果,类似于PS软件中的“磁性套索”。这对我来说是一个难点,我的想法是:在用户拍完照后,程序就已经找出了可能的边缘,再由用户框选出最终的边缘(这一步很像人工智能在训练)。所以该普通模式可以让寻找边缘变得更精准(如果拍出来的证件或文件看上去是曲线也可以),但是用户的操作效率较低,不知道是不是在一个可以接受的范围内
  2. 如使用证件模式,该软件就会给出一个适合某一类证件的方框,让用户对准方框即可,但如果使用该模式,且用户使用得当(几乎对准了证件),我认为就失去了矫正的意义,只需要微调即可

我的想法

找边缘

直接采用老师已教方法,或者方便一点,利用库函数:高斯滤波+卷积核+膨胀+canny边缘

定四点

highgui库可以利用交互的方式解决

或者利用边缘定点

变换

opencv提供了仿射变换和透视变换的功能

仿射变换

在仿射变换中,原始图像中的所有平行线在输出图像中仍将平行。为了找到变换矩阵,我们需要

输入图像中的三个点及其在输出图像中的对应位置。然后cv.getAffineTransform将创建一个2x3

矩阵,该矩阵将传递给cv.warpAffine

查看以下示例,并查看我选择的点(以绿色标记):

1
2
3
4
5
6
7
8
img = cv.imread('drawing.png')
rows,cols,ch = img.shape
pts1 = np.float32([[50,50],[200,50],[50,200]])
pts2 = np.float32([[10,100],[200,50],[100,250]])
M = cv.getAffineTransform(pts1,pts2)
dst = cv.warpAffine(img,M,(cols,rows))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')

1

透视变换

对于透视变换,您需要3x3变换矩阵。即使在转换后,直线也将保持直线。要找到此变换矩阵,您

需要在输入图像上有4个点,在输出图像上需要相应的点。在这四个点中,其中三个不应共线。然

后可以通过函数cv.getPerspectiveTransform找到变换矩阵。然后将cv.warpPerspective

用于此3x3转换矩阵。

请参见下面的代码:

结果:

1
2
3
4
5
6
7
8
9
img = cv.imread('sudoku.png')
rows,cols,ch = img.shape
pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
M = cv.getPerspectiveTransform(pts1,pts2)
dst = cv.warpPerspective(img,M,(300,300))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()

2

在变换方面因为接触的还太少,很遗憾不能想出更好的方法

加工

但是这样的做法显然是粗糙的,我们可以加工的更完美,利用上面方法大致矫正了之后,再以自己的程序进行调整,也许会更好