本人毕设题目是身份证照片矫正 —— 给一个简单背景下的含有身份证的照片,对其所产生的几何畸变进行矫正,使处理后的照片几何尺寸的比例关系接近于真实身份证的几何尺寸比例关系。
在现有条件下,我的思路是利用 OpenCV 的透视变换来进行矫正,那么这样就需要知道身份证的边界,进而确定身份证的四个顶点坐标,大致流程如下:
在对图像中身份证进行边缘提取后,运用霍夫变换线画出身份证的四条边,由此形成了四个交点,即为身份证的四个顶点,如图所示:
注: 找交点的算法参考 LeetCode - 面试题 16.03. 交点
之后就是纯粹的解四边形问题了。
分析它们的特点:
注意:
按照上下来分类(y: 上 < 下) | 按照左右来分类(x: 左 < 右) |
---|---|
{ y 1 < y 2 , y 1 < y 4 y 3 < y 2 , y 3 < y 4 \left\{\begin{aligned}y_1& |
{ x 1 < x 3 , x 2 < x 3 x 1 < x 4 , x 2 < y 4 \left\{\begin{aligned}x_1& |
1. 上下分类
(1) 先按 y坐标 排序
· 找到最小的 m i n 1 min_1 min1和倒数第二小 m i n 2 min_2 min2 ,放入up[2]中;
· 剩下的两个为靠下的坐标,放入down[2]中;
(2) 分别对数组up[2], down[2]按照 x坐标 排序
所得结果如下:
up[2] | down[2] |
---|---|
m i n 1 min_1 min1 => 左上 m i n 2 min_2 min2 => 右上 |
m i n 1 min_1 min1 => 左下 m i n 2 min_2 min2 => 右下 |
2. 左右分类
(1) 先按 x x x坐标 排序
· 找到最小的 m i n 1 min_1 min1和倒数第二小 m i n 2 min_2 min2 ,放入left[2]中;
· 剩下的两个为靠右的坐标,放入right[2]中;
(2) 分别对数组up[2], down[2]按照 y y y坐标 排序
所得结果如下:
up[2] | down[2] |
---|---|
m i n 1 min_1 min1 => 左上 m i n 2 min_2 min2 => 右上 |
m i n 1 min_1 min1 => 左下 m i n 2 min_2 min2 => 右下 |
但是这样做是否符合任何位置下的身份证图片呢?
它有一个很明显的前提:
超出了这个前提,点的位置判别就会出错。如下图所示:
可以看到左下角 B B B 在右上角 D D D 上方( y B < y D y_B < y_D yB<yD),如果用“先按照 y y y坐标 分类”进行判断,那么上下坐标的分类就会出错。
具体如下图所示:
(上为倾角较小的情况,下为倾角较大的情况)
该方法具有局限性,没有考虑到水平旋转角度任意的情况,仅适用于上述前提下的身份证摆放位置。
总结了第一次的经验,开始第二次尝试。
如果说第一次尝试仅仅依靠点坐标来判断位置关系,那么利用的条件是不是太少了呢?既然知道了点的坐标,那么就可以计算出边长,从而利用长短边来判断点的位置关系。
有了思路现在就开始分析吧!
已知: 四个顶点坐标 A ( x 1 , y 1 ) A(x_1, y_1) A(x1,y1) ~ D ( x 4 , y 4 ) D(x_4, y_4) D(x4,y4)
设:
则:
比较,得:以 A A A 为端点的边为 A ‾ B ‾ \overline A\overline B AB、 A ‾ D ‾ \overline A\overline D AD。其中短边为 A ‾ B ‾ \overline A\overline B AB,长边为 A ‾ D ‾ \overline A\overline D AD
=> B B B 为身份证左下角, D D D 为身份证右上角
现在得到了四个点的位置信息,但是问题又来了:如何确定左上角点 A A A 呢?
这就引出了推广情况。
目的: 找出证件真正的左上角点 A A A
假设:
身份证位置未知,随机找一个顶点 A ( x 0 , y 0 ) A(x_0, y_0) A(x0,y0),则其余记为 B B B, C C C, D D D;
距离记为 d d d A B AB AB, d d d A C AC AC, d d d A D AD AD;
令 d d d A B AB AB < d d d A D AD AD < d d d A C AC AC(短边 < 长边 < 对角边)
此时,再找一点 B,则四点的位置关系有如下四种情况:
【基于边长的先y后x法】
根据上述推导,我们可以从理论上人为例举出所有的旋转情况,但是只是凭借 “点坐标 + 线段长度” 还是不能解决问题:
试想一下,若我们任取一个照片,不知其中的身份证是正着放的还是倒着放的(如下图所示),则基于这种方法的计算机并不知道究竟哪个是左上角顶点 A A A ,只能判断以点 A A A 为顶点的长短边。经透视变换,身份证图像有可能变为以下两种情况:
这是因为 —— 由于矩形的对称性,计算机仅能判断出此任意点 M ( x , y ) M(x, y) M(x,y) 为点 A A A 或 点 C C C( A A A 的对角顶点)两种情况,因而不能得出是否为点 A A A。
基于此,我引入了人脸检测的方法,通过“试错”来解决:将矫正后的照片垂直一分为二,只取右半部分(w > img.width / 2
)。若检测出人脸,则表示矫正正确;否则,矫正错误,此时将此照片旋转180°,再进行上述操作,得到正确结果。
经过上述推导,最终还是先利用采集图像的相对靠左上角的顶点,计算出相邻边长,判断长短边;再通过透视变换后的图像对其右半部分进行人脸检测,判断方向是否为正,倒立则旋转。
而并没有一次性判断出身份证的左上角顶点而免去旋转的操作。
如果有更好的方法,还望各位大佬不吝赐教!
注:以上身份证图像均经过 Adobe Photoshop CC 处理