OpenCV处理拍照表格(二)

先来看看上次处理后的整张图片效果:

afterdilate

这里发现我将图片的颜色已经反相了,这是考虑到下一步的直接检测必须以白色像素为内容。做法在上一篇提到过,交换两段的位置就可以了。

可以看到噪点已经几乎没有了,文字的清晰度还是可以的。这里采用的kernel都是2x2的。

直线检测

下面就是比较关键步骤——直线检测了。

首先介绍一下openCV提供的直线检测算法:霍夫变换。

霍夫变换是图像处理中一个著名的检测算法,用于对二值图片中特定的几何形状的检测,直线检测只是其中比较常见的一种用法。从holybin的专栏中复制一段介绍基本理论的内容:

Hough直线检测的基本理论是二值图像中的任何点都可能是一些候选直线集合的一部分,所选的参数方式是每一行代表极坐标中的一个点,并且隐含的直线是通过象征点的,垂直于原点到此点的半径,即:检测的过程可以看成从图像中的一个个像素点出发,寻找每个点成为直线一部分的可能,再把这条线上可能的点连起来形成直线。在实际检测中,当一条线出现凹陷或是弯曲度时,也会检测出直线,只是不是一条完整长度直线,而是断断续续重叠相近的很多直线。>
而对于图像中的一条直线而言,利用直角坐标系,可以表示为:的形式。那么,该直线上任意一点(x,y)变换到k-b参数空间将变成一个“点”。也就是说,将图像空间中所有的非零像素转换到k-b参数空间,那么它们将聚焦在一个点上。如此一来,参数空间中的一个局部峰值点就很有可能对应着原图像空间中的一条直线。不过,由于直线的斜率可能为无穷大,或者无穷小,那么,在k-b参数空间就不便于对直线进行刻画和描述。所以,研究人员提出采用极坐标参数空间进行直线检测。在极坐标系中,直线可以表述为以下形式:>

更为详细的分析可以看浅墨的博客

如果不能理解也没有关系,在openCV中已经为我们封装成了两个函数HoughLines( )HoughLinesP( ),他们之间的区别在于算法的不同,而效果的差别不大,但HoughLinesP可以减少计算量,所以在这里我们采用了HoughLinesP来进行。

1
public static void HoughLinesP(Mat image,Mat lines,double rho,double theta,int threshold,double minLineLength,double maxLineGap)

Finds line segments in a binary image using the probabilistic Hough transform.

Parameters:
image - 8-bit, single-channel binary source image. The image may be modified by the function.
lines - Output vector of lines. Each line is represented by a 4-element vector (x_1, y_1, x_2, y_2), where (x_1,y_1) and (x_2, y_2) are the ending points of each detected line segment.
rho - Distance resolution of the accumulator in pixels.
theta - Angle resolution of the accumulator in radians.
threshold - Accumulator threshold parameter. Only those lines are returned that get enough votes (>threshold).
minLineLength - Minimum line length. Line segments shorter than that are rejected.
maxLineGap - Maximum allowed gap between points on the same line to link them.

解释一下各个参数:

  • image:源图像 Mat格式,8位单通道(Cv_8UC1

  • lines: 输出的“图像” 虽然是Mat格式,但是其中保存的内容已经不再是图像了,其中的每行(Rows!在这里手上买到的一本书中写成了列,大概是因为版本不同导致的,因为这个在这里卡了好几个小时……)中储存了一个double[],下面会讲到如何使用里面的信息。

  • rho:翻译过来是距离的解析度,以像素为单位,在后面这个参数起了大作用。

  • theta:与rho相似地,是角度的解析度,以弧度为单位。

  • threshold:阈值 这个值决定了霍夫变换后对于一对值投票所需达到的阈值才能被记录。换句话说,这个值越大,检测出直线的要求就越高(这个要求应该是对于直线上的点聚集程度的要求)。应为一个非负值。

  • minLineLength:字面意思,检测出的直线的最小长度,小于这个长度的直线将不会被记录。单位是像素。

  • maxLineGap:字面意思,检测时可以接受的直线断开的距离(实际情况中很难达到一条直线上的点全部都有,通常是断断续续的,这时这个值就发挥了很大的作用)。单位是像素。

可以看到这个函数的参数非常多,并且有个别参数并没有一个量化的标准(比如threshold在检测大图的时候取150左右的值比较好,但在后面检测小图时候设成0都不尽人意,rhotheta参数如果按照资料中普遍的1和2pi/180来设置小图的检测就会出现问题),更加悲惨的是这些参数之间存在相互影响,对实际的图片进行处理的过程中参数的差别可能很大,需要一些耐心和方法去慢慢调试(我写了嵌套的循环再输出所有的图用肉眼看效果再缩小范围……)

最影响最终效果的部分在于最后两个值的设置,可以看到上面我们将要处理的图片,这步我的目的是检测出所有的横向的表格边线。下面先上最终的效果图:

redlines1

(红线为最终检测出的直线位置)

具体的检测过程下一篇介绍。