日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

『OpenCV3』霍夫变换原理及实现

發布時間:2024/8/26 综合教程 34 生活家
生活随笔 收集整理的這篇文章主要介紹了 『OpenCV3』霍夫变换原理及实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

霍夫變換常用于檢測直線特征,經擴展后的霍夫變換也可以檢測其他簡單的圖像結構。

在霍夫變換中我們常用公式

ρ = x*cosθ + y*sinθ

表示直線,其中ρ是圓的半徑(也可以理解為原點到直線的距離),θ是直線與水平線所成的角度(0~180°),確定了它們,也就確定一條直線了,和下圖略有出入的是實際的原點定在圖片左上角。

原理是對于輸入的二值圖像中的像素點(有值的),按照步長(參數三參數四對應rho和theta的步長)分別計算出每個點上的所有可能的直線。記錄下每條直線經過的點數(即存在多個點計算出的直線有交集),按照閾值(參數五)篩選符合條件的圖像,下面給出基本霍夫變換的由來,原文見:霍夫變換。

基本原理

一條直線可由兩個點A=(X1,Y1)和B=(X2,Y2)確定(笛卡爾坐標)

另一方面,也可以寫成關于(k,q)的函數表達式(霍夫空間):

對應的變換可以通過圖形直觀表示:

變換后的空間成為霍夫空間。即:笛卡爾坐標系中一條直線,對應霍夫空間的一個點

反過來同樣成立(霍夫空間的一條直線,對應笛卡爾坐標系的一個點):

再來看看A、B兩個點,對應霍夫空間的情形:

一步步來,再看一下三個點共線的情況:

可以看出如果笛卡爾坐標系的點共線,這些點在霍夫空間對應的直線交于一點:這也是必然,共線只有一種取值可能。

如果不止一條直線呢?再看看多個點的情況(有兩條直線):

其實(3,2)與(4,1)也可以組成直線,只不過它有兩個點確定,而圖中A、B兩點是由三條直線匯成,這也是霍夫變換的后處理的基本方式選擇由盡可能多直線匯成的點

看看,霍夫空間:選擇由三條交匯直線確定的點(中間圖),對應的笛卡爾坐標系的直線(右圖)。

到這里問題似乎解決了,已經完成了霍夫變換的求解,但是如果像下圖這種情況呢?

k=∞是不方便表示的,而且q怎么取值呢,這樣不是辦法。因此考慮將笛卡爾坐標系換為:極坐標表示

在極坐標系下,其實是一樣的:極坐標的點→霍夫空間的直線,只不過霍夫空間不再是[k,q]的參數,而是的參數,給出對比圖:

是不是就一目了然了?

給出霍夫變換的算法步驟:

計數過程簡易實現如下,我們通過H矩陣記錄每一條直線經過的像素點,后續處理實際上已經不算Hough算法的部分了,不予實現了,另外我的H矩陣的行數(即rho的存儲部分)設定的非常不嚴謹,浪費了很多空間,實際實現應考慮優化,確定rho的最小范圍,并投影到0~某個正數區間,作為H的行數。

void hough() {
	Mat souImg = imread("建筑.png");
	imshow("原始圖片", souImg);
	Mat contour;
	Canny(souImg, contour, 50, 200);
	imshow("輪廓圖片", contour);
	int H_row;
	if (contour.cols > contour.rows)
		H_row = contour.cols;
	else
		H_row = contour.rows;
	Mat H(3*H_row, 180, CV_8S, Scalar(0));
	std::cout << H_row << std::endl;

	float theta, rho;
	for (int i = 0; i < contour.rows; i++) {
		for (int j = 0; j < contour.cols; j++) {
			if (contour.at<uchar>(i, j) > 0) {
				for (theta = 0; theta < 180; ++theta) {
					rho = floor(i*cos(theta*CV_PI / 180) + j*sin(theta*CV_PI / 180));
					try {
						H.at<uchar>(rho + H_row, theta) += 1;
					}
					catch (...) {
						std::cout << i << j << rho << theta << std::endl;
						return;
					}
				}
			}
		}
	}
	imshow("H", H);
	waitKey(0);
}

1、霍夫變換

霍夫變換接收二值化的輸入,即已經進行初步的輪廓檢測之后,才進行直線檢測;輸出一組cv::Vec2f,通常用vector<CV::Vec2f>接收,所以我們通常使用Canny檢測之后進行霍夫變換

輸出的兩個float數字表示(rho, theta),使用cv::line繪圖,因其參數需要的是線段的兩個端點,所以我們不得不進行還原操作。

void hough() {
	cv::Mat image = cv::imread("road.png");
	cv::Mat midImage;
	cv::Canny(image, midImage, 50, 200, 3);
	std::vector<cv::Vec2f> lines;
	cv::HoughLines(midImage, lines, 1, CV_PI / 180, 150);  // 輸入的時二值圖像,輸出vector向量
	for (size_t i=0; i < lines.size(); i++) {
		float rho = lines[i][0]; //就是圓的半徑r
		float theta = lines[i][1]; //就是直線的角度
		cv::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));

		cv::line(image, pt1, pt2, cv::Scalar(55, 100, 195), 1); //Scalar函數用于調節線段顏色,就是你想檢測到的線段顯示的是什么顏色

		cv::imshow("邊緣檢測后的圖", midImage);
		cv::imshow("最終效果圖", image);
	}
}

2、概率霍夫變換

概率霍夫變換輸出Vec4i,直接輸出了每一條線段的首尾,繪圖更加方便。它是霍夫變換的改進版,由于算法的改進(會沿著搜尋到的直線掃描圖像),可以進一步檢測到線段的長度,除了最小投票數(參數五)外,可以額外限制最小線段長度(參數六)和同一線段最大像素間距(參數七)。

void houghp() {
	cv::Mat image = cv::imread("road.png");
	cv::Mat midImage;
	cv::Canny(image, midImage, 50, 200, 3);
	std::vector<cv::Vec4i> lines;
	cv::HoughLinesP(midImage, lines, 1, CV_PI / 180, 50);  // 輸入的時二值圖像,輸出vector向量
	for (int i=0; i < lines.size(); i++) {
		cv::Point pt1(lines[i][0], lines[i][1]);
		cv::Point pt2(lines[i][2], lines[i][3]);
		cv::line(image, pt1, pt2, cv::Scalar(0, 255, 255));
	}
	cv::imshow("概率霍夫變換", image);
}

總結

以上是生活随笔為你收集整理的『OpenCV3』霍夫变换原理及实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。