91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

openCV去除文字中亂入的線條的方法示例

發布時間:2020-07-20 09:38:35 來源:億速云 閱讀:262 作者:小豬 欄目:開發技術

這篇文章主要講解了openCV去除文字中亂入的線條的方法示例,內容清晰明了,對此有興趣的小伙伴可以學習一下,相信大家閱讀完之后會有幫助。

今天上午,朋友發來一張圖片如下。沒錯,這就是原圖,他希望可以通過一些簡單的算法將圖中這條穿過單詞間的直線去掉,使得到的結果能夠通過他的文字識別算法并得出正確結果——The Techniques of Machine Vision。

openCV去除文字中亂入的線條的方法示例

乍一看這似乎挺簡單,(1)將圖像二值化;(2)找出這條直線;(3)將直線區域填成背景色(即白色);(4)再通過膨脹、腐蝕等操作將單詞缺失的部分給補全。以上4步似乎可以滿足要求,但測試發現,效果不盡人意。

一、按上述方法實現過程

openCV去除文字中亂入的線條的方法示例

二值化結果如圖1.1所示,可以看到圖像并不標準,直線粗細也不一,我們嘗試用霍夫變換找一下直線,代碼如下

void findLines(IplImage* raw, IplImage* dst)
{
	IplImage* src = cvCloneImage(raw);
	IplImage* canny = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
	cvCanny(src, canny, 20, 200, 3);
	CvMemStorage* stor = cvCreateMemStorage(0);
	CvSeq* lines = NULL;
	lines = cvHoughLines2(canny, stor, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 180, 80, 200, 30);
	cvZero(dst);
	CvPoint maxStart, maxEnd;
	int maxDistance = 0;
	for (int i = 0; i < lines->total; i++)
	{
		CvPoint* line = (CvPoint*)cvGetSeqElem(lines, i);
		if (abs(line[0].x - line[1].x) > maxDistance)
		{
			maxDistance = abs(line[0].x - line[1].x);
			maxStart = line[0];
			maxEnd = line[1];
		}
	}
	cvLine(dst, maxStart, maxEnd, cvScalar(255), 1);
	cvReleaseImage(&src);
	cvReleaseMemStorage(&stor);
}

簡要解釋一下這段代碼。函數的功能是在輸入圖像中找出一條直線,輸入的圖像是灰度圖raw,返回值為dst,返回值是以圖片的形式,將找到的直線畫上圖中。

函數lines = cvHoughLines2(canny, stor, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 180, 80, 200, 30);的參數表明,要求直線長度在200個像素以上,且兩條在同一直線上的線段,如果相隔不到30個像素,就把它們連起來【注:圖片尺寸為1066×148】。對于找到的多條直線,認為最長的一條是我們要找的那條。找距離時用了abs(line[0].x - line[1].x);是不嚴格的,嚴格來講應該是

sqrt((line[0].x - line[1].x)*(line[0].x - line[1].x)+(line[0].y - line[1].y)*(line[0].x - line[1].x))

不過圖中的直線接近水平,這里就簡化一下啦。

所以將運行這段代碼后,返回的圖片dst應該是這樣子的

openCV去除文字中亂入的線條的方法示例

圖1.2中直線的粗線可以通過改變cvLine(dst, maxStart, maxEnd, cvScalar(255), 1);最后一個參數來調整,這里用的是1。

接下來步驟就是在二值化圖(圖1.1)中去掉這條線,代碼如下:

void eraseLine(IplImage* src, IplImage* flag)
{// flag為圖1.2所示的圖片,src為圖1.1所示的二值化圖片
	for (int row = 0; row < src->height; row++)
		for (int col = 0; col < src->width; col++)
		{	// 如果在白色線段上,則將二值化圖片填為白色
			if (cvGet2D(flag, row, col).val[0] == 255)
				cvSet2D(src, row, col, cvScalar(255));
		}
}

當直線的寬度分別為2、3個像素時,二值化圖去掉直線后的效果如下

openCV去除文字中亂入的線條的方法示例

可以看到,效果很差,如果要膨脹(黑色部分減小),單詞下邊部分都會消失了,直接腐蝕(黑色部分增大),線又不能完全去掉。

后來,我采用的辦法是,對圖1.3重新找一次直線(減去一次直線后,中間還殘留一部分短些的直線),再減掉,再找再減掉。后面再對圖像進行腐蝕(黑色部分增長)。最終效果最好這就如下圖所示

openCV去除文字中亂入的線條的方法示例

但這種方法用時長、針對不同的直線,找直線-減直線 的重復次數還不一樣,不具有可移植性。而且啊,這個圖片識別出來的結果是

The Technique_sJ_otMachine Vision

所以需要采用新的辦法來解決這個問題。

二、新的辦法

源代碼如下

