OpenCV2马拉松第16圈——边缘检测(形态学梯度)

计算机视觉讨论群162501053
转载请注明:http://blog.csdn.net/abcd1992719g


收入囊中

  • 利用OpenCV函数进行形态学梯度操作
  • 自定义结构矩阵进行形态学梯度操作


葵花宝典
在此之前,如果你还没接触过灰度图像形态学膨胀与腐蚀,希望你能仔细阅读 灰度图像形态学膨胀与腐蚀
本质上,灰度与二值并不差异,二值不过是0与255,膨胀与腐蚀的操作都是一样的
形态学梯度的定义如下:

形态梯度

dst=morph_grad(src,element)=dilate(src,element)-erode(src,element)


通俗讲,dilate是膨胀操作,相当于把图像稍微变胖,灰度阶梯变高,erode相当于把图像变稍微细一点,两个相减,就产生了边缘。
我在 Computer Vision: Algorithms and ApplicationsのImage processing    里对形态学操作有简单的介绍。




初识API

C++:   Mat  getStructuringElement ( int  shape , Size  ksize , Point  anchor =Point(-1,-1) )
这个函数用来获得结构矩阵
shape:     MORPH_RECT - 矩形的结构元素:值全为1
MORPH_ELLIPSE - 椭圆形结构元素
MORPH_CROSS - 十字形,只有中心在的那一行一列的值为1
ksize:结构元素的大小
anchor:默认(-1,-1),指代中心,只有十字形元素才依赖这个

C++:  void  dilate (InputArray  src, OutputArray  dst, InputArray  kernel, Point  anchor=Point(-1,-1), int  iterations=1, int borderType=BORDER_CONSTANT, const Scalar&  borderValue=morphologyDefaultBorderValue()  )
 
  • src – 输入图像
  • dst – 输出图像
  • element –  结构元素.如果 element=Mat() , 一个3*3的结构元素就被使用
  • anchor – 同上
  • iterations – 迭代次数
  • borderType – 边界类型,我在Computer Vision: Algorithms and ApplicationsのImage processing讨论过
  • borderValue – 边界值,当边界类型为常数填充时启用

\texttt{dst} (x,y) =  \max _{(x',y'):  \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')(膨胀公式,灰度图像形态学膨胀与腐蚀此文都有介绍)


腐蚀操作对应的API erode和膨胀是一样的


其他形态学操作函数

C++:  void  morphologyEx (InputArray  src, OutputArray  dst, int  op, InputArray  kernel, Point  anchor=Point(-1,-1), int  iterations=1, int borderType=BORDER_CONSTANT, const Scalar&  borderValue=morphologyDefaultBorderValue()  )
 
  • op – 操作类型,今天我们只关注梯度,也就是第3个
    • MORPH_OPEN - an opening operation
    • MORPH_CLOSE - a closing operation
    • MORPH_GRADIENT - a morphological gradient
    • MORPH_TOPHAT - “top hat”
    • MORPH_BLACKHAT - “black hat”
其他的参数和腐蚀,膨胀是一样的

Morphological gradient:

\texttt{dst} = \mathrm{morph\_grad} ( \texttt{src} , \texttt{element} )= \mathrm{dilate} ( \texttt{src} , \texttt{element} )- \mathrm{erode} ( \texttt{src} , \texttt{element} )



荷枪实弹

先介绍一个类

class MorphoFeatures {
private:

	int threshold;  //用于阀值操作
	
	void applyThreshold(Mat& result) {
		if (threshold>0)
			cv::threshold(result, result,threshold, 255, THRESH_BINARY_INV); //注意参数是THRESH_BINARY_INV,当<threshold为255,否则为0,倒过来了
	}

public:

	void setThreshold(int x) {
		threshold = x;
	}

	Mat getEdges(const Mat &image) {
		Mat result;
		morphologyEx(image,result,MORPH_GRADIENT,Mat());  //直接调用,默认3*3
		applyThreshold(result);
		return result;
   	}
   	
};

我们的主函数

int main( int, char** argv )  
{  
	Mat image;
    image = imread( argv[1] );
    cvtColor( image, image, CV_RGB2GRAY );
    
	MorphoFeatures morpho;
	morpho.setThreshold(40); 
	Mat edges;
	edges= morpho.getEdges(image);

    namedWindow("dstImage", 1);  
    imshow("dstImage", edges);  
    waitKey();  
    return 0;  
} 

效果图:



我们再基于\texttt{dst} = \mathrm{morph\_grad} ( \texttt{src} , \texttt{element} )= \mathrm{dilate} ( \texttt{src} , \texttt{element} )- \mathrm{erode} ( \texttt{src} , \texttt{element} )公式自己实现一下,修改的地方很少,主函数没有变化(不一样的地方有注释)

class MorphoFeatures {
private:

	int threshold;
	Mat structedElement;  //自己定义的结构矩阵
	
	void applyThreshold(Mat& result) {
		if (threshold>0)
			cv::threshold(result, result,threshold, 255, THRESH_BINARY_INV);
	}

public:

	MorphoFeatures() : structedElement(3,3,CV_8U,Scalar(1)){} //没有使用API而是直接构造

	void setThreshold(int x) {
		threshold = x;
	}

	Mat getEdges(const Mat &image) {
		Mat result,result1,result2;
		dilate(image,result1,structedElement);  //先膨胀
		erode(image,result2,structedElement);   //再腐蚀
		result = result1 - result2;             //然后相减
		applyThreshold(result);
		return result;
   	}
   	
};

效果图:好像一样哦




举一反三
习惯了用矩形的结构元素,我们用椭圆试一试吧


代码改的地方也很少,为了方便大家,这个代码就全部发出来了
#include "opencv2/highgui/highgui.hpp"  
#include "opencv2/imgproc/imgproc.hpp"  
using namespace cv;  

class MorphoFeatures {
private:

	int threshold;
	Mat structedElement;
	
	void applyThreshold(Mat& result) {
		if (threshold>0)
			cv::threshold(result, result,threshold, 255, THRESH_BINARY_INV);
	}

public:

	MorphoFeatures() {
		structedElement = getStructuringElement( MORPH_ELLIPSE,  Size( 3, 3 ));  
	}

	void setThreshold(int x) {
		threshold = x;
	}

	Mat getEdges(const Mat &image) {
		Mat result,result1,result2;
		dilate(image,result1,structedElement);
      	erode(image,result2,structedElement);
      	result = result1 - result2;
		applyThreshold(result);
		return result;
   	}
   	
};
 

int main( int, char** argv )  
{  
	Mat image;
    image = imread( argv[1] );
    cvtColor( image, image, CV_RGB2GRAY );
    
	MorphoFeatures morpho;
	morpho.setThreshold(40); 
	Mat edges;
	edges= morpho.getEdges(image);

    namedWindow("dstImage", 1);  
    imshow("dstImage", edges);  
    waitKey();  
    return 0;  
} 


  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值