Opencv——霍夫變換以及遇到的一些問題

問題1 :顏色空間轉換函數參數問題:CV_BGR2GRAY vs CV_GRAY2BGR

OpenCV的顏色空間轉換函數:

void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0 )

dstCn現在已經改成COLOR_GRAY2BGR之類的以COLOR開頭的。
CV_BGR2GRAY :將RGB圖轉換成GRAY圖
CV_GRAY2BGR:將GRAY圖轉換成RGB圖
淺墨源碼
cvtColor(midImage, dstImage, COLOR_GRAY2BGR);
//將canny算子掃描後的二值圖轉化爲RGB圖,原因是後面你可視化霍夫變換效果時,畫的曲線是彩色的。

問題2:cvRound()、cvFloor()、cvCeil()函數用法

cvRound():返回跟參數最接近的整數值,即四捨五入;
cvFloor():返回不大於參數的最大整數值,即向下取整;
cvCeil():返回不小於參數的最小整數值,即向上取整;

霍夫變換的含義

這個我在邊緣的文章中有涉及過,直接貼鏈接:
https://blog.csdn.net/qq_42604176/article/details/104300287
還有我參考的一個鏈接:
https://blog.csdn.net/yuyuntan/article/details/80141392

標準霍夫直線變換

霍夫線變換函數參數講解

●第一個參數,InputArray類型的image, 輸入圖像,即源圖像。需爲8位的單通道二進制圖像
●第二個參數,InputArray類型的lines,經過調用HoughLines函數後儲存了霍 夫線變換檢測到線條的輸出矢量。每一條線由具有兩個元素的矢量( ρ, 0) 表示,其中,ρ是離座標原點(0,0) (也就是圖像的左上角)的距離,θ是弧度線條旋轉角度(0度表示垂直線,π/2 度表示水平線)。
●第三個參數,double類型的rho,以像素爲單位的距離精度。另-種表述方
式是直線搜索時的進步尺寸的單位半徑。(Latex 中/rho即表示ρ )
●第四個參數,double 類型的theta,
以弧度爲單位的角度精度。另一種表述 方式是直線搜索時的進步尺寸的單位角度。
●第五個參數,int類型的threshold,累加平面的閾值參數,即識別某部分爲 圖中的一條直線時它在累加平面中必須達到的值。大於國值threshold的線段纔可以被檢測通過並返回到結果中。
●第六個參數,double類型的srn,, 有默認值0。對於多尺度的霍夫變換,這 是第三個參數進步尺寸rho的除數距離。粗略的累加器進步尺寸直接是第三個參數rho,而精確的累加器進步尺寸爲rho/sm。
●第七個參數,double 類型的stn, 有默認值0,對於多尺度霍夫變換,sm表示第四個參數進步尺寸的單位角度theta的除數距離。且如果sr和 stn同時爲0,就表示使用經典的霍夫變換。否則,這兩個參數應該都爲正數。

理解:在XY平面,直線有兩個參數:K、B(斜率和截距),可視化直線,需要構造x,y軸,假設XY軸的最小精度爲1,則勾畫出的直線其實是一系列離散的點。隨着XY精度升高,所可視化出來的數據將越來越像一條線。
同理,在rho/theta平面,一條直線對應平面上以rho爲橫座標,tehta爲縱座標的一個點。
rho/theta的精度越高,所表示的直線越精準。我想這邊是第三參數和第四參數的含義。
我們一般以rho=1,theta=1度的精度來構造投票空間。

#include <opencv2/opencv.hpp>
#include <iostream>
#include "windows.h"
#include <stdio.h>
#define WINDOW_NAME "【程序窗口】"			//爲窗口標題定義的宏