#include <cv.h>
#include <highgui.h>
#include <iostream>
using namespace std;
/*
函數功能:在輸入圖像中找一條直線
輸入輸出:輸入的圖像是灰度圖raw,返回值為dst,返回值是一條白色的線
lines = cvHoughLines2(canny, stor, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 180, 80, 200, 30);
參數中的200是指要找的直線長度要在200個像素以上;
參數中的30指的是兩條在同一直線上的線段,如果相隔不到30,則把它們連起來
*/
void findLines(IplImage* raw, IplImage* dst)
{
 IplImage* src = cvCloneImage(raw); // clone the input image
 IplImage* canny = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1); // create a tmp image head to save gradient image
 cvCanny(src, canny, 20, 200, 3); // Generate its gradient image
 CvMemStorage* stor = cvCreateMemStorage(0);
 CvSeq* lines = NULL;
 // find a line whose length bigger than 200 pixels
 lines = cvHoughLines2(canny, stor, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 180, 80, 200, 30);
 cvZero(dst);
 CvPoint maxStart, maxEnd; // save the coordinate of the head and rear of the line we want
 int maxDistance = 0; // The maximum distance of all lines found by [cvHoughLines2]
 for (int i = 0; i < lines->total; i++) // lines->total: the number of lines 
 {
 // variable 'lines' is a sequence, [cvGetSeqElem] gets the (i)th line, and it returns its head and rear.
 CvPoint* line = (CvPoint*)cvGetSeqElem(lines, i); 
 // line[0] and line[1] is respectively the line's coordinate of its head and rear
 if (abs(line[0].x - line[1].x) > maxDistance)
 {/* It's a trick because the line is almost horizontal.
 strictly, it should be 
 sqrt((line[0].x - line[1].x)*(line[0].x - line[1].x)+(line[0].y - line[1].y)*(line[0].x - line[1].x))
 */
 maxDistance = abs(line[0].x - line[1].x);
 maxStart = line[0];
 maxEnd = line[1];
 }
 }
 cvLine(dst, maxStart, maxEnd, cvScalar(255), 1); // draw the white line[cvScalar(255)] in a black background
 cvReleaseImage(&src); // free the memory
 cvReleaseMemStorage(&stor);
}
/*
函數功能:擦除面積小于【15個像素】的小塊兒
輸入輸出:無返回值,直接對輸入的圖像進行操作
*/
void erase(IplImage* raw)
{
 IplImage* src = cvCloneImage(raw);
 /*Binarization and inverse the black and white because the function next only find white area while
 the word in image is black.*/
 cvThreshold(src, src, 120, 255, CV_THRESH_BINARY_INV); 
 // create some space to save the white areas but we access it via variable 'cont'
 CvMemStorage* stor = cvCreateMemStorage(0); 
 CvSeq* cont;
 cvFindContours(src, stor, &cont, sizeof(CvContour), CV_RETR_EXTERNAL); // find the white regions
 for (; cont; cont = cont->h_next) // Traversal
 {
 if (fabs(cvContourArea(cont)) < 15) // if its Area smaller than 15, we fill it with white[cvScalar(255)]
 cvDrawContours(raw, cont, cvScalar(255), cvScalar(255), 0, CV_FILLED, 8);
 }
 cvReleaseImage(&src);
}
 
int main()
{
 IplImage* src = cvLoadImage("D:/test.png");
 cvNamedWindow("原圖", 1);
 cvShowImage("原圖", src);
 IplImage* gray = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
 IplImage* canny = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
 IplImage* dst = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
 IplImage* binary = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
 
 cvCvtColor(src, gray, CV_RGB2GRAY);
 cvThreshold(gray, binary, 120, 255, CV_THRESH_OTSU);
 
 findLines(gray, dst);
 cvNamedWindow("dst", 1);
 cvShowImage("dst", dst);
 
 for (int row = 0; row < binary->height; row++)
 for (int col = 0; col < binary->width; col++)
 {
 if (cvGet2D(dst, row, col).val[0] == 255)
 {
 int up = 0, down = 0;
 int white = 0;
 for (int i = row; i >= 0; i--)
 {
 if (cvGet2D(binary, i, col).val[0] == 0)
 {
 up++; 
 white = 0;
 }
 else white++;
 if(white > 2) break;
 }
 white = 0;
 for (int i = row; i < binary->height; i++)
 {
 if (cvGet2D(binary, i, col).val[0] == 0)
 {
 down++;
 white = 0;
 }
 else white++;
 if (white > 2) break;
 }
 if (up + down < 8)
 {
 for (int i = -up; i <= down; i++) cvSet2D(binary, row + i, col, cvScalar(255));
 }
 }
 }
 cvNamedWindow("結果", 1);
 cvShowImage("結果", binary);
 erase(binary);
 //cvDilate(binary, binary, NULL, 1);
 cvErode(binary, binary, NULL, 1);
 cvNamedWindow("膨脹腐蝕", 1);
 cvShowImage("膨脹腐蝕", binary);
 cvSaveImage("D:/result.png", binary);
 cvReleaseImage(&src);
 cvReleaseImage(&canny);
 cvReleaseImage(&gray);
 cvReleaseImage(&dst);
 cvReleaseImage(&binary);
 cvWaitKey(0);
 return 0;
}

這個方法很簡單的,就是在找到直線(直線寬度為1)后,沿著直線從左到右對二值化圖進行上下掃描,如果這個直線的寬度(黑色的寬度)小于8個像素,則認為它只是直線,而不是文字的一部分,那么將它填成白色;反之,對于直線是文字的一部分這種情況,則不對它進行任何操作。

這樣得到的結果如下圖2.1所示

openCV去除文字中亂入的線條的方法示例

當然這個結果有點差強人意,如果你有更好的想法,請在下面留言,我們交流交流。

看完上述內容,是不是對openCV去除文字中亂入的線條的方法示例有進一步的了解,如果還想學習更多內容,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

苍南县| 楚雄市| 西乌| 墨竹工卡县| 乐东| 荆门市| 富蕴县| 汝城县| 开封市| 图木舒克市| 临泉县| 剑川县| 伊通| 黑山县| 新乡市| 蒙山县| 安阳市| 长顺县| 买车| 大丰市| 云霄县| 宜章县| 庆安县| 平湖市| 德令哈市| 洛隆县| 宁阳县| 灵丘县| 定边县| 东海县| 卓尼县| 河南省| 康乐县| 镇赉县| 玛纳斯县| 安福县| 天柱县| 秀山| 安溪县| 陆河县| 泾川县|