OpenCV角点检测: Harris算子, ShiTomasi算子

角点检测

角点的特征检测与匹配是Computer Vision 应用总重要的一部分,这需要寻找图像之间的特征建立对应关系。点,也就是图像中的特殊位置,是很常用的一类特征,点的局部特征也可以叫做“关键特征点”(keypoint feature),或“兴趣点”(interest point),或“角点”(conrner)。

关于角点的具体描述可以有几种:

一阶导数(即灰度的梯度)的局部最大所对应的像素点;
两条及两条以上边缘的交点;
图像中梯度值和梯度方向的变化速率都很高的点;
角点处的一阶导数最大,二阶导数为零,指示物体边缘变化不连续的方向。

Harris算子和ShiTomasi算子

Harris角点检测推导:https://blog.csdn.net/lql0716/article/details/52628959

角点检测的Harris算子和ShiTomasi算子非常好的解释:https://blog.csdn.net/xiaowei_cqu/article/details/7805206

  • Harris算子

OpenCV中定义了 cornerHarris 函数:

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

可以结合 convertScaleAbs 函数,通过阈值取角点。

  • Shi-Tomasi算子

由于Shi-Tomasi算子与1994年在文章 Good Features to Track [1]中提出,OpenCV 实现的算法的函数名定义为 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.04 );

代码例子

编译环境: Qt 5.5.1+opencv3.2.0+cmake3.5.1


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


using namespace cv;
using namespace std;

Mat image, image_gray;

int thresh = 200;
int max_thresh = 255;

char* source_window = "Source image";
char* corners_window = "Harris Courners detected";

int maxCorners = 23;
int maxTrackbar = 100;

RNG rng(12345);

Mat myHarris_dst;
Mat myHarris_copy;
Mat Mc;
Mat myShiTomasi_dst;
Mat myShiTomasi_copy;


int myShiTomasi_qualityLevel = 50;
int myHarris_qualityLevel = 50;
int max_qualityLevel = 100;

double myHarris_minVal;
double myHarris_maxVal;
double myShiTomasi_minVal;
double myShiTomasi_maxVal;

const char* myHarris_window = "my harris corner detector";
const char* myShiTomasi_window = "my Shi Tomasi corner detector";

// Function header
void cornerHarris_demo(int, void*);
void goodFeaturesToTrack_demo(int, void*);
void myShiTomasi_function(int, void*);
void myHarris_function(int, void*);

int main(int argc, char** argv)
{

    image = imread(argv[1],1);
    if(image.empty())
        return 0;
    cvtColor(image, image_gray, COLOR_BGR2GRAY);

    int blockSize = 3;
    int apertureSize = 3;

    // my harris matrix -- usin cornerEigenValsAndVecs
    myHarris_dst = Mat::zeros(image_gray.size(), CV_32FC(6));
    Mc = Mat::zeros(image_gray.size(), CV_32FC1);

    cornerEigenValsAndVecs(image_gray, myHarris_dst, blockSize, apertureSize, BORDER_DEFAULT);

    /* calculate Mc */
    for( int j=0; j<image_gray.rows; j++)
    {
        for(int i=0; i<image_gray.cols; i++)
        {
            float lambda_1 = myHarris_dst.at<Vec6f>(j,i)[0];
            float lambda_2 = myHarris_dst.at<Vec6f>(j,i)[1];
            Mc.at<float>(j,i) = lambda_1*lambda_2-0.04f*pow((lambda_1+lambda_2),2);

        }
    }

    minMaxLoc(Mc, &myHarris_minVal, &myHarris_maxVal, 0, 0, Mat());

    // create window and trackbar
    namedWindow( myHarris_window, WINDOW_AUTOSIZE);
    createTrackbar("Quality Level:", myHarris_window, &myHarris_qualityLevel, max_qualityLevel, myShiTomasi_function);
    myHarris_function(0,0);
    /// My Shi-Tomasi -- Using cornerMinEigenVal
    myShiTomasi_dst = Mat::zeros( image_gray.size(), CV_32FC1 );
    cornerMinEigenVal( image_gray, myShiTomasi_dst, blockSize, apertureSize, BORDER_DEFAULT );

    minMaxLoc( myShiTomasi_dst, &myShiTomasi_minVal, &myShiTomasi_maxVal, 0, 0, Mat() );

    /* Create Window and Trackbar */
    namedWindow( myShiTomasi_window, WINDOW_AUTOSIZE );
    createTrackbar( " Quality Level:", myShiTomasi_window, &myShiTomasi_qualityLevel, max_qualityLevel, myShiTomasi_function );
    myShiTomasi_function( 0, 0 ) ;

    // create window
    namedWindow(source_window, WINDOW_AUTOSIZE);
    createTrackbar("Threshold:", source_window, &thresh, max_thresh, cornerHarris_demo);
    createTrackbar("Max corners:", source_window, &maxCorners, maxTrackbar, goodFeaturesToTrack_demo);

    imshow(source_window, image);

    cornerHarris_demo(0,0);
    goodFeaturesToTrack_demo(0,0);

    waitKey(10000);

    return (0);
}

