Opencv学习笔记(2)–形态学角点检测

5,860次阅读
没有评论

共计 6603 个字符,预计需要花费 17 分钟才能阅读完成。

形态学角点检测

角点

角点检测(Corner Detection)是计算机视觉系统中用来获得图像特征的一种方法,广泛应用于运动检测、图像匹配、视频跟踪、三维建模和目标识别等领域中。也称为特征点检测。

角点通常被定义为两条边的交点,更严格的说,角点的局部邻域应该具有两个不同区域的不同方向的边界。而实际应用中,大多数所谓的角点检测方法检测的是拥有特定特征的图像点,而不仅仅是“角点”。这些特征点在图像中有具体的坐标,并具有某些数学特征,如局部最大或最小灰度、某些梯度特征等。

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

– 一阶导数(即灰度的梯度)的局部最大所对应的像素点;

– 两条及两条以上边缘的交点;

– 图像中梯度值和梯度方向的变化速率都很高的点;

– 角点处的一阶导数最大,二阶导数为零,指示物体边缘变化不连续的方向。

形态学

一 引言

数学形态学是一门建立在集论基础上的学科,是几何形态学分析和描述的有力工具。数学形态学的历史可回溯到19世纪。1964年法国的Matheron和Serra在积分几何的研究成果上,将数学形态学引入图像处理领域,并研制了基于数学形态学的图像处理系统。1982年出版的专著《Image Analysis and Mathematical Morphology》是数学形态学发展的重要里程碑,表明数学形态学在理论上趋于完备及应用上不断深入。数学形态学蓬勃发展,由于其并行快速,易于硬件实现,已引起了人们的广泛关注。目前,数学形态学已在计算机视觉、信号处理与图像分析、模式识别、计算方法与数据处理等方面得到了极为广泛的应用。
数学形态学可以用来解决抑制噪声、特征提取、边缘检测、图像分割、形状识别、纹理分析、图像恢复与重建、图像压缩等图像处理问题。该文将主要对数学形态学的基本理论及其在图像处理中的应用进行综述。

二 数学形态学的定义和分类

数学形态学是以形态结构元素为基础对图像进行分析的数学工具。它的基本思想是用具有一定形态的结构元素去度量和提取图像中的对应形状以达到对图像分析和识别的目的。数学形态学的应用可以简化图像数据,保持它们基本的形状特征,并除去不相干的结构。数学形态学的基本运算有4个:膨胀、腐蚀、开启和闭合。它们在二值图像中和灰度图像中各有特点。基于这些基本运算还可以推导和组合成各种数学形态学实用算法。

(1)二值形态学

数学形态学中二值图像的形态变换是一种针对集合的处理过程。其形态算子的实质是表达物体或形状的集合与结构元素间的相互作用,结构元素的形状就决定了这种运算所提取的信号的形状信息。形态学图像处理是在图像中移动一个结构元素,然后将结构元素与下面的二值图像进行交、并等集合运算。
基本的形态运算是腐蚀和膨胀。
在形态学中,结构元素是最重要最基本的概念。结构元素在形态变换中的作用相当于信号处理中的“滤波窗口”。用B(x)代表结构元素,对工作空间E中的每一点x,腐蚀和膨胀的定义为:
Opencv学习笔记(2)--形态学角点检测
用B(x)对E进行腐蚀的结果就是把结构元素B平移后使B包含于E的所有点构成的集合。用B(x)对E进行膨胀的结果就是把结构元素B平移后使B与E的交集非空的点构成的集合。先腐蚀后膨胀的过程称为开运算。它具有消除细小物体,在纤细处分离物体和平滑较大物体边界的作用。先膨胀后腐蚀的过程称为闭运算。它具有填充物体内细小空洞,连接邻近物体和平滑边界的作用。
可见,二值形态膨胀与腐蚀可转化为集合的逻辑运算,算法简单,适于并行处理,且易于硬件实现,适于对二值图像进行图像分割、细化、抽取骨架、边缘提取、形状分析。但是,在不同的应用场合,结构元素的选择及其相应的处理算法是不一样的,对不同的目标图像需设计不同的结构元素和不同的处理算法。结构元素的大小、形状选择合适与否,将直接影响图像的形态运算结果。因此,很多学者结合自己的应用实际,提出了一系列的改进算法。如梁勇提出的用多方位形态学结构元素进行边缘检测算法既具有较好的边缘定位能力,又具有很好的噪声平滑能力。许超提出的以最短线段结构元素构造准圆结构元素或序列结构元素生成准圆结构元素相结合的设计方法,用于骨架的提取,可大大减少形态运算的计算量,并可同时满足尺度、平移及旋转相容性,适于对形状进行分析和描述。

