1. 程式人生 > >Opencv3筆記31——Harris角點檢測

Opencv3筆記31——Harris角點檢測

1. 興趣點和角點

在影象處理和計算機視覺領域,興趣點,也被稱為關鍵點、特徵點。被用於解決物體識別和影象識別,影象匹配、視覺跟蹤、三維建模等一系列的問題。
影象特徵型別被分為三種:
1. 邊緣
2. 角點(感興趣關鍵點)
3. 斑點(Blobs)感興趣區域
角點是個很特殊的存在。如果某一點在任意方向的一個微小變動都會引起灰度很大的變化,我們稱之為角點。角點作為影象上的特徵點,包含重要的資訊,在影象融合和目標跟蹤及三維重建中有重要的應用價值。因為角點位於兩條邊緣的交點處,代表了兩個邊緣變換的方向上的點,所以它們精確的定位二維特徵。

關於角點的具體描述有以下幾種。

  • 一階導數:灰度的梯度,區域性最大所對應的畫素點
  • 兩條及兩條以上邊緣的交點
  • 影象中梯度值和梯度方向的變化速率都很高的點
  • 角點處的一階導數最大,二階導數為0,指示了物體邊緣變換不連續的方向

2 角點檢測

現有的角點檢測演算法並不是都十分的健壯。很多的方法都要求有大量的訓練集和冗餘資料來防止和減少錯誤特徵的出現。
角點檢測方法的一個很重要的評價標準是其多幅影象中相同或相似特徵的檢測能力,並且能夠應對光照變化、影象旋轉等影象變化。

演算法歸類

  • 基於灰度影象角點檢測
  • 基於二值影象的角點檢測
  • 基於輪廓曲線的角點檢測

基於灰度影象的角點檢測又可分為基於梯度、基於模板和基於模板梯度組合三類方法。
基於模板的方法主要考慮畫素鄰域點的灰度變化、即影象亮度的變化將與領點亮度對比最夠大的店定義為角點。
基於模板的角點檢測演算法有kitchen-Rosenfeld角點檢測演算法,Harris角點檢測演算法、KLT檢點檢測演算法及SUSAN角點檢測演算法。

3. harris角點檢測

harris角點檢測時一種直接基於灰度影象的角點提取演算法,穩定性高,尤其對於L型角點檢測精度高。但是由於採用了高斯濾波,運算速度相對比較的慢,角點資訊有丟失和位置偏移的現象,而且角點提取有聚簇現象。

4. 實現harris角點檢測:cornerHarris()函式

cornerHarris函式和cornerMinEigenVal()以及cornerEigenValsAndVecs()函式類似。cornerHarris函式對於每一個畫素(x,y)blockSize×blockSize鄰域內,計算

2×2梯度的協方差矩陣M(x,y),接著計算如下:

dst(x,y)=detM(x,y)k(trM(x,y))2
就可以找出輸出圖中的區域性最大值,找出了角點。
函式原型:
void cornerHarris(InputArray src,OutputArray dst,int blockSize,int ksize,double k, intborderType = BORDER_DEFAULT)
  • 第三個引數:int型別的blockSize,表示領域的大小
  • 第四個引數:int型別的ksize,表示Sobel()運算元的孔徑大小
  • 第五個引數:double 型別的k,Harris引數
  • 第六個引數:int型別的borderType,影象畫素的邊界模式,預設值為BORDER_DEFAULT

5.cornerHarris程式例項

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

using namespace cv;

int main()
{
    //灰度的方式讀入影象
    Mat srcImage = imread("1.jpg", 0);
    imshow("原始圖", srcImage);

    //進行Harris角點檢測找出角點
    Mat cornerStrength;
    cornerHarris(srcImage, cornerStrength, 2, 3, 0.01);

    //對灰度影象進行閾值操作
    Mat harrisCorner;
    threshold(cornerStrength, harrisCorner, 0.00001, 255, THRESH_BINARY);
    imshow("角點檢測後的二值效果圖", harrisCorner);
    waitKey(0);
    return 0;
}

這裡寫圖片描述

這裡寫圖片描述

6. Harris角點檢測與繪製

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

using namespace cv;

//定義巨集
#define WINDOW_NAME1 "【程式視窗1】"
#define WINDOW_NAME2 "【程式視窗2】"

//全域性變數宣告
Mat g_srcImage, g_srcImage1, g_grayImage;
//當前閾值
int thresh = 30;
//最大閾值
int max_thresh = 175;

//全域性函式宣告
//回撥函式
void on_CornerHarris(int, void *);

int main()
{
    //載入原圖
    g_srcImage = imread("1.jpg", 1);
    if (!g_srcImage.data)
    {
        printf("圖片錯誤~!\n");
        return false;
    }
    imshow("原始圖", g_srcImage);
    g_srcImage1 = g_srcImage.clone();

    //轉為灰度圖
    cvtColor(g_srcImage1, g_grayImage, COLOR_BGR2GRAY);

    //建立視窗和滾動條
    namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE);
    createTrackbar("閾值:", WINDOW_NAME1, &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();

    //進行角點檢測
    cornerHarris(g_grayImage, dstImage, 2, 3, 0.04, BORDER_DEFAULT);
    //歸一化與轉換
    normalize(dstImage, normImage, 0, 255, NORM_MINMAX, CV_32FC1);
    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) > 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(WINDOW_NAME1, g_srcImage1);
    imshow(WINDOW_NAME2, scaledImage);
}

這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述