opencv学习(9)利用形态滤波学检测角点

来源:互联网 发布:势不可挡 网络剧 编辑:程序博客网 时间:2024/06/05 04:29

       在一幅灰度图像中,我们可以把亮的那一部分比作山,暗的那一部分比作山谷,而边缘就是山和山谷的相接的地方,这部分的灰度值会急剧的变化。如果在边缘地方使用腐蚀操作,那么和边缘交接的亮的地方就会被0所替代,也就山的一部分变成了山谷,那么山的高度就降低了。而膨胀的结果和这个相反。而水平地势的地方,也就是山顶的平地不会被影响到。

利用这个原理我们就可以找到图像的边缘。也就是找出腐蚀和膨胀后的图像的不同,结果就是边缘。很明显,如果我们使用的结构元素越大,那么得到的边缘就会越厚。由于我们是找出两张图片的不同,就不需要处理二值图像了。

同样的,拿腐蚀或者膨胀后的图像和原图像进行比较,也可以得到边缘,并且边缘更细一些。

在OpenCV中算子cv::morphologyEx(img, result, cv::MORPH_GRADIENT, cv::Mat()); 可以实现这个功能,函数名与开操作闭操作的相同,只是int op这个参数不同。

角点检测比边缘检测要复杂一些,他需要使用四个结构元素。这四个结构元素是我们自己定义的。首先我们先将图像使用两个不同的结构元素进行膨胀和腐蚀,结果就是,原有的图像平滑的边缘没有变化,而角点却显现出来,下面就是对一幅正方形白色图像爱说明一下,其中第一个是原图。

角点检测示例


需要使用到的结构元素

当我们用一个十字交叉(cross)的结构元素对图像进行膨胀操作时,只有角点的地方没有膨胀。然后我们再利用菱形(diamond)结构元素对其进行腐蚀操作,边缘的部分又回到了原来的位置,而角点却显现了出来。也可以使用x形状和正方形(square)形状的结构元素重复以上操作,可以看出这两个结构元素是对上面两个元素的旋转45度形成的,因此它们可以用来检测45度的角点。然后比较这两个结果的不同便可以得出我们想要的角点。


检测到的边缘

</pre><pre name="code" class="cpp">#include "stdafx.h"#include<opencv2/opencv.hpp>using namespace cv;class MorphoFeatures{private://用于生成二值图像的阈值int threshold;//角点检测用到的结构元素Mat cross;Mat diamond;Mat square;Mat x;public://检测角点//opencv没有直接实现它,需要定义四种不同的结构元素,//包括:菱形,方形,十字形,x形。并在构造函数中完成MorphoFeatures() :threshold(-1),cross(5, 5, CV_8U, Scalar(0)),diamond(5, 5, CV_8U, Scalar(1)),square(5, 5, CV_8U, Scalar(1)),x(5, 5, CV_8U, Scalar(0)){//创建十字形元素for (int i = 0; i < 5; i++){cross.at<uchar>(2, i) = 1;cross.at<uchar>(i, 2) = 1;}//创建菱形diamond.at<uchar>(0, 0) = 0;diamond.at<uchar>(0, 1) = 0;diamond.at<uchar>(1, 0) = 0;diamond.at<uchar>(4, 4) = 0;diamond.at<uchar>(3, 4) = 0;diamond.at<uchar>(4, 3) = 0;diamond.at<uchar>(4, 0) = 0;diamond.at<uchar>(4, 1) = 0;diamond.at<uchar>(3, 0) = 0;diamond.at<uchar>(0, 4) = 0;diamond.at<uchar>(0, 3) = 0;diamond.at<uchar>(1, 4) = 0;//创建x形for (int i = 0; i < 5; i++){x.at<char>(i, i) = 1;x.at<char>(4 - i, i) = 1;}}Mat getEdges(const Mat &image){//得到梯度图Mat result;//morphology函数配上合适的滤波器就可以实现直线检测morphologyEx(image, result, MORPH_GRADIENT, Mat());applyThreshold(result);return result;}void setThreshold(int t){threshold = t;}void applyThreshold(Mat & result){if (threshold > 0)cv::threshold(result, result, threshold, 255, THRESH_BINARY);}//需要连接使用这些结构元素,得到最终的角点映射图Mat getCorners(const Mat&image){Mat result;//十字形膨胀dilate(image, result, cross);//菱形腐蚀erode(result, result, diamond);Mat result2;//x形膨胀dilate(image, result2, x);//方形腐蚀erode(result2, result2, square);//通过对两张图像做差值,得到角点图像absdiff(result2, result, result);//阈值化得到二值图像applyThreshold(result);return result;}//为了可视化,在在二值图像中每个监测点绘制一个圆void drawOnImage(const Mat & binary, Mat & image){Mat_<uchar>::const_iterator it = binary.begin<uchar>();Mat_<uchar>::const_iterator itend = binary.end<uchar>();//遍历每个像素for (int i = 0; it != itend; ++i, ++it){if (!*it)circle(image, Point(i%image.step, i / image.step), 5, Scalar(0, 255, 0));}}};int _tmain(int argc, _TCHAR* argv[]){//直线检测Mat image = imread("building.jpg", 0);//imshow("d", image);if (!image.data)return -1;MorphoFeatures morpho;morpho.setThreshold(40);Mat edges;edges = morpho.getEdges(image);imshow("d", edges);//角点检测morpho.setThreshold(-1);Mat corners;corners = morpho.getCorners(image);morphologyEx(corners, corners, MORPH_TOPHAT, Mat());threshold(corners, corners, 40, 255, THRESH_BINARY_INV);//imshow("角点",corners);  //展示图片上的角点  morpho.drawOnImage(corners, image);imshow("jj", image);waitKey(0);return 0;}

0 0