Opencv學習之角點檢測

Opencv學習之角點檢測

角點檢測

在圖像處理和計算機視覺領域,興趣點(interest points),也被稱作關鍵點(key points)、特徵點(feture points)。它被大量用於解決物體識別、圖像識別、圖像匹配、視覺跟蹤、三維重建等一系列的問題,如果能檢測到足夠多特殊的點,同時它們的區分度很高,並且可以精確定位穩定的特徵,那麼這個方法就具有使用價值。
圖像特徵類型被分爲以下三種:
(1)邊緣
(2)角點(感興趣關鍵點):如果某一點在任意方向的一個微小變動都會引起灰度很大的變化。
(3)斑點(Blobs)(感興趣區域)
關於角點的具體描述:
*一階導數(灰度的梯度)的局部最大所對應的像素點。
*兩條及兩條以上邊緣的交點。
*圖像中梯度值和梯度方向的變化速率都很高的點。
*角點處的一階導數最大,二階導數爲零,它指示了物體邊緣變化不連續的方向。
目前圖像處理領域角點檢測算法歸納:
*基於灰度圖像的角點檢測(又分爲,基於梯度、基於模板(圖像亮度的變化,將鄰點亮度對比足夠大的點定義爲角點)、基於模板梯度組合三類方法)
*基於二值圖像的角點檢測
*基於輪廓曲線的角點檢測

Harris角點檢測–cornerHarris函數

Harris角點檢測是一種直接基於灰度圖像的角點提取算法,穩定性高,尤其對L型角點檢測精度高。但由於採用了高斯濾波,運算速度相對較慢,角點信息有丟失和位置偏移的現象,而且角點提取有聚簇現象。
void cornerHarris(inputArray src,outputArray dst,int blockSize,int ksize,double k, int borderType=BORDER_DEFAULT)
*第一個參數,輸入圖像,須爲單通道8位或者浮點型圖像。
*第二個參數,用於存放Harris角點檢測的輸出結果,和源圖像有一樣的尺寸和類型。
*第三個參數,表示鄰域的大小。
*第四個參數,表示Sobel()算子的孔徑大小。
*第五個參數,Harris焦點響應函數中的參數。
*第六個參數,圖像像素的邊界模式,默認值BORDER_DEFAULT。

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>

using namespace cv;

//宏定義部分
#define WINDOW_NAME1 "image[procedure window1]"
#define WINDOW_NAME2 "image[procedure window2]"

//全局變量聲明
Mat g_srcImage,g_srcImage1,g_grayImage;
int g_nThresh=30;//當前閾值
int g_nThresh_max=175;//最大閾值

//全局函數聲明
void on_CornerHarris(int ,void *);//回調函數

//主函數
int main()
{
    //載入源圖像顯示並進行克隆保存
    g_srcImage=imread("/Users/new/Desktop/2.jpg");
    if(!g_srcImage.data){printf("讀取源圖像srcImage錯誤~!\n");return false;}
    imshow(WINDOW_NAME1, g_srcImage);
    g_srcImage1=g_srcImage.clone();

    //轉換爲灰度圖像
    cvtColor(g_srcImage1, g_grayImage, COLOR_BGR2GRAY);

    //創建窗口和閾值滑動條
    namedWindow(WINDOW_NAME1);
    createTrackbar("threshold: ", WINDOW_NAME1, &g_nThresh, g_nThresh_max,on_CornerHarris);
    on_CornerHarris(0, 0);

    waitKey(0);
    return 0;

}

//回調函數定義
void on_CornerHarris(int ,void *)
{
    //定義一些局部變量
    Mat dstImage;//目標圖
    Mat normImage;//歸一化後圖
    Mat scaledImage;//線性變換後的八位無符號整型的圖

    //初始化
    //置零當前需要顯示的兩幅圖,即清除上一次調用此函數時他們的值
    dstImage=Mat::zeros(g_srcImage.size(), CV_32FC1);
    g_srcImage1=g_srcImage.clone();

    //正式檢測
    //進行角點檢測
    cornerHarris(g_grayImage, dstImage, 2, 3, 0.04);
    //歸一化
    normalize(dstImage, normImage,0,255,NORM_MINMAX,CV_32FC1,Mat());
    //將歸一化後的圖線性變換成8位無符號整型
    convertScaleAbs(normImage, scaledImage);

    //進行繪製
    for(int j=0;j<normImage.rows;j++)
        for(int i=0;i<normImage.cols;++i)
        {
            if((int)normImage.at<float>(j,i)>g_nThresh+80)
            {
                circle(g_srcImage1, Point(i,j), 3, Scalar(10,10,255),2,8,0);
                circle(scaledImage, Point(i,j), 3, Scalar(10,10,255),2,8,0);
            }
        }
    //顯示最終結果
    imshow(WINDOW_NAME1,g_srcImage1);
    imshow(WINDOW_NAME2,scaledImage);
}

