圖片的傾斜檢測


1、原理:

計算圖片里主要少數線條的平均角度,大於某個值則認為傾斜

2、效果圖:

傾斜的(設角度大於12度為傾斜)

 正常的

 

 3、流程

a、先對圖片進行大小縮放,加快處理速度

Mat srcPic = imread(pInFileName);
	int cols=configText.resizeCols;
	int rows=srcPic.rows/(srcPic.cols*1.00/cols);//按寬高比例縮放
	Mat src =Mat::zeros(rows,cols , CV_8UC3);
	resize(srcPic,src,src.size());

b、如果要檢索的圖片具有共同的特征(都是貨架且貨架顏色相同)可采用閾值化二分,讓邊緣檢測更有方向性(慎用!

threshold(srcImage, srcThrImage, 40, 255, THRESH_BINARY);
	imshow("閾值化后的效果圖", srcThrImage);

c、通過Canny算子進行邊緣檢測

高閾值求邊緣低閾值平滑邊緣,可以將高低閾值的比率設置為足夠大如factor=5使得邊緣更加的平滑

Canny(srcThrImage, midImage, cannyThreshold,cannyThreshold*factor);//Canny邊緣檢測算法,指定高低閾值(梯度幅值)

d、根據邊緣用HoughLinesP霍夫線變換檢測直線,最終需要控制檢測到的直線條數

方法說明:

霍夫變換使用極坐標來表示直線(極徑rho和極角theta),一條直線能夠通過在平面 \theta - r 尋找交於一點的曲線數量來檢測

CV_EXPORTS_W void HoughLinesP( InputArray image, OutputArray lines,
double rho, double theta, int threshold,
double minLineLength=0, double maxLineGap=0 );

rho:就是一個半徑的分辨率
theta:角度分辨率
threshold:判斷直線點數的閾值
minLineLength:線段長度閾值
minLineGap:線段上最近兩點之間的閾值(不大於此閾值則會認為是同一條直線上的點)

注意:

1、參數 threshold、minLineLength的設置很重要,關系到是否能過檢測到線段及數量,需要根據目標圖片的大小特征實驗得到

2、minLineGap建議設置為2會使實際的輪廓更多的識別為線段,太大也會導致識別太多的錯誤線段。

HoughLinesP(midImage, lines, 1, CV_PI / 180, configText.thresholdVal, configText.minLineLength, configText.maxLineGap);//HoughLinesP霍夫線變換
	while (lines.size()>10)//為了保持檢查到的直線條數需要對threshold進行遞減或遞增
	{
		cannyThreshold+=10;
		Canny(srcThrImage, midImage, cannyThreshold,cannyThreshold*factor);
		cvtColor(midImage, dstImage, CV_GRAY2BGR);
		HoughLinesP(midImage, lines, 1, CV_PI / 180, configText.thresholdVal, configText.minLineLength, configText.maxLineGap);
	}
	if (!lines.size())
	{
		cannyThreshold-=10;
		Canny(srcThrImage, midImage, cannyThreshold,cannyThreshold*factor);
		cvtColor(midImage, dstImage, CV_GRAY2BGR);
		HoughLinesP(midImage, lines, 1, CV_PI / 180, configText.thresholdVal, configText.minLineLength, configText.maxLineGap);
	}

e、對檢測到的線條計算平均角度用來判斷是否傾斜

注意:

1、檢測到最大角度不會超過45度

2、保證檢測到的線條數足夠多(如50,太多會有很多無效的線段導致最終結果無意義),讓計算的平均角度與實際更加的符合

double DetectionSlope::GetAvgAngle(const vector<Vec4i>& lines){//通過直線求平均角度
	double totalAngle=0;
	for (auto & line : lines)
	{
		//360度=2π弧度
		auto radian=atan(abs((line[3]-line[1])*1.0/(line[2]-line[0])));
		auto angle=abs(360*radian/(2*CV_PI));
		if(angle>45)
			angle=abs(90-angle);
		totalAngle+=angle;
	}
	return totalAngle/lines.size();
}

4、補充

a、對於沒有扭曲只是角度傾斜的圖片可通過旋轉來修正

//逆時針旋轉圖像degree角度(原尺寸)    
void rotateImage(Mat src, Mat& img_rotate, double degree)
{
	//旋轉中心為圖像中心    
	Point2f center;
	center.x = float(src.cols / 2.0);
	center.y = float(src.rows / 2.0);
	int length = 0;
	length = sqrt(src.cols*src.cols + src.rows*src.rows);
	//計算二維旋轉的仿射變換矩陣  
	Mat M = getRotationMatrix2D(center, degree, 1);//獲取旋轉矩陣
	warpAffine(src, img_rotate, M, Size(length, length), 1, 0, Scalar(255,255,255));//仿射變換,背景色填充為白色  
}

b、對於存在扭曲的圖片進行修正需要找到 四個角的坐標點,一般認為是檢測到的直線的四個角度(這個不太靠譜,找准實際的四個點比較難)

通過檢測到的四個坐標點,形成源與目標的變換矩陣,再對圖片進行透視變換

	Mat m1 = Mat(srcTriangle);
	Mat m2 = Mat(dstTriangle);
	Mat status;
	Mat h = findHomography(m1, m2, status, 0, 3);//獲取單映射H(理解為兩帳圖片的點映射)
	warpPerspective(this->srcImage, this->dstImage, h, this->dstImage.size());//對圖像進行透視變換,就是變形

 

 

 

 

參考:

Canny邊緣檢測

http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.html#canny-detector 

threshold閾值操作

http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/threshold/threshold.html#basic-threshold

霍夫線變換

http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.html#hough-lines

圖像旋轉

https://blog.csdn.net/guduruyu/article/details/70799804

Homography單映射

https://blog.csdn.net/liuphahaha/article/details/50719275

perspectiveTransform透視變換

https://blog.csdn.net/xiaowei_cqu/article/details/26478135

對傾斜的圖像進行修正——基於opencv 透視變換 

https://blog.csdn.net/MrCharles/article/details/73739693

極坐標

https://zhuanlan.zhihu.com/p/26172668

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM