图像验证码识别(六)——图像中的直线检测

来源:互联网 发布:js toggle 切换状态 编辑:程序博客网 时间:2024/06/06 13:10

这里题目之所以没有写成“验证码图片中的干扰线去除”,就是因为在干扰线去除做的不是很好,最后也没有找到什么较为通用的算法能够有效地去除干扰线因素。不过也不算完全没有收获,这里就谈谈直线的检测。

OpenCV提供hough变换来检测直线,具体的API是

CvSeq* cvHoughLines2(CvArr* image,void* line_storage,int mehtod,double rho,double theta,int threshold,double param1 =0,double param2 =0);


image就是源图像,单通道图像,因此被检测的图像必须是灰度图,另外需要注意的是原图像在函数调用完成后会改变,因此有必要在调用这个函数进行hough检测之间对原来的图像进行备份。

line_storage在这里是检测到的线段存储仓. 可以是内存存储仓 (此种情况下,一个线段序列在存储仓中被创建,并且由函数返回),或者是包含线段参数的特殊类型(见下面)的具有单行/单列的矩阵(CvMat*)。矩阵头为函数所修改,使得它的 cols/rows 将包含一组检测到的线段。如果 line_storage 是矩阵,而实际线段的数目超过矩阵尺寸,那么最大可能数目的线段被返回(线段没有按照长度、可信度或其它指标排序).

method表示变换的方法,OpenCV一共给出了3种变换方法,分别是:

CV_HOUGH_STANDARD - 传统或标准 Hough 变换. 每一个线段由两个浮点数 (ρ, θ) 表示,其中 ρ 是直线与原点 (0,0) 之间的距离,θ 线段与 x-轴之间的夹角。因此,矩阵类型必须是 CV_32FC2 type.

CV_HOUGH_PROBABILISTIC - 概率 Hough 变换(如果图像包含一些长的线性分割,则效率更高). 它返回线段分割而不是整个线段。每个分割用起点和终点来表示,所以矩阵(或创建的序列)类型是 CV_32SC4.

CV_HOUGH_MULTI_SCALE - 传统 Hough 变换的多尺度变种。线段的编码方式与 CV_HOUGH_STANDARD 的一致。

rho表示与像素相关单位的距离精度

theta表示弧度测量的角度精度

threshold表示阀值,如果相应的累计值大于这个值,就返回这条线段

param1第一个方法相关的参数:

对传统 Hough 变换,不使用(0).

对概率 Hough 变换,它是最小线段长度.

对多尺度 Hough 变换,它是距离精度 rho 的分母 (大致的距离精度是 rho 而精确的应该是 rho / param1 ).

param2第二个方法相关参数:

对传统 Hough 变换,不使用 (0).

对概率 Hough 变换,这个参数表示在同一条直线上进行碎线段连接的最大间隔值(gap), 即当同一条直线上的两条碎线段之间的间隔小于param2时,将其合二为一。

对多尺度 Hough 变换,它是角度精度 theta 的分母 (大致的角度精度是 theta 而精确的角度应该是 theta / param2).

函数最后返回检测到得line数组,这个数组每个值都是检测到得一条直线,使用cvGetSeqElem函数可以读取line数组种的直线,返回值是一个float数组,有两个值,第一个是该直线的rho,第二个值表示theta。这样就可以得到检测的直线了。

下面有一个例子,就是我在验证码去除干扰线所做的尝试。

void Image::RemoveLine(int nThsd){IplImage *srcRGB = cvLoadImage("temp.jpg");IplImage *src = cvCreateImage(cvSize(srcRGB->width,srcRGB->height),IPL_DEPTH_8U,1);cvCvtColor(srcRGB,src,CV_RGB2GRAY);IplImage *dst = cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,src->nChannels);CvMemStorage *storage = cvCreateMemStorage();CvSeq *lines = 0;cvCanny(src,dst,40,90);lines = cvHoughLines2(dst,storage,CV_HOUGH_STANDARD,1,CV_PI/180,nThsd,0,0);for(int i = 0;i<MIN(lines->total,100);i++){float *line = (float*)cvGetSeqElem(lines,i);float rho = line[0];float threta = line[1];CvPoint pt1, pt2;double a = cos(threta),b = sin(threta);double x0 = a*rho, y0 = b * rho;pt1.x = cvRound(x0 + 200*(-b));pt1.y = cvRound(y0 + 200*(a));pt2.x = cvRound(x0 - 200*(-b));pt2.y = cvRound(y0 - 200*(a));cvLine(src,pt1,pt2,cvScalar(255),1,8);}Mat temp(src);temp.copyTo(m_Mat);}

在这里,先对前面经过处理降噪的二值图像做一个拷贝,然后在使用hough检测,经过检测得到的line对象,根据rho和theta求出直线的两个端点,然后利用cvLine函数再对源图像(检测过的图像已经改变)的直线所在的位置进行颜色覆盖,由于字符pixel是黑色,背景是白色,这里我都填充的是白色(255灰度值)。

下面是运行的结果:


左上图是源图,右上图是hough检测的结果,直线部分用红色显示出来,最后对其进行处理,把检测到得直线部分填充为白色

当然前面这张效果比较好,后面的效果就一般了



可以看到,仅仅用hough检测来去除干扰线是不行的,这是因为干扰线不一定是直线,很多干扰线都是弯弯曲曲的,有的甚至粗细不一,因此在检测时比较难,我也没有找到较好地通用直线检测方法。当然对于特定的干扰线,比如有些彩色的验证码图片中,干扰线和字符的颜色不一样,这样的检测起来就很简单了。

0 0
原创粉丝点击