OpenCV探索之路(十五):角點檢測

weixin_34162629發表於2017-05-24

角點檢測是計算機視覺系統中用來獲取影象特徵的一種方法。我們都常說,這幅影象很有特點,但是一問他到底有哪些特點,或者這幅圖有哪些特徵可以讓你一下子就識別出該物體,你可能就說不出來了。其實說影象的特徵,你可以嘗試說一下這幅圖有幾個矩形啊幾個圓形啊,有幾條直線啊,當然啦,你也可以說一下有幾個角點。

什麼是角點?

角點通常被定義為兩條邊的交點。比如,三角形有三個角,矩形有四個角,這些就是角點,也是他們叫做矩形、三角形的特徵,我們看到一些幾何圖形具有三個角,那麼我們便可以脫口而出說這是一個三角形。

上面所說的是嚴格意義上的角點,但是從廣義來說,角點指的是擁有特定特徵的影象點,這些特徵點在影象中有具體的座標,並具有某些數學特徵(比如區域性最大或最小的灰度)。

影象特徵型別可以被分為三種:

  • 邊緣
  • 角點(感興趣關鍵點)
  • 斑點(感興趣區域)

角點是個很特殊的存在。如果某一點在任意方向的一個微小的變動都會引起灰度很大的變化,那麼我們就可以把該點看做是角點。

Harris 角點檢測

Harris角點檢測是一種直接基於灰度圖的角點提取演算法,穩定性高,尤其對L型角點(也就是直角)檢測精度高。缺點也是明顯的,就是運算速度慢。

OpenCV使用的相應函式是

void cornerHarris( InputArray src, OutputArray dst, int blockSize,int ksize,
                    double k, int borderType = BORDER_DEFAULT );

下面給出相應的檢測程式碼。

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

using namespace cv;
using namespace std;
 

Mat g_srcImage, g_srcImage1, g_grayImage;
int thresh = 30; //當前閾值  
int max_thresh = 175; //最大閾值  

void on_CornerHarris(int, void*);//回撥函式  

int main(int argc, char** argv)
{
    g_srcImage = imread("lol19.jpg", 1);
    if (!g_srcImage.data)
    {
        printf("讀取圖片錯誤! \n");
        return -1;
    }
    imshow("原始圖", g_srcImage);
    g_srcImage1 = g_srcImage.clone();

    //存留一張灰度圖  
    cvtColor(g_srcImage1, g_grayImage, CV_BGR2GRAY);

    //建立視窗和滾動條  
    namedWindow("角點檢測", CV_WINDOW_AUTOSIZE);
    createTrackbar("閾值: ", "角點檢測", &thresh, max_thresh, 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();

    //進行角點檢測  
    //第三個參數列示鄰域大小,第四個參數列示Sobel運算元孔徑大小,第五個參數列示Harris引數
    cornerHarris(g_grayImage, dstImage, 2, 3, 0.04, BORDER_DEFAULT);

    // 歸一化與轉換  
    normalize(dstImage, normImage, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
    convertScaleAbs(normImage, scaledImage);//將歸一化後的圖線性變換成8位無符號整型   

    // 將檢測到的,且符合閾值條件的角點繪製出來  
    for (int j = 0; j < normImage.rows; j++)
    {
        for (int i = 0; i < normImage.cols; i++)
        {
            //Mat::at<float>(j,i)獲取畫素值,並與閾值比較
            if ((int)normImage.at<float>(j, i) > thresh + 80)
            {
                circle(g_srcImage1, Point(i, j), 5, Scalar(10, 10, 255), 2, 8, 0);
                circle(scaledImage, Point(i, j), 5, Scalar(0, 10, 255), 2, 8, 0);
            }
        }
    }
    
    imshow("角點檢測", g_srcImage1);
    imshow("角點檢測2", scaledImage);

}

先看看原始圖
1093303-20170524162644138-1515209896.png

開始檢測,我把閾值設為30,檢測到角點還挺多的。
1093303-20170524162726919-137981424.png

我把閾值進一步提高,角點變少了。認真觀察一下,是不是檢測到的點都是一些亮度明顯變化的臨界點?比如由黑變白的邊界點。
1093303-20170524162741029-214621823.png

Shi-Tomasi角點檢測

除了上述的Harris角點檢測方法,我們還可以採用Shi-Tomasi方法進行角點檢測。Shi-Tomsi演算法是Harris演算法的加強版,效能當然也有相應的提高。

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace cv;
using namespace std;

Mat src, src_gray;

int maxCorners = 23;
int maxTrackbar = 100;

RNG rng(12345);  //RNG:random number generator,隨機數產生器
char* source_window = "Image";

void goodFeaturesToTrack_Demo(int, void*);

int main()
{
    //轉化為灰度圖
    src = imread("lol19.jpg", 1);
    cvtColor(src, src_gray, CV_BGR2GRAY);

    namedWindow(source_window, CV_WINDOW_AUTOSIZE);

    //建立trackbar
    createTrackbar("MaxCorners:", source_window, &maxCorners, maxTrackbar, goodFeaturesToTrack_Demo);

    imshow(source_window, src);

    goodFeaturesToTrack_Demo(0, 0);

    waitKey(0);
    return(0);
}

void goodFeaturesToTrack_Demo(int, void*)
{
    if (maxCorners < 1) { maxCorners = 1; }

    //初始化 Shi-Tomasi algorithm的一些引數
    vector<Point2f> corners;
    double qualityLevel = 0.01;
    double minDistance = 10;
    int blockSize = 3;
    bool useHarrisDetector = false;
    double k = 0.04;

    //給原圖做一次備份
    Mat copy;
    copy = src.clone();

    // 角點檢測
    goodFeaturesToTrack(src_gray,corners,maxCorners,qualityLevel,minDistance,Mat(),blockSize,useHarrisDetector,k);

    //畫出檢測到的角點
    cout << "** Number of corners detected: " << corners.size() << endl;
    int r = 4;
    for (int i = 0; i < corners.size(); i++)
    {
        circle(copy, corners[i], r, Scalar(rng.uniform(0, 255), rng.uniform(0, 255),
            rng.uniform(0, 255)), -1, 8, 0);
    }

    namedWindow(source_window, CV_WINDOW_AUTOSIZE);
    imshow(source_window, copy);
}

1093303-20170524162811575-274826897.png

1093303-20170524162841107-1439635947.png

相關文章