這裏寫圖片描述

Shi-Tomasi角點檢測–goodFeaturesToTrack函數

Shi-Tomasi算法是Harris算法的改進,此算法最原始的定義是將矩陣M的行列式與M的跡相減,再將差值同預先給定的閾值進行比較,後來Shi和Tomasi提出了改進方法,若兩個特徵值中較小的一個大於最小的閾值的話,則會得到強角點。
goodFeaturesToTrack函數就是確定圖像強角點的函數。
void goodFeaturesToTrack(inputArray image,outputArray corners,int maxCorners,double qualityLevel,double minDistance,inputArray mask=noArray(),int blockSize=3,bool useHarrisDetector=false,double k=0.4)
*第一個參數,輸入圖像,須爲8位或浮點型32位單通道圖像。
*第二個參數,檢測到的角點的輸出向量。
*第三個參數,角點的最大數量。
*第四個參數,角點檢測可接受的最小特徵值。其實實際用於過濾角點的最小特徵值時qualityLevel與圖像中最大特徵值的乘積。所以qualityLevel通常不會超過1(常用的值爲0.10或者0.01),而檢測完所有的角點後,還要進一步剔除掉一些距離較近的角點。
*第五個參數,角點之間的最小距離,此參數用於保證返回的角點之間的距離不小於此參數個像素。
*第六個參數,可選參數,表示感興趣區域,默認值noArray(),若此參數非空(需爲CV_8UC1類型,且和第一個參數image有相同的尺寸),便用於指定角點檢測區域。
*第七個參數,默認值3,是計算導數自相關矩陣時指定的鄰域範圍。
*第八個參數,默認值false,只是是否使用Harris角點檢測。
*第九個參數,默認值0.04,爲用於設置Hessian自相關矩陣行列式的相對權重的權重係數。
另外值得一提,goodFeaturesToTrack函數可以用來初始化一個基於點的對象跟蹤操作。

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>

using namespace cv;
using namespace std;

//宏定義部分
#define WINDOW_NAME1 "image[Shi-Tomasi corner dtector]"


//全局變量聲明
Mat g_srcImage,g_grayImage;
int g_maxCornerNumber=33;
int g_maxTrackbarNumber=500;
RNG g_rng(12345);

//全局函數聲明
void on_GoodFeaturesToTrack(int ,void *);//回調函數

//主函數
int main()
{
   //載入源圖像並將其轉換爲灰度圖
    g_srcImage=imread("/Users/new/Desktop/2.jpg");
    if(!g_srcImage.data){printf("讀取源圖像srcImage錯誤~!\n");return false;}
    cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
    //創建窗口和滑動條
    namedWindow(WINDOW_NAME1);
    createTrackbar("max corners_num: ", WINDOW_NAME1, &g_maxCornerNumber, g_maxTrackbarNumber,on_GoodFeaturesToTrack);
    imshow(WINDOW_NAME1,g_srcImage);
    on_GoodFeaturesToTrack(0, 0);

    waitKey(0);
    return 0;

}

//回調函數定義
void on_GoodFeaturesToTrack(int ,void *)
{
    //對變量小於等於1時的處理
    if(g_maxCornerNumber<=1){g_maxCornerNumber=1;}

    //Shi-Tomasi算法的參數準備
    vector<Point2f>corners;
    double qualityLevel=0.01;//角點檢測可接受的最小特徵
    double minDistance=10;//角點之間的最小距離
    int blockSize=3;//計算導數自相關矩陣時指定的鄰域範圍
    double k=0.04;//權重係數
    Mat copy=g_srcImage.clone();//複製源圖像到一個臨時變量中,作爲感興趣區域

    //進行Shi-Tomasi角點檢測
    goodFeaturesToTrack(g_grayImage, corners, g_maxCornerNumber, qualityLevel, minDistance,Mat(),blockSize,false,k);

    //輸出文字信息
    cout<<">此次檢測到的角點數量爲:"<<corners.size()<<endl;
    //繪製檢測到的角點
    int r=4;
    for(unsigned int i=0;i<corners.size();++i)
    {
    //以隨機顏色繪製角點
        circle(copy, corners[i], r, Scalar(g_rng.uniform(0, 255),g_rng.uniform(0, 255),g_rng.uniform(0, 255)),-1,8,0);

    }
    imshow(WINDOW_NAME1, copy);

}

這裏寫圖片描述

亞像素級角點檢測–cornerSubPix函數