using namespace cv;
using namespace std;
//==================================標準霍夫變換============================================
int main()
{
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN);		//字體爲綠色

	Mat srcImage = imread("D:\\opencv_picture_test\\霍夫變換.png");
	//判斷圖像是否加載成功
	if (srcImage.empty())
	{
		cout << "圖像加載失敗!" << endl;
		return -1;
	}
	else
		cout << "圖像加載成功!" << endl << endl;
	Mat midImage,dstImage;
	Canny(srcImage, midImage, 50, 200, 3);//進行一此canny邊緣檢測  
	//【3】進行霍夫線變換  
	vector<Vec2f> lines;//定義一個矢量結構lines用於存放得到的線段矢量集合  
	HoughLines(midImage, lines, 1, CV_PI / 180, 150, 0, 0);
	//【4】依次在圖中繪製出每條線段  
	for (size_t i = 0; i < lines.size(); i++)
	{
		float rho = lines[i][0], theta = lines[i][1];
		Point pt1, pt2;
		double a = cos(theta), b = sin(theta);
		double x0 = a * rho, y0 = b * rho;
		pt1.x = cvRound(x0 + 1000 * (-b));	
		
		pt1.y = cvRound(y0 + 1000 * (a));
		pt2.x = cvRound(x0 - 1000 * (-b));
		pt2.y = cvRound(y0 - 1000 * (a));
		line(midImage, pt1, pt2, Scalar(255,255,255),1, LINE_AA);
	}

	//【5】顯示原始圖    
	imshow("【原始圖】", srcImage);

	//【6】邊緣檢測後的圖   
	imshow("【邊緣檢測後的圖】", midImage);

	//【7】顯示效果圖    
	//imshow("【效果圖】", dstImage);
	waitKey(0);
	return 0;
}

累計概率霍夫變換

C++: void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength=0, double maxLineGap=0 )

第一個參數,InputArray類型的image,輸入圖像,即源圖像,需爲8位的單通道二進制圖像,可以將任意的源圖載入進來後由函數修改成此格式後,再填在這裏。
第二個參數,InputArray類型的lines,經過調用HoughLinesP函數後後存儲了檢測到的線條的輸出矢量,每一條線由具有四個元素的矢量(x_1,y_1, x_2, y_2) 表示,其中,(x_1, y_1)和(x_2, y_2) 是是每個檢測到的線段的結束點。
第三個參數,double類型的rho,以像素爲單位的距離精度。另一種形容方式是直線搜索時的進步尺寸的單位半徑。
第四個參數,double類型的theta,以弧度爲單位的角度精度。另一種形容方式是直線搜索時的進步尺寸的單位角度。
第五個參數,int類型的threshold,累加平面的閾值參數,即識別某部分爲圖中的一條直線時它在累加平面中必須達到的值。大於閾值threshold的線段纔可以被檢測通過並返回到結果中。
第六個參數,double類型的minLineLength,有默認值0,表示最低線段的長度,比這個設定參數短的線段就不能被顯現出來。
第七個參數,double類型的maxLineGap,有默認值0,允許將同一行點與點之間連接起來的最大的距離。

通過設定直線長度閾值,對過長或過短的直線不予理會。

//==================================累計概率霍夫變換============================================
int main()
{
	//讀取原圖片
	Mat Image = imread("D:\\opencv_picture_test\\霍夫變換.png");
	//顯示原圖片
	namedWindow("【原圖】");
	imshow("【原圖】", Image);

	Mat srcImage = Image.clone();
	Mat midImage, dstImage;
	//進行邊緣檢測和轉化爲將灰度圖轉爲RGB圖
	Canny(srcImage, midImage, 50, 200, 3);
	cvtColor(midImage, dstImage, COLOR_GRAY2BGR);
	//定義矢量結構lines用於存放得到的線段矢量集合
	vector<Vec4i> lines;
	//進行霍夫變換
	HoughLinesP(midImage, lines, 1, CV_PI / 180, 80, 50, 10);
	//依次在圖中繪製每條線段
	for (size_t i = 0;i < lines.size();i++) {
		Vec4i l = lines[i];
		line(dstImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 1, LINE_AA);
	}

	imshow("【邊緣檢測後的圖】", midImage);
	imshow("【效果圖】", dstImage);

	waitKey(0);
	return 0;
}

霍夫變換圓變換

原理和算法步驟:

原理和算法步驟

霍夫圓變換函數參數講解

