有關opencv的學習(17)—形態學濾波器檢測邊緣和角點

一、圖像特徵類型可被分爲以下三種:

       邊緣、角點、斑點

       其中,角點是個很特殊的存在。他們在圖像中可以輕易地定位,同時,他們在人造物體場景,比如門、窗、桌等出隨處可見。因爲

角點位於兩條邊緣的交點處,代表了兩個邊緣變化的方向上的點,,所以他們是可以精確定位的二維特徵,甚至可以達到亞像素的精

度。且其圖像梯度有很高的變化,這種變化是可以用來幫助檢測角點的。需要注意的是,角點與位於相同強度區域上的點不同,與物

體輪廓上的點也不同,因爲輪廓點難以在相同的其他物體上精確定位。

二、圖像處理領域,角點檢測算法可歸納爲三類:

        基於灰度圖像的角點檢測、基於二值圖像的角點檢測、基於輪廓曲線的角點檢測。

三、角點檢測(corner detection)

        角點檢測(Corner Detection)是計算機視覺系統中用來獲得圖像特徵的一種方法,廣泛應用於運動檢測、圖像匹配、視頻跟蹤、三維

建模和目標識別等領域中。也稱爲特徵點檢測。

       現有的角點檢測算法並不是都十分的健壯。很多方法都要求有大量的訓練集和冗餘數據來防止或減少錯誤特徵的出現。另外,角點

檢測方法的一個很重要的評價標準是其對多幅圖像中相同或相似特徵的檢測能力,並且能夠應對光照變化、圖像旋轉等圖像變化。

       圖像中的點作爲圖像的特殊位置,是很常用的一類特徵,點的局部特徵也可以叫做“關鍵特徵點”(keypoint feature),或“興趣

點”(interest point),或“角點”(conrner)。

另外,關於角點的具體描述可以有幾種:

     (1).一階導數(即灰度的梯度)的局部最大所對應的像素點;

     (2).兩條及兩條以上邊緣的交點;

     (3).圖像中梯度值和梯度方向的變化速率都很高的點;

     (4).角點處的一階導數最大,二階導數爲零,指示物體邊緣變化不連續的方向。

四、使用形態學濾波器檢測邊緣

圖像如下所示:


用cv::morphologyEx函數的相關濾波器,檢測圖像的邊緣

代碼如下:

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

using namespace std;
using namespace cv;


int main()
{
    
    
    Mat image=imread("/Users/zhangxiaoyu/Desktop/4.png",0);
    if(image.empty())
    {   cout<<"Error!/n";
        return -1;
    }
    
    cv::Mat result;
    cv::morphologyEx(image, result, cv::MORPH_GRADIENT, cv::Mat());
    
    cv::Mat result2;
    int threshold=35;
    cv::threshold(result, result2, threshold, 255, cv::THRESH_BINARY);
    
    namedWindow("Gradient Image");
    imshow("Gradient Image",result);
    
    namedWindow("Binary Image");
    imshow("Binary Image",result2);

    waitKey(0);
    return 0;
    
}

      使用形態學檢測角點的過程比較複雜,需要連續使用多個不同的形態學濾波器。需要在構造函數中定義四個不同的結構函數,分別是正方形、菱形、十字形和X形(在下面的例子中,爲了簡化,所有的結構都固定爲5*5).

      在角點特徵檢測過程中,要依次應用所有結構元素,得到角點分佈圖:

代碼如下:

#ifndef MorphoFeatures_h
#define MorphoFeatures_h


class morphoFeatures
{
    
private:
    
    //用於產生二值圖像的閾值
    int threshold;
    
    //用於檢測角點的結構元素
    cv::Mat_<uchar> cross;
    cv::Mat_<uchar> diamond;
    cv::Mat_<uchar> square;
    cv::Mat_<uchar> x;

    void applyThreshold(cv::Mat &result)
    {
        if(threshold>0)
            cv::threshold(result,result,threshold,255,cv::THRESH_BINARY_INV);
    }
    
public:
    
