版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhang_alongzd/article/details/51586140
1:图像形态学用于边缘的提取:
我们知道,图像膨胀后边缘会扩张,腐蚀后会紧缩,通过计算膨胀与紧缩的图像之差,就可以粗略的检测出图像的边缘;
int _tmain(int argc, _TCHAR* argv[])
{
Mat image = imread("007.jpg",1);
cvtColor(image,image,CV_RGB2GRAY);
namedWindow("原图");
imshow("原图",image);
Mat eroded;
erode(image,eroded,Mat());
Mat dilated;
dilate(image,dilated,Mat());
Mat Edge = dilated-eroded;
namedWindow("边缘");
imshow("边缘",Edge);
threshold(Edge,Edge,30,255,THRESH_BINARY);
namedWindow("阈值边缘");
imshow("阈值边缘",Edge);
waitKey(0);
return 0;
}
得到的结果:
除了做减法之外,morphologyEx() 函数直接提供了一个求边缘的参数,只需要修改第三个参数即可,得到的结果和上述一致;
int _tmain(int argc, _TCHAR* argv[])
{
Mat image = imread("007.jpg",1);
cvtColor(image,image,CV_RGB2GRAY);
namedWindow("原图");
imshow("原图",image);
Mat Edge;
morphologyEx(image,Edge,MORPH_GRADIENT,Mat()); //修改第三个参数,直接求边缘
threshold(Edge,Edge,30,255,THRESH_BINARY);
namedWindow("阈值边缘");
imshow("阈值边缘",Edge);
waitKey(0);
return 0;
}
2:图像形态学检测角点
角点最直观的印象就是水平和竖直方向上变换都很大,即X,Y的梯度都很大;边缘可以理解为X,Y方向上只有一个梯度大;而平坦地区水平竖直两个方向上的梯度都很小;角点不仅保留了图像的重要的特征,还有效地减少了信息的数据量,使其信息的含量很高,在三维场景重建、运动估计、目标跟踪与识别、图像的配准与匹配等计算机视觉领域有着非常重要的作用;
目前角点检测的方法主要有基于图像边缘的和基于图像灰度的,前者用的比较少,后者比较常见主要包括Harris算子,Moravec算子和Susan算子。
这里我们自定义一个类,用来实现图像角点的检测;
class MorphologyFeature
{
private:
int Threshold; //用于生成二值图像的阈值;
//角点检测用到的结构元素;
Mat cross;
Mat diamond;
Mat square;
Mat x;
public:
MorphologyFeature();
Mat GetCorners(const Mat &image);
void DrawOnImage(Mat &image,const Mat &binary);
Mat getEdge(Mat &image)
{
Mat result;
morphologyEx(image,result,MORPH_GRADIENT,Mat());
applyThreshold(result);
return result;
}
void applyThreshold(Mat &result)
{
if(threshold>0)
{
threshold(result,result,Threshold,255,THRESH_BINARY);
}
}
void setThreshold(int a)
{
Threshold = a;
}
};
MorphologyFeature::MorphologyFeature():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>(0,4)=0;
diamond.at<uchar>(0,3)=0;
diamond.at<uchar>(1,4)=0;
diamond.at<uchar>(3,0)=0;
diamond.at<uchar>(4,0)=0;
diamond.at<uchar>(4,1)=0;
diamond.at<uchar>(4,4)=0;
diamond.at<uchar>(4,3)=0;
diamond.at<uchar>(3,4)=0;
//创建X型
for(int i=0;i<5;i++)
{
x.at<uchar>(i,i) = 1;
x.at<uchar>(i,4-i) = 1;
}
}
Mat MorphologyFeature::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 MorphologyFeature::DrawOnImage(Mat &image,const Mat &binary)
{
/*Mat_<uchar>::const_iterator it = binary.begin<uchar>();
Mat_<uchar>::const_iterator itend = binary.end<uchar>();
//遍历图像像素
for(int i=0;it!=itend;it++,i++)
{
if(*it)
{
circle(image,Point(i*3%image.step,i*3/image.step),5,Scalar(0,255,0));
}
}*/
for(int i=0;i<binary.rows;i++)
{
//获取行指针
const uchar* data = binary.ptr<uchar>(i);
for(int j=0;j<binary.cols;j++)
{
if(data[j])
{
circle(image,Point(j,i),5,Scalar(0,255,0));
}
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
Mat image = imread("007.jpg",1);
Mat image1 = image;
cvtColor(image,image,CV_RGB2GRAY);
namedWindow("原图");
imshow("原图",image);
MorphologyFeature morph;
morph.setThreshold(10);
Mat Edge = morph.GetCorners(image);
morph.DrawOnImage(image1,Edge);
namedWindow("角点");
imshow("角点",Edge);
namedWindow("结果");
imshow("结果",image1);
waitKey(0);
return 0;
}
得到的结果如下: