国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

使用opencv提取單據輪廓并旋轉后生成圖片

2019-11-08 01:47:56
字體:
來源:轉載
供稿:網友

最近做圖像識別方面的工作,需要對圖片中的票據進行提取、識別,票據可能并不是正著放進去的,所以還需要進行旋轉,還涉及到一些坐標轉換的問題。

這就要用到opencv的輪廓提取、旋轉變換等接口知識了。

首先,看看要識別的圖片,這里我隨便找了一張單據的圖片

這里要把圖片中的單據提取出來,扶正,并且單據要充滿整個圖片。(其實還需要識別單據左上方的條形碼,并獲取其坐標,有點復雜,這里就不說了)

這里說說我的思路:首先,灰度化、二值化,根據亮度的不同,把單據部分的輪廓提取出來,然后填充單據部分,將其作為mask把單據部分拿出來,然后旋轉扶正,再次識別,去除邊框外的部分,剩下部分生成圖片保存。這個過程其實就是這么簡單,下面直接上代碼:

void GetContoursPic(const char* pSrcFileName, const char* pDstFileName){	iplImage* pSrcImg = NULL;      IplImage* pFirstFindImg = NULL;      IplImage* PRoiSrcImg = NULL;  	IplImage* pRatationedImg = NULL;	IplImage* pSecondFindImg = NULL;	IplImage* pDstImg = NULL;      CvSeq* pFirstSeq = NULL; 	CvSeq* pSecondSeq = NULL; 	CvMemStorage* storage = cvCreateMemStorage(0);      pSrcImg = cvLoadImage(pSrcFileName, 1);      pFirstFindImg = cvCreateImage(cvGetSize(pSrcImg), IPL_DEPTH_8U, 1);   	//檢索外圍輪廓    cvCvtColor(pSrcImg, pFirstFindImg, CV_BGR2GRAY);  //灰度化    cvThreshold(pFirstFindImg, pFirstFindImg, 100, 200, CV_THRESH_BINARY);  //設置閾值,二值化	//注意第5個參數為CV_RETR_EXTERNAL,只檢索外框    int nCount = cvFindContours(pFirstFindImg, storage, &pFirstSeq, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);  	//顯示看一下	cvNamedWindow ("pSrcImg", 1);  	cvShowImage("pSrcImg", pSrcImg);       for (;pFirstSeq != NULL; pFirstSeq = pFirstSeq->h_next)      {  		if (pFirstSeq->total < 600) //太小的不考慮,這個要考慮圖片分辨率大小		{			continue;		}		//需要獲取的坐標		CvPoint2D32f rectpoint[4]; 		CvBox2D End_Rage2D = cvMinAreaRect2(pFirstSeq); //尋找包圍矩形,獲取角度		cvBoxPoints(End_Rage2D, rectpoint); //獲取4個頂點坐標		//與水平線的角度		float angle = End_Rage2D.angle;		CString strFort = _T("");		strFort.Format(_T("/n angle:%f /n"), angle);		OutputDebugString(strFort);		//如果角度超過5度,就需要做旋轉,否則不需要		if (angle > 5 || angle < -5)		{			//計算兩條邊的長度			int line1 = sqrt((rectpoint[1].y-rectpoint[0].y)*(rectpoint[1].y-rectpoint[0].y)+(rectpoint[1].x-rectpoint[0].x)*(rectpoint[1].x-rectpoint[0].x));			int line2 = sqrt((rectpoint[3].y-rectpoint[0].y)*(rectpoint[3].y-rectpoint[0].y)+(rectpoint[3].x-rectpoint[0].x)*(rectpoint[3].x-rectpoint[0].x));					//為了讓正方形橫著放,所以旋轉角度是不一樣的			if (line1 > line2) //			{				angle = 90 + angle;			}			//新建一個感興趣的區域圖,大小跟原圖一樣大			pRoiSrcImg = cvCreateImage(cvGetSize(pSrcImg), pSrcImg->depth, pSrcImg->nChannels); 			cvSet(pRoiSrcImg, CV_RGB(0,0,0));  //顏色都設置為黑色			//對得到的輪廓填充一下			cvDrawContours(pFirstFindImg, pFirstSeq, CV_RGB(255, 255, 255), CV_RGB(255, 255, 255), -1, CV_FILLED, 8);			//把pFirstFindImg這個填充的區域從pSrcImg中摳出來放到pRoiSrcImg上			cvCopy(pSrcImg, pRoiSrcImg, pFirstFindImg);			//再顯示一下看看,除了感興趣的區域,其他部分都是黑色的了			cvNamedWindow ("pRoiSrcImg", 1);  			cvShowImage("pRoiSrcImg", pRoiSrcImg);			//創建一個旋轉后的圖像			pRatationedImg = cvCreateImage(cvGetSize(pRoiSrcImg), pRoiSrcImg->depth, pRoiSrcImg->nChannels); 			//對pRoiSrcImg進行旋轉			CvPoint2D32f center = End_Rage2D.center;  //中心點			double map[6];			CvMat map_matrix = cvMat(2, 3, CV_64FC1, map);			cv2DRotationMatrix(center, angle, 1.0, &map_matrix);			cvWarpAffine(pRoiSrcImg, pRatationedImg, &map_matrix, CV_INTER_LINEAR | CV_WARP_FILL_OUTLIERS, cvScalarAll(0));			//顯示一下旋轉后的圖像			cvNamedWindow ("pRatationedImg", 1);  			cvShowImage ("pRatationedImg", pRatationedImg); 			//對旋轉后的圖片進行輪廓提取			pSecondFindImg = cvCreateImage(cvGetSize(pRatationedImg), IPL_DEPTH_8U, 1);			cvCvtColor(pRatationedImg, pSecondFindImg, CV_BGR2GRAY);  //灰度化			cvThreshold(pSecondFindImg, pSecondFindImg, 80, 200, CV_THRESH_BINARY); 			nCount = cvFindContours(pSecondFindImg, storage, &pSecondSeq, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);  			for (;pSecondSeq != NULL; pSecondSeq = pSecondSeq->h_next)  			{  				if (pSecondSeq->total < 600) //太小的不考慮				{					continue;				}				//這時候其實就是一個長方形了,所以獲取rect				CvRect rect = cvBoundingRect(pSecondSeq); 				cvSetImageROI(pRatationedImg, rect);  				CvSize dstSize;				dstSize.width = rect.width;				dstSize.height = rect.height;				pDstImg = cvCreateImage(dstSize, pRatationedImg->depth, pRatationedImg->nChannels);  				cvCopy(pRatationedImg, pDstImg, 0);  				cvResetImageROI(pRatationedImg);  				//保存成圖片				cvSaveImage(pDstFileName, pDstImg);			}		}		else		{			//角度比較小,本來就是正放著的,所以獲取矩形			CvRect rect = cvBoundingRect(pFirstSeq); 			//把這個矩形區域設置為感興趣的區域			cvSetImageROI(pSrcImg, rect);  			CvSize dstSize;			dstSize.width = rect.width;			dstSize.height = rect.height;			pDstImg = cvCreateImage(dstSize, pSrcImg->depth, pSrcImg->nChannels);  			//拷貝過來			cvCopy(pSrcImg, pDstImg, 0);  			cvResetImageROI(pSrcImg);  			//保存			cvSaveImage(pDstFileName, pDstImg);		}	}  	//顯示一下最后的結果    cvNamedWindow ("Contour", 1);      cvShowImage("Contour", pDstImg);        cvWaitKey(0);    	//釋放所有    cvReleaseMemStorage(&storage);  	if (pRoiSrcImg)	{		cvReleaseImage(&pRoiSrcImg);	}	if (pRatationedImg)	{		cvReleaseImage(&pRatationedImg); 	}	if (pSecondFindImg)	{		cvReleaseImage(&pSecondFindImg); 	}	cvReleaseImage(&pDstImg);    cvReleaseImage(&pFirstFindImg);  	cvReleaseImage(&pSrcImg); }調用的時候直接使用類似這樣既可:

GetContoursPic("D://clip//IMG_1431.JPG", "D://clip//IMG_1431_ratation.JPG");  

這個過程中,其實最重要的部分就是設置提取的閾值、提取和旋轉,首先看設置閾值

cvThreshold(pFirstFindImg, pFirstFindImg, 100, 200, CV_THRESH_BINARY);  //設置閾值,二值化

這里第三、第四和第五個參數很重要,在第五個參數為CV_THRESH_BINARY的時候,只要圖片中的亮度超過100的,就顯示200的亮度以便于提取,這樣檢索外框的接口就可以提取了

int nCount = cvFindContours(pFirstFindImg, storage, &pFirstSeq, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);  

這里第三和第五個參數很重要,CV_RETR_EXTERNAL表示只檢索外框,pFirstSeq是檢索后獲取到的外框鏈表,可從中篩選出需要的外框。

cv2DRotationMatrix(center, angle, 1.0, &map_matrix);cvWarpAffine(pRoiSrcImg, pRatationedImg, &map_matrix, CV_INTER_LINEAR | CV_WARP_FILL_OUTLIERS, cvScalarAll(0));

這兩個接口主要是用來旋轉變換的,上方的是獲取旋轉矩陣,下方是旋轉變換

可以根據下方的圖片看到程序處理的過程

完整的工程,可以到這里下載:工程下載


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 北流市| 兴隆县| 晋州市| 邯郸市| 新兴县| 香河县| 精河县| 苏尼特右旗| 湖口县| 尚义县| 广汉市| 锡林浩特市| 五河县| 如东县| 岳普湖县| 临颍县| 怀来县| 元朗区| 和龙市| 米泉市| 时尚| 巴马| 大港区| 磐石市| 绍兴市| 兴宁市| 大化| 隆回县| 潮州市| 阳东县| 三台县| 当涂县| 都匀市| 台州市| 贺兰县| 桐庐县| 宣武区| 香河县| 天柱县| 揭东县| 河间市|