void cornerHarris_demo(int, void*)
{
    Mat dst, dst_norm, dst_norm_scaled;
    dst = Mat::zeros(image.size(), CV_32FC1);

    int blockSize = 2;
    int apertureSize = 3;
    double k = 0.04;

    //detecting corners
    cornerHarris(image_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT);

    //normalizing
    normalize(dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
    convertScaleAbs(dst_norm, dst_norm_scaled);

    //draw a circle
    for(int j=0; j<dst_norm.rows; j++)
    {
        for(int i = 0; i < dst_norm.cols; i++)
        {
            if((int)dst_norm.at<float>(j,i) > thresh)
            {
                circle(dst_norm_scaled, Point(i,j), 5, Scalar(0), 2, 8, 0);
            }
        }

    }
    namedWindow(corners_window, WINDOW_AUTOSIZE);
    imshow(corners_window, dst_norm_scaled);

}

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

    /// parameters for 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 = image.clone();

    // apply corner detection
    goodFeaturesToTrack(image_gray,
                        corners,
                        maxCorners,
                        qualityLevel,
                        minDistance,
                        Mat(),
                        blockSize,
                        useHarrisDetector,
                        k);

    // draw corners detected
    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);
    }

    // show
    namedWindow(source_window, WINDOW_AUTOSIZE);
    imshow(source_window, copy);

}


void myShiTomasi_function(int, void *)
{
    myShiTomasi_copy = image.clone();

    for( int j=0; j<image_gray.rows; j++ )
    {
        for( int i = 0; i<image_gray.cols; i++ )
        {
            if( myShiTomasi_dst.at<float>(j,i) > myShiTomasi_minVal+(myShiTomasi_maxVal-myShiTomasi_minVal)*myShiTomasi_qualityLevel/max_qualityLevel)
            {
                circle(myShiTomasi_copy, Point(i,j), 4, Scalar(rng.uniform(0,255), rng.uniform(0,255), rng.uniform(0,255)), -1, 8, 0);
            }

        }

    }
    imshow(myShiTomasi_window, myShiTomasi_copy);

}

void myHarris_function(int, void *)
{
    myHarris_copy = image.clone();

    if( myHarris_qualityLevel < 1){
        myHarris_qualityLevel = 1;
    }

    for( int j=0; j<image_gray.rows; j++)
    {
        for(int i=0; i<image_gray.cols; i++)
        {
            if(Mc.at<float>(j,i) > myHarris_minVal+(myHarris_maxVal-myHarris_minVal)*myHarris_qualityLevel/max_qualityLevel)
            {
                circle( myHarris_copy, Point(i,j), 4, Scalar(rng.uniform(0,255), rng.uniform(0,255), rng.uniform(0,255)), -1, 8, 0);
            }

        }

    }
    imshow( myHarris_window, myHarris_copy);
}

参考及更多阅读

openCV高斯模糊、边缘检测、灰度化、二值化、闭运算、绘制边缘
https://cloud.tencent.com/developer/article/1106887

角点检测的数学原理: https://www.cnblogs.com/riddick/p/7645904.html

发布了111 篇原创文章 · 获赞 118 · 访问量 28万+

猜你喜欢

转载自blog.csdn.net/happyhorizion/article/details/100781482