cvHoughCircles( CvArr* image, void* circle_storage, int method, double dp, double min_dist, double param1=100, double param2=100, int min_radius=0, int max_radius=0 );

輸入:輸入 8-bit、單通道灰度圖像. circle_storage:檢測到的圓存儲倉. 可以是內存存儲倉 (此種情況下,一個線段序列在存儲倉中被創建,並且由函數返回)或者是包含圓參數的特殊類型的具有單行/單列的CV_32FC3型矩陣(CvMat*).矩陣頭爲函數所修改,使得它的 cols/rows 將包含一組檢測到的圓。如果 circle_storage是矩陣,而實際圓的數目超過矩陣尺寸,那麼最大可能數目的圓被返回。 每個圓由三個浮點數表示:圓心座標(x,y)和半徑.
method:Hough 變換方式,目前 只支持HOUGH_GRADIENT
dp:累加器圖像的分辨率。這個參數允許創建一個比輸入圖像分辨率低的累加器。(這樣做是因爲有理由認爲圖像中存在的圓會自然降低到與圖像寬高相同數量的範疇)。如果dp設置爲1,則分辨率是相同的;如果設置爲更大的值(比如2),累加器的分辨率受此影響會變小(此情況下爲一半)。dp的值不能比1小。
min_dist:該參數是讓算法能明顯區分的兩個不同圓之間的最小距離。
param1:用於Canny的邊緣閥值上限,下限被置爲上限的一半。
param2:累加器的閥值。
min_radius:最小圓半徑。
max_radius:最大圓半徑。


////==================================霍夫變換圓變換============================================

int main()
{
	//載入原始圖和Mat變量定義     
	Mat srcImage = imread("D:\\opencv_picture_test\\形態學操作\\孔洞.png");
	Mat midImage, dstImage;
	//顯示原始圖  
	imshow("【原始圖】", srcImage);

	//轉爲灰度圖,進行圖像平滑  
	cvtColor(srcImage, midImage, COLOR_BGR2GRAY);//轉化邊緣檢測後的圖爲灰度圖  
	GaussianBlur(midImage, midImage, Size(9, 9), 2, 2);		//模糊去噪

	//進行霍夫圓變換  
	vector<Vec3f> circles;		//圓存儲器,存儲圓的數量,圓心座標和半徑
	HoughCircles(midImage, circles,HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);
	//inputImage  circle_storage 霍夫變換的方式 累加器圖像的分辨率 兩個不同圓之間的距離 
	//依次在圖中繪製出圓  
	for (size_t i = 0; i < circles.size(); i++)
	{
		Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
		int radius = cvRound(circles[i][2]);
		//繪製圓心  
		circle(srcImage, center, 3, Scalar(0, 0, 255), 3, 8, 0);
		//繪製圓輪廓  
		circle(srcImage, center, radius, Scalar(0, 0, 255), 3, 8, 0);
	}

	//顯示效果圖    
	imshow("【效果圖】", srcImage);

	while ((char)waitKey(1) != 'q') {}
	return 0;
}

霍夫變換總結

1、爲什麼在霍夫變換求直線方程時,要用極座標的形式
斜截式不能表示垂直於x軸的直線,而極座標形式可以表達。
2、霍夫變換求直線方程,和使用最小二乘法求直線最小方程相比,有什麼優缺點
優點:當出現離羣採樣點時最小二乘法會有很大誤差而霍夫變換不會
缺點:時間複雜度和空間複雜度都很高,只能檢測線段的方向,而不能確定線段的長度

參考鏈接

https://blog.csdn.net/timidsmile/article/details/9342855

https://blog.csdn.net/OliverkingLi/article/details/54754814?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158565498519724835852132%2522%252C%2522scm%2522%253A%252220140713.130056874…%2522%257D&request_id=158565498519724835852132&biz_id=0&utm_source=distribute.pc_search_result.none-task

http://www.manongjc.com/article/42132.html
https://stackoverflow.com/questions/5929125/opencv-houghcircles-param1-param2
https://blog.csdn.net/yuyuntan/article/details/80141392
淺墨大神博客

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