本文要點總結(jié)(倆算法的聯(lián)系與區(qū)別)
Harris角點檢測與Shi-Tomasi角點檢測都是經(jīng)典的角點特征提取算法饰抒,
但兩者在API的使用上有出入(詳見文中代碼或GitHub項目)掠兄;
Harris角點檢測的API朱监,
返回/輸出
的是一個與輸入圖像大小一致的Mat對象
禽笑,
這個Mat對象
的每一個坐標(biāo)(i目代,j)
都是對應(yīng)輸入圖像對應(yīng)坐標(biāo)(i靴迫,j)
的像素
的響應(yīng)值R
,
要先將這個Mat對象
歸一化盐碱,
再循環(huán)每一個Mat數(shù)據(jù)元素
瘩例,一 一 跟自己設(shè)置的閾值
進行比較,
合格的再認(rèn)為是角點
并提取
出來甸各,
進行繪制和保存垛贤;與
Harris角點
輸出不同,shi-tomasi
簡單多了趣倾,
直接輸出一個包含若干個(具體個數(shù)通過API形參設(shè)置)角點坐標(biāo)的角點數(shù)組
聘惦,(其數(shù)據(jù)類型是MatOfPoint
)
省略了很多步驟;
遍歷
這個角點數(shù)組,
繪制出
每個角點
即可善绎。
引子
前面兩章筆記(
圖像操作黔漂、基本特征檢測
)
主要講述了OpenCV中圖像處理模塊的主要知識與API使用;本章的筆記記錄OpenCV中另外一個重要模塊——
feature2d模塊
禀酱,
該模塊的主要功能是檢測圖像的特征
炬守,
并根據(jù)特征進行對象匹配
;首先剂跟,關(guān)于
圖像的特征
减途,
簡單地說,特征就是邊緣曹洽、角點鳍置、紋理
等。本章會筆記
特征提取送淆、檢測與匹配
相關(guān)的知識與API税产,
包括角點特征檢測、特征點檢測偷崩、特征描述子提取
辟拷,
以及根據(jù)特征描述子去匹配、尋找特征對象
阐斜。本章知識會涉及較多的數(shù)學(xué)知識與公式衫冻,
我們可以閱讀一些與特征提取相關(guān)的數(shù)學(xué)知識
,
比如導(dǎo)數(shù)與微分智听、多項式與高斯公式曲線擬合羽杰,三角函數(shù),矩陣的特征值與特征向量的簡單計算
等基礎(chǔ)數(shù)學(xué)知識到推,
以更好地掌握本章知識以及各個API參數(shù)意義與用法考赛。
0 角點的定義與作用
基本特征檢測
一章中,學(xué)習(xí)了關(guān)于邊緣檢測
的知識莉测,
在圖像邊緣
中颜骤,有一些特殊的像素點值
得我們特別關(guān)注,
那就是圖像邊緣的角點
捣卤,
這些角點更能反映出圖像中對象的整體特征
忍抽,
基于角點周圍的像素塊生成特征描述子
可以更好地表述圖像特征數(shù)據(jù)
。
本文首先筆記如何提取圖像的角點特征董朝。
1 Harris角點檢測
關(guān)于角點特征提取最經(jīng)典
的算法之一就是Harris角點檢測
鸠项。
Harris角點檢測
的基本原理
是對圖像求導(dǎo)
,對每個像素點生成二階梯度圖像
子姜,
只是在卷積
核使用的時候需要使用高斯核
祟绊,
得到圖像X與Y方向的二階矩
,
基于它們就可以得到如下Hessian矩陣
:
求得最大兩個特征值 λ1 與 λ2
,可以得到如下 角點響應(yīng)值R
:
其中牧抽,系數(shù)K常見的取值范圍為0.02~0.04嘉熊。
每個像素點
有自己的一個響應(yīng)值R
,
也即有自己的一對特征值 λ1 與 λ2扬舒;全局像素則有多個R值阐肤;
根據(jù)M計算
可以得到特征值 λ1、λ2
讲坎,它們的值與角點的關(guān)系如下圖:
Harris角點檢測
的API:
-
cornerHarris(Mat src, Mat dst, int blockSize, int ksize, double k)
src
:單通道的8位或者浮點數(shù)圖像孕惜,用灰度圖像;
dst
:輸出的每個像素點的響應(yīng)值
衣赶,是CV_32F
類型诊赊,大小與輸入圖像一致厚满。
blockSize
:根據(jù)特征值與特征向量計算矩陣M的大小府瞄,常見取值為2
。
ksize Sobel
:算子梯度計算碘箍,常見取值為3
遵馆。
k
:系數(shù)大小,取值范圍為0.02~0.04
丰榴。
使用Harris角點檢測函數(shù)計算得到圖像角點的演示代碼如下:
private void harrisCornerDemo(Mat src, Mat dst) {
// 定義閾值T//初始化各種Mat對象
int threshold = 100;
Mat gray = new Mat();
Mat response = new Mat();
Mat response_norm = new Mat();
// 角點檢測
Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);//轉(zhuǎn)灰度;醯恕O乙丁U俦摺?茬浴P胶茫舶!
Imgproc.cornerHarris(gray, response, 2, 3, 0.04);
Core.normalize(response, response_norm, 0, 255, Core.NORM_MINMAX, CvType.CV_32F);//歸一化
// 繪制角點
dst.create(src.size(), src.type());
src.copyTo(dst);
float[] data = new float[1];//3婀 7孔省6犹痢T省>蹩浴!F偷恕O侍病!节值!
for(int j=0; j<response_norm.rows(); j++ )
{
for(int i=0; i<response_norm.cols(); i++ )
{
response_norm.get(j, i, data);
if((int)data[0] > 100)
{
Imgproc.circle(dst, new Point(i, j), 5, new Scalar(0, 0, 255),
2, 8, 0);
Log.i("Harris Corner", "find corner point……");
}
}
}
gray.release();
response.release();
}
response_norm
歸一化后的響應(yīng)值Mat對象- data[0]是某個響應(yīng)值徙硅;
>100
認(rèn)為其是一個較大的響應(yīng)值,
響應(yīng)值大于指定閾值T(這里是100)搞疗,則對應(yīng)的像素點被認(rèn)為是角點嗓蘑;float[] data = new float[1] //在這里,可能有人有疑問, 數(shù)組長度只有 1
get()
方法脐往,第三個參數(shù)要求是數(shù)組休吠,
get多個像素時,傳入一個多元素空數(shù)組业簿,常規(guī)理解操作瘤礁;
但當(dāng)只要get一個像素,則需創(chuàng)建一個只有一個元素的數(shù)組
梅尤!而非變量
柜思!
這種接口設(shè)計思想
,
一個方法(如get()
)接口即可實現(xiàn)包含一到多個數(shù)據(jù)元素的形式參數(shù)的傳入巷燥;
而沒必要去準(zhǔn)備/重載
兩個方法——
一個用來接收包含單個數(shù)據(jù)元素的變量型形參
赡盘,
另一個用來接收包含多個數(shù)據(jù)元素的數(shù)組型形參
;沒必要這樣了缰揪;
即無論是負(fù)責(zé)接收數(shù)據(jù)的形參是包含 單個數(shù)據(jù)元素 還是 多個數(shù)據(jù)元素 陨享,一律按 數(shù)組型形參 處理,把數(shù)據(jù)形參位定義成數(shù)組類型钝腺,接口統(tǒng)一設(shè)計抛姑,一套代碼,一個接口即可艳狐,省時省力定硝!
- 上述程序首先把彩色RGB圖像轉(zhuǎn)換為單通道灰度圖像,
然后使用Harris角點檢測函數(shù)完成各個像素點上角點響應(yīng)值的計算毫目,
最后使用閾值過濾繪制那些響應(yīng)值R比較大的像素點(角點)蔬啡。
注意,閾值T與繪制檢測得到的角點數(shù)目相關(guān)镀虐,
T值越大箱蟆,被過濾的響應(yīng)像素點越多,留下來的就越可能是角點
粉私,反之亦然顽腾。
本章完整代碼在文末GitHub里邊的Feature2dMainActivity.java文件中
,后續(xù)對此不再說明诺核。
2 Shi-Tomasi角點檢測
還有一種經(jīng)常使用的角點檢測方法稱為
Shi-Tomasi角點檢測
抄肖,
其與Harris角點檢測類似,這種方法同樣是基于梯度圖像
發(fā)展而來的窖杀,
它是1994年由兩位作者Jianbo Shi與Carlo Tomasi一起提出來的漓摩,
他們當(dāng)時所發(fā)表的論文名為<<Good Feature to Track>>,
這也是為什么在OpenCV中使用同名函數(shù)來表示Shi-Tomasi角點檢測的原因入客。
Shi-Tomasi角點檢測與Harris角點檢測唯一(指的是方法邏輯管毙,不包括API腿椎,API的輸出還不同) 不同的地方
在于計算角點響應(yīng)R值
時使用的是如下方法:
如果R大于指定閾值T,則對應(yīng)的像素點被認(rèn)為是角點夭咬;
假設(shè)λ1啃炸、λ2
為坐標(biāo),
則對角點
的描述就是當(dāng)λ1卓舵、λ2都大于閾值T=λmin的右上角時
南用,
角點響應(yīng)值滿足要求的區(qū)域,
如下圖:
相關(guān)的API如下:
-
goodFeaturesToTrack(Mat image, MatOfPoint corners, int maxCorners, double qualityLevel, double minDistance, Mat mask, int blockSize, boolean useHarrisDetector, double k)
image
:表示輸入圖像掏湾、類型為單通道的8位或浮點數(shù)裹虫,用灰度圖像
;
corners
:輸出得到角點數(shù)組融击,注意數(shù)據(jù)類型
筑公;
maxCorners
:表示獲取前N個
最強響應(yīng)R值的角點。
qualityLevel
:其取值范圍為0~1尊浪,這里取它與最大R值
相乘匣屡,得到的值作為閾值T
,低于它的都要被丟棄际长,
假設(shè)Rmax=1500耸采,qualityLevel=0.01兴泥,則閾值T=15工育,小于15的角點都會被丟棄。
每個像素點有自己的一個響應(yīng)值R搓彻,去全局像素最大的R為Rmax如绸;
minDistance
:最終返回的角點
之間的最小距離,小于這個距離則的角點
被丟棄旭贬。
mask
:默認(rèn)全部為零怔接。
blockSize
:計算矩陣M時需要的,常取值為3稀轨。
useHarrisDetector
:是否使用Harris角點檢測扼脐,true表示使用,若為false則使用Shi-Tomasi角點檢測奋刽。
k
:當(dāng)使用Harris角點檢測的時候才使用瓦侮。
實現(xiàn)shi-tomasi角點檢測的demo:
private void shiTomasicornerDemo(Mat src, Mat dst) {
// 變量定義
double k = 0.04;
int blockSize = 3;
double qualityLevel= 0.01;
boolean useHarrisCorner = false;
// 角點檢測
Mat gray = new Mat();
Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);
MatOfPoint corners = new MatOfPoint();
Imgproc.goodFeaturesToTrack(gray, corners, 100, qualityLevel, 10, new Mat(), blockSize, useHarrisCorner, k);
// 繪制角點
dst.create(src.size(), src.type());
src.copyTo(dst);
Point[] points = corners.toArray();
for(int i=0; i<points.length; i++) {
Imgproc.circle(dst, points[i], 5, new Scalar(0, 0, 255), 2, 8, 0);
}
gray.release();
}
完整的代碼可參考GitHub項目。
參考材料
- 《OpenCV Android 開發(fā)實戰(zhàn)》(賈志剛 著)
- 關(guān)于《OpenCV Android 開發(fā)實戰(zhàn)》作者的GitHub項目
- 筆者基于作者GitHub維護的APP