(2)灰度数学形态学

二值数学形态学可方便地推广到灰度图像空间。只是灰度数学形态学的运算对象不是集合,而是图像函数。以下设f(x,y)是输入图像,b(x,y)是结构元素。用结构元素b对输入图像y进行膨胀和腐蚀运算分别定义为:
Opencv学习笔记(2)--形态学角点检测
对灰度图像的膨胀(或腐蚀)操作有两类效果:

1. 如果结构元素的值都为正的,则输出图像会比输入图像亮(或暗);

2. 根据输入图像中暗(或亮)细节的灰度值以及它们的形状相对于结构元素的关系,它们在运算中或被消减或被除掉。灰度数学形态学中开启和闭合运算的定义与在二值数学形态学中的定义一致。用b对f进行开启和闭合运算的定义为:
Opencv学习笔记(2)--形态学角点检测

(3)模糊数学形态学

将模糊集合理论用于数学形态学就形成了模糊形态学。模糊算子的定义不同,相应的模糊形态运算的定义也不相同。在此,选用Shinba的定义方法。模糊性由结构元素对原图像的适应程度来确定。用有界支撑的模糊结构元素对模糊图像的腐蚀和膨胀运算按它们的隶属函数定义为:
Opencv学习笔记(2)--形态学角点检测
其中,x,y∈Z2代表空间坐标,ua,ub分别代表图像和结构元素的隶属函数。从(7),(8)式的结果可知,经模糊形态腐蚀膨胀运算后的隶属函数均落在[0,1]的区间内。模糊形态学是传统数学形态学从二值逻辑向模糊逻辑的推广,与传统数学形态学有相似的计算结果和相似的代数特性。模糊形态学重点研究n维空间目标物体的形状特征和形态变换,主要应用于图像处理领域,如模糊增强、模糊边缘检测、模糊分割等。

实验分析

//MORPHOF.h
#pragma once
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

#include <stdio.h>
#include <tchar.h>

#if !defined MORPHOF
#define MORPHOF

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

