圖像驗證碼識別(六)——圖像中的直線檢測

這裏題目之所以沒有寫成“驗證碼圖片中的干擾線去除”,就是因爲在干擾線去除做的不是很好,最後也沒有找到什麼較爲通用的算法能夠有效地去除干擾線因素。不過也不算完全沒有收穫,這裏就談談直線的檢測。

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檢測來去除干擾線是不行的,這是因爲干擾線不一定是直線,很多幹擾線都是彎彎曲曲的,有的甚至粗細不一,因此在檢測時比較難,我也沒有找到較好地通用直線檢測方法。當然對於特定的干擾線,比如有些彩色的驗證碼圖片中,干擾線和字符的顏色不一樣,這樣的檢測起來就很簡單了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章