霍夫直線檢測的作用——計算得到輸入圖像(一般是二值化的邊緣檢測結果圖像)中包含的所有直線的數(shù)目與位置
- 在取得
圖像邊緣
的基礎上灾馒,
對一些特定的幾何形狀邊緣
巩搏,如直線敞咧、圓
匹表,通過圖像霍夫變換
把圖像從平面坐標空間
變換到霍夫坐標空間
孽江,
就可以通過求取霍夫空間
的局部極大值方法(其實就是霍夫空間中的曲線交集點)
,
得到極坐標空間
對應參數(shù)方程
中直線的兩個參數(shù)(r讶坯,θ)
,
從而計算得到邊緣圖像中
的所有直線
(基于平面坐標
)的數(shù)目與位置
岗屏。
假設有一條直線如下圖:
(紅色部分是計算過程辆琅,遞等到右下角的結果漱办,待會兒要用)
在笛卡兒平面坐標系
統(tǒng)中的斜率參數(shù)與截距參數(shù)為(k,b)
婉烟;
若變換到
極坐標空間
則變成求取另外兩個參數(shù)(r娩井,θ)
,r 和 θ
之間的關系可以表示為:
(公式的來源運算過程見上圖)
對于每個平面空間的像素點坐標(x似袁,y)
洞辣,
隨著角度θ
的取值不同,都會得到r值
昙衅,
(%+++%要點.B)而對于任意一條直線
來說扬霜,在極坐標空間
它的(r,θ)
都是固定不變的
而涉,
則對于邊緣圖像
的每個平面空間坐標點
可繪制極坐標的曲線
如圖所示:
- 上圖中著瓶,
左側是一個
平面空間的像素點
,
基于公式r = x * cosθ + y * sinθ
啼县,
通過給定不同的θ
值蟹但,得到唯一對應r
值,
無數(shù)個(r谭羔,θ)
數(shù)對構成的一道極坐標曲線
华糖;
右側是三個
平面空間的像素點
,
基于公式r = x * cosθ + y * sinθ
瘟裸,
通過給定不同的θ
值客叉,得到唯一對應r
值,
無數(shù)個(r话告,θ)
數(shù)對構成的三道極坐標曲線
兼搏;
- 無論截圖的左側還是右側,都是所謂
霍夫空間的一部分
沙郭,所謂霍夫空間
佛呻,如下圖:圖片參考于此博文
霍夫空間 概念詳析
霍夫空間
就是一個基于(r所坯,θ)兩個參數(shù)坐標軸的數(shù)據空間缤谎,
數(shù)量級規(guī)模
是可以是一個邊緣圖像
的像素點數(shù)量
斧吐;
并且這個空間包括了這樣的一系列曲線 :
一個邊緣圖像
的所有(all & each,假設為 N 個)像素點(x,y)
续捂,
基于公式r = x * cosθ + y * sinθ
斥季,
通過給定不同的θ
值茫陆,得到唯一對應r
值苫昌,
無數(shù)個(r哩至,θ)
數(shù)對構成對應上N個 像素點
的N 道 極坐標曲線(霍夫空間的曲線)
惕耕;
霍夫直線檢測 的 知識要點
- (要點.A)
輸入的邊緣圖像中的每一個像素點一 一 對 應
一條霍夫空間(or 極坐標參數(shù))曲線
纺裁;
- (要點.B)
而對于邊緣圖像中的 任意一條直線
來說,在極坐標空間
它的(r,θ)
都是固定不變的
欺缘,
- (由上可得 要點.C)
霍夫空間中的一個交集點(若干曲線的交點(r栋豫,θ))
就是一條直線
(點的參數(shù)(r,θ)可變換成直線)谚殊;- 而重疊在這個
交集點
上的霍夫(極坐標)曲線集
笼才,
其實就是該交集點
代表的(存在邊緣圖像中 的 對應的)直線
所包含的(像素)點集
;
- (要點.D)
交集點
上累積的曲線
越多
络凿;
對應(平面坐標系的邊緣圖像上的)直線
所包含的像素點集
就越多
骡送;
也即對應直線
的長度
越大
;
霍夫直線檢測 從二值化.邊緣檢測.結果圖像到檢測繪制出直線 的大概步驟
以上引用框中的內容是個人的梳理總結絮记,下面繼續(xù)讀書筆記的內容摔踱。
- 由在平面空間
同屬于一條直線的像素點
繪制出來的曲線
必然會相交于一點
(上方截圖的b)右側所示的曲線), - 而這個點正是
存在邊緣對象中的對應的直線
在極坐標空間
中的參數(shù)方程的參數(shù)
怨愤,
這樣就在極坐標空間找到了直線的參數(shù)方程派敷,
反變換
回到平面坐標空間就可以求得直線的兩個參數(shù)(k,b)撰洗,
得到直線位置篮愉,
而它們在極坐標的交點
就是直線在霍夫空間的表達
,
直線越長
差导,其在霍夫空間這個點的累積值
就越高
试躏,相對的灰度值
也就越(亮)
。
OpenCV關于霍夫直線變換
提供了兩個相關API函數(shù)设褐,
一個
是在霍夫空間求取直線兩個極坐標的參數(shù)
颠蕴,
需要開發(fā)者自己轉換到平面坐標空間計算直線;
另外
一個則會直接返回平面空間直線/線段的兩個點坐標信息
助析。
返回極坐標參數(shù)的API函數(shù)如下:
-
HoughLines(Mat image, Mat lines, double rho, double theta, int threshold)
image
:表示輸入
圖像犀被,8位單通道圖像,一般為二值圖像外冀。
lines
:表示輸出
的每個直線的極坐標參數(shù)方程的兩個參數(shù)寡键。
rho
:表示極坐標空間r值
每次的步長,一般設置為1
雪隧。
theta
:表示角度θ
西轩,每次移動1°
即可。
threshold
:表示霍夫空間
中該點的累積數(shù)
膀跌,
該累積數(shù)越大遭商,則得到的直線可能就越長,
取值范圍通常為30~50捅伤,單位是像素,
假設為30的話巫玻,則表示大于30個像素長度的線段才會被檢測到丛忆。
threshold
解釋中所述的累積數(shù)
可以看做我們數(shù)據處理中的投票機制
祠汇,
票數(shù)
大于threshold
的交集點
(即累積的曲線數(shù)
大于threshold
的交集點
),
才認定是有效直線
熄诡,
才能被函數(shù)檢測到
并提取出來
用于返回/變換
并繪制
成直線可很;
使用該API實現(xiàn)直線檢測:
private void houghLinesDemo(Mat src, Mat dst) {
Mat edges = new Mat();
Imgproc.Canny(src, edges, 50, 150, 3, true);
Mat lines = new Mat();
Imgproc.HoughLines(edges, lines, 1,Math.PI/180.0, 200);
Mat out = Mat.zeros(src.size(), src.type());
float[] data = new float[2];
for(int i=0; i<lines.rows(); i++) {
lines.get(i, 0, data);
float rho = data[0], theta = data[1];
double a = Math.cos(theta), b = Math.sin(theta);
double x0 = a*rho, y0 = b*rho;
Point pt1 = new Point();
Point pt2 = new Point();
pt1.x = Math.round(x0 + 100*(-b));//!!!!!!!!!!!!!!!!!
pt1.y = Math.round(y0 + 100*(a));
pt2.x = Math.round(x0 - 100*(-b));
pt2.y = Math.round(y0 - 100*(a));
Imgproc.line(out, pt1, pt2, new Scalar(0,0,255), 3, Imgproc.LINE_AA, 0);
}
out.copyTo(dst);
out.release();
edges.release();
}
關于pt1.x = Math.round(x0 + 100*(-b));這一行代碼,
- 關于參數(shù)100的意義凰浮,可參考 原作者博文:
x0與y0是直線上的點我抠,100是表示對該點到直線上分別向前后延長的距離;
在實際效果圖中(下方結果圖源程序用的原圖是lena
)袜茧,這個100偏移量菜拓,決定的就是這些生成直線的長度:
- 關于 Math.round()函數(shù)
- 關于 Imgproc.HoughLines() 與 Imgproc.HoughLinesP() 的 區(qū)別 以及 lines 參數(shù)位 的意義詳析
以上的這個API函數(shù)需要對得到的每對極坐標參數(shù)(r,θ)
做計算
笛厦,
使其變換
到平面空間
(x0 = r * cosθ ; y0 = r * sinθ
)纳鼎,
接著通過對x0
和y0
添加偏移量
并進行計算,得到直線的兩個點
裳凸;
然后繪制直線
贱鄙。
另外一個
API函數(shù)則比較簡單,
它省去了
開發(fā)者自己把極坐標變換為直線坐標的過程
姨谷,
直接返回
每個線段/直線對應的兩個點坐標
逗宁,
其API函數(shù)與參數(shù)的解釋具體如下:
-
HoughLinesP(Mat image, Mat lines, double rho, double theta, int threshold, double minLineLength, double maxLineGap)
image
:表示輸入圖像,8位單通道圖像梦湘,一般為二值圖像疙剑。
lines
:表示輸出的每個直線最終要繪制用
的兩個 平面坐標系參數(shù)
。
rho
:表示極坐標空間r值每次的步長践叠,一般設置為1言缤。
theta
:表示角度θ,每次移動1°即可禁灼。
threshold
:表示極坐標中該點的累積數(shù)管挟,該累積數(shù)越大,則得到的直線可能就越長弄捕,取值范圍通常為30~50僻孝,單位是像素,假設取值為30守谓,則表示大于30個像素長度的線段才會被檢測到穿铆。
minLineLength
:表示可以檢測的最小線段長度
,根據實際需要進行設置斋荞。
maxLineGap
:表示線段之間的最大間隔像素荞雏,假設5表示小于5個像素的兩個相鄰線段可以連接
起來。
使用該API實現(xiàn)圖像直線檢測:
private void houghLinePDemo(Mat src, Mat dst) {
Mat edges = new Mat();
Imgproc.Canny(src, edges, 50, 150, 3, true);
Mat lines = new Mat();
Imgproc.HoughLinesP(edges, lines, 1, Math.PI/180.0, 100, 50, 10);
Mat out = Mat.zeros(src.size(), src.type());
for(int i=0; i<lines.rows(); i++) {
int[] oneline = new int[4];
lines.get(i, 0, oneline);
Imgproc.line(out, new Point(oneline[0], oneline[1]),
new Point(oneline[2], oneline[3]),
new Scalar(0, 0, 255), 2, 8, 0);
}
out.copyTo(dst);
// 釋放內存
out.release();
edges.release();
}
- 這里需要注意的是,
圖像二值化
與邊緣檢測算法輸出結果
的質量
在很大程度上影響 霍夫直線變換
的結果
凤优,
同時在使用HoughLinesP
的時候悦陋,最后兩個參數(shù)
的設置
也會影響
霍夫直線檢測的結果。