若進行圖像處理的目的不是提取用於識別的特徵點而是進行幾何測量,這通常需要更高的精度,而函數goodFeaturesToTrack函數只能提供簡單的像素的座標值,也就是說,有時候會需要實數座標值而不是整數座標值。
亞像素級角點檢測的位置在攝像機標定、跟蹤並重建攝像機的軌跡,或者重建被跟蹤目標的三維結構時,是一個基本的測量值。
cornerSubPix函數用於尋找亞像素角點位置(不是整數類型的位置,而是更精確的浮點類型的位置)。
void cornerSubPix(inputArray image,inputoutputArray corners,Size winSize,Size zeroZone,TermCriteria criteria)
*第一個參數,輸入圖像。
*第二個參數,提供輸入角點的初始座標和精確的輸出座標。
第三個參數,搜索窗口的一半尺寸,若winSize=Size(5,5),那麼就表示使用(5*2+1)(5*2+1)=11x11大小的搜索窗口。
*第四個參數,表示死區的一半尺寸,而死區爲不對搜索區的中央位置做求和運算的區域,用來避免自相關矩陣出現的某些可能的奇異性。值(-1,-1)表示沒有死區。
*第五個參數,求角點的迭代過程的終止條件,即角點位置的確定,要麼迭代數大於某個設定值,或者是精確度達到某個設定值,criteria可以是最大迭代數目,或者是設定的精確度,也可以是它們的組合。

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>

using namespace cv;
using namespace std;

//宏定義部分
#define WINDOW_NAME1 "image[Shi-Tomasi corner dtector]"


//全局變量聲明
Mat g_srcImage,g_grayImage;
int g_maxCornerNumber=33;
int g_maxTrackbarNumber=500;
RNG g_rng(12345);

//全局函數聲明
void on_GoodFeaturesToTrack(int ,void *);//回調函數

//主函數
int main()
{
   //載入源圖像並將其轉換爲灰度圖
    g_srcImage=imread("/Users/new/Desktop/2.jpg");
    if(!g_srcImage.data){printf("讀取源圖像srcImage錯誤~!\n");return false;}
    cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
    //創建窗口和滑動條
    namedWindow(WINDOW_NAME1);
    createTrackbar("max corners_num: ", WINDOW_NAME1, &g_maxCornerNumber, g_maxTrackbarNumber,on_GoodFeaturesToTrack);
    imshow(WINDOW_NAME1,g_srcImage);
    on_GoodFeaturesToTrack(0, 0);

    waitKey(0);
    return 0;

}

//回調函數定義
void on_GoodFeaturesToTrack(int ,void *)
{
    //對變量小於等於1時的處理
    if(g_maxCornerNumber<=1){g_maxCornerNumber=1;}

    //Shi-Tomasi算法的參數準備
    vector<Point2f>corners;
    double qualityLevel=0.01;//角點檢測可接受的最小特徵
    double minDistance=10;//角點之間的最小距離
    int blockSize=3;//計算導數自相關矩陣時指定的鄰域範圍
    double k=0.04;//權重係數
    Mat copy=g_srcImage.clone();//複製源圖像到一個臨時變量中,作爲感興趣區域

    //進行Shi-Tomasi角點檢測
    goodFeaturesToTrack(g_grayImage, corners, g_maxCornerNumber, qualityLevel, minDistance,Mat(),blockSize,false,k);

    //輸出文字信息
    cout<<">此次檢測到的角點數量爲:"<<corners.size()<<endl;

    //亞像素角點檢測的參數設置
    Size winSize=Size(5,5);
    Size zeroZone=Size(-1,-1);
    TermCriteria criteria=TermCriteria(TermCriteria::EPS+TermCriteria::MAX_ITER,400, 0.001);

    //計算出亞像素點角點位置
    cornerSubPix(g_grayImage, corners, winSize, zeroZone, criteria);

    //輸出角點信息
    for(int i=0;i<corners.size();++i)
    {
        cout<<"\t精確角點座標["<<i<<"]("<<corners[i].x<<","<<corners[i].y<<")"<<endl;
    }
    //繪製檢測到的角點
    int r=4;
    for(unsigned int i=0;i<corners.size();++i)
    {
        //以隨機顏色繪製角點
        circle(copy, corners[i], r, Scalar(g_rng.uniform(0, 255),g_rng.uniform(0, 255),g_rng.uniform(0, 255)),-1,8,0);

    }
    imshow(WINDOW_NAME1, copy);

}

這裏寫圖片描述

Opencv技巧

(1) //將歸一化後的圖線性變換成8位無符號整型

 convertScaleAbs(normImage, scaledImage);
(2)定義角點的迭代過程的終止條件:
TermCriteria       criteria=TermCriteria(TermCriteria::EPS+TermCriteria::MAX_ITER,400, 0.001);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章