有关opencv的学习(17)—形态学滤波器检测边缘和角点

来源:互联网 发布:淘宝网液晶电视机 编辑:程序博客网 时间:2024/04/29 14:11

一、图像特征类型可被分为以下三种:

       边缘、角点、斑点

       其中,角点是个很特殊的存在。他们在图像中可以轻易地定位,同时,他们在人造物体场景,比如门、窗、桌等出随处可见。因为

角点位于两条边缘的交点处,代表了两个边缘变化的方向上的点,,所以他们是可以精确定位的二维特征,甚至可以达到亚像素的精

度。且其图像梯度有很高的变化,这种变化是可以用来帮助检测角点的。需要注意的是,角点与位于相同强度区域上的点不同,与物

体轮廓上的点也不同,因为轮廓点难以在相同的其他物体上精确定位。

二、图像处理领域,角点检测算法可归纳为三类:

        基于灰度图像的角点检测、基于二值图像的角点检测、基于轮廓曲线的角点检测。

三、角点检测(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_hclass 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度的角点。最后比较两个结果,就可以提取出角点特征。

  








       

0 0
原创粉丝点击