class MorphoFeatures {

private:

// threshold to produce binary image
int threshold;
// structuring elements used in corner detection
cv::Mat cross;
cv::Mat diamond;
cv::Mat square;
cv::Mat x;

void applyThreshold(cv::Mat& result) {

// Apply threshold on result
if (threshold>0)
cv::threshold(result, result, threshold, 255, cv::THRESH_BINARY_INV);
}

public:

MorphoFeatures() : threshold(-1), cross(5,5,CV_8U,cv::Scalar(0)),
diamond(5,5,CV_8U,cv::Scalar(1)),
square(5,5,CV_8U,cv::Scalar(1)),
x(5,5,CV_8U,cv::Scalar(0)){

// Creating the cross-shaped structuring element
for (int i=0; i<5; i++) {

cross.at<uchar>(2,i)= 1;
cross.at<uchar>(i,2)= 1;
}

// Creating the diamond-shaped structuring element
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;

// Creating the x-shaped structuring element
for (int i=0; i<5; i++) {

x.at<uchar>(i,i)= 1;
x.at<uchar>(4-i,i)= 1;
}
}

void setThreshold(int t) {

threshold= t;
}

int getThreshold() const {

return threshold;
}

cv::Mat getEdges(const cv::Mat &image) {

// Get the gradient image
cv::Mat result;
cv::morphologyEx(image,result,cv::MORPH_GRADIENT,cv::Mat());

// Apply threshold to obtain a binary image
applyThreshold(result);

return result;
}

cv::Mat getCorners(const cv::Mat &image) {

cv::Mat result;
//添加这么显示窗口是为了看到每一步的处理结果,仅用于debug使用,方便理解
// Dilate with a cross
cv::dilate(image,result,cross);
cv::namedWindow("cross Image");
cv::imshow("cross Image",result);
///cv::waitKey(0);
// Erode with a diamond
cv::erode(result,result,diamond);
cv::namedWindow("erode Image");
cv::imshow("erode Image",result);
//cv::waitKey(0);
cv::Mat result2;
// Dilate with a X
cv::dilate(image,result2,x);
cv::namedWindow("X Image");
cv::imshow("X Image",result2);
//cv::waitKey(0);
// Erode with a square
cv::erode(result2,result2,square);
cv::namedWindow("square Image");
cv::imshow("square Image",result2);
//cv::waitKey(0);
// Corners are obtained by differencing
// the two closed images
cv::absdiff(result2,result,result);
cv::namedWindow("absdiff Image");
cv::imshow("absdiff Image",result);
cv::waitKey(0);
// Apply threshold to obtain a binary image
applyThreshold(result);
//添加这么显示窗口是为了看到每一步的处理结果,仅用于debug使用,方便理解
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 each pixel
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
主程序文件如下:

//MAIN.CPP
#include"MORPHOF.h"
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

int main()
{
// Read input image
//binanry test
cv::Mat image=cv::imread("binary3.bmp");
if (!image.data)
return 0;

// Display the image
cv::namedWindow("Image");
cv::imshow("Image",image);

// Create the morphological features instance
MorphoFeatures morpho;
//morpho.setThreshold(40);

// Get the edges
cv::Mat edges;
edges= morpho.getEdges(image);

// Display the edge image
cv::namedWindow("Edge Image");
cv::imshow("Edge Image",edges);

// Get the corners
morpho.setThreshold(-1);
cv::Mat corners;
corners= morpho.getCorners(image);
cv::morphologyEx(corners,corners,cv::MORPH_TOPHAT,cv::Mat());
cv::threshold(corners, corners, 40, 255, cv::THRESH_BINARY_INV);

// Display the corner image
cv::namedWindow("Corner Image");
cv::imshow("Corner Image",corners);

// Display the corner on the image
morpho.drawOnImage(corners,image);
cv::namedWindow("Corners on Image");
cv::imshow("Corners on Image",image);
cv::waitKey(0);
}

实验测试使用的图像Matlab生成:

>> image=zeros(200,200);

>> image(50:150,50:150)=1;

>> imshow(image,[]);

>> saveas(gcf,'binary3','bmp');

实验结果图像如下所示:

原图:
Opencv学习笔记(2)--形态学角点检测
cross十字型膨胀之后:
Opencv学习笔记(2)--形态学角点检测
diamond腐蚀之后:
Opencv学习笔记(2)--形态学角点检测
x模板膨胀之后:
Opencv学习笔记(2)--形态学角点检测
Square腐蚀之后:
Opencv学习笔记(2)--形态学角点检测
图像做差(diamond腐蚀之后图片与Square腐蚀之后图片相减):
Opencv学习笔记(2)--形态学角点检测

总结

数学形态学对图像的处理具有直观上的简明性和数学上的严谨性,在定量描述图像的形态特征上具有独特的优势,为基于形状细节进行图像处理提供了强有力的手段。建立在集合理论基础上的数学形态学,主要通过选择相应的结构元素采用膨胀、腐蚀、开启、闭合等基本运算的组合来处理图像。利用形态学进行角点的检测是形态学处理的一个应用之一。角点检测的方法不限于形态学,比如Harris角点检测,susan检测等等,后续会陆续深入了解。

正文完
请博主喝杯咖啡吧!
post-qrcode
 
admin
版权声明:本站原创文章,由 admin 2015-05-30发表,共计6603字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码