    morphoFeatures():threshold(-1), cross(5,5),diamond(5,5),square(5,5),x(5,5)
    {
        
        // 產生十字形結構元素
        cross<<
        0,0,1,0,0,
        0,0,1,0,0,
        1,1,1,1,1,
        0,0,1,0,0,
        0,0,1,0,0;
        diamond<<
        0,0,1,0,0,
        0,1,1,1,0,
        1,1,1,1,1,
        0,1,1,1,0,
        0,0,1,0,0;
        square<<
        1,1,1,1,1,
        1,1,1,1,1,
        1,1,1,1,1,
        1,1,1,1,1,
        1,1,1,1,1;
        x<<
        1,0,0,0,1,
        0,1,0,1,0,
        0,0,1,0,0,
        0,1,0,1,0,
        1,0,0,0,1;
        
}
    
    void setThreshold(int t) {
        
        threshold= t;
    }
    
    int getThreshold() const {
        
        return threshold;
    }
    
   
    
    cv::Mat getCorners(const cv::Mat &image)
    {
        cv::Mat result;
        
        //用十字形元素膨脹
        cv::dilate(image,result,cross);
        
        //用菱形元素腐蝕
        cv::erode(result, result, diamond);
        
        cv::Mat result2;
        
        //用x形元素膨脹
        cv::dilate(image, result2, x);
        
        //用正方形元素腐蝕
        cv::erode(result2, result, square);
        
        //比較兩個經過閉合運算的圖像,得到角點
        cv::absdiff(result2, result, result);
        
        //應用閾值,獲得二值圖像
        
        applyThreshold(result);
        
        return result;
    
    }
   
    void drawOnImage(const cv::Mat& binary, cv::Mat& image) {
        
        
        cv::Mat_<uchar>::const_iterator it= binary.begin<uchar>();
        cv::Mat_<uchar>::const_iterator itend= binary.end<uchar>();
       
        for (int i=0; it!= itend; ++it,++i) {
            if (!*it)
                cv::circle(image,cv::Point(i%image.step,i/image.step),5,cv::Scalar(255,0,0));
        }
    }
    
    
    
};



#endif /* MorphoFeatures_h */

主函數如下:

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "morphoFeatures.h"


using namespace cv;
using namespace std;


int main( )
{
    Mat image=imread("/Users/zhangxiaoyu/Desktop/4.png",0);
    if(image.empty())
    {
        cout<<"Error!cannot be read...../n";
        return -1;
    }
    
    morphoFeatures morpho;
    morpho.setThreshold(30);
    
    //檢測角點
    morpho.setThreshold(-1);
    cv::Mat corners;
    corners= morpho.getCorners(image);
    cv::morphologyEx(corners,corners,cv::MORPH_TOPHAT,cv::Mat());
    cv::threshold(corners, corners, 30, 255, cv::THRESH_BINARY_INV);
    
    //顯示角點
    morpho.drawOnImage(corners,image);
    cv::namedWindow("Corners on Image");
    cv::imshow("Corners on Image",image);
    
    waitKey(0);
    
}

運行程序,如下圖所示:


      角點檢測使用了四個不同的結構元素,檢測過程較爲複雜。它的原理是通過使用兩個不同的結構元素膨脹和腐蝕圖像,從而實現圖像的閉合運算。選用這些結構元素後,直線的邊緣保持不變。但因爲它們各自的作用,拐角處的邊緣會受影響。如下圖所示:


       第一個正方形是原始圖像。用十字形結構元素膨脹後,正方形的邊緣擴大了,但拐角處沒有擴大,中間的正方形就對應這種結果。然後用菱形結構元素腐蝕(膨脹後的)圖像。腐蝕運算把大部分邊緣都推回到原始位置,但角點因爲未被膨脹的原因從而會被推得更遠,得到最右邊的正方形,可以看到它已經失去了尖角。用X形和正方形結構元素重複上述過程。這兩個元素與前面兩個類似,因此它們可以捕獲旋轉了45度的角點。最後比較兩個結果,就可以提取出角點特徵。

  








       

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章