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, intborderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() )
 
  • src – 输入图像
  • dst – 输出图像
  • element –  结构元素.如果

    element=Mat()
     , 一个3*3的结构元素就被使用
  • anchor – 同上
  • iterations – 迭代次数
  • borderType – 边界类型,我在Computer
    Vision: Algorithms and ApplicationsのImage processing
    讨论过
  • borderValue – 边界值,当边界类型为常数填充时启用

(膨胀公式,灰度图像形态学膨胀与腐蚀此文都有介绍)

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

其他形态学操作函数

C++: void morphologyEx(InputArray src,
OutputArray dst, int op, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, intborderType=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:

荷枪实弹

先介绍一个类

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;
} 

效果图:

我们再基于公式自己实现一下,修改的地方很少,主函数没有变化(不一样的地方有注释)

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;
} 

OpenCV2马拉松第16圈——边缘检测(形态学梯度),布布扣,bubuko.com

时间: 2024-10-25 00:47:44

OpenCV2马拉松第16圈——边缘检测(形态学梯度)的相关文章

OpenCV2马拉松第17圈——边缘检测(Canny边缘检测)

计算机视觉讨论群162501053 转载请注明:http://blog.csdn.net/abcd1992719g 收入囊中 利用OpenCV Canny函数进行边缘检测 掌握Canny算法基本理论 分享Java的实现 葵花宝典 在此之前,我们先阐述一下canny检测的算法.总共分为4部分. (1)处理噪声 一般用高斯滤波.OpenCV使用如下核 (2)计算梯度幅值 先用如下Sobel算子计算出水平和竖直梯度 我在OpenCV2马拉松第14圈--边缘检测(Sobel,prewitt,robert

OpenCV2马拉松第14圈——边缘检测(Sobel,prewitt,roberts)

收入囊中 差分在边缘检测的角色 Sobel算子 OpenCV sobel函数 OpenCV Scharr函数 prewitt算子 Roberts算子 葵花宝典 差分在边缘检测到底有什么用呢?先看下面的图片 作为人,我们可以很容易发现图中红圈有边界,边界处肯定是非常明显,变化陡峭的,在数学中,什么可以表示变化的快慢,自然就是导数,微分了. 想像有如下的一维图片. 红圈处变化最陡峭,再看导数图 红圈在最高值,也就是导数可以很好表示边缘,因为变化很剧烈 图像中的Sobel算子 是离散差分算子. 结合了

OpenCV2马拉松第15圈——边缘检测(Laplace算子,LOG算子)

收入囊中 拉普拉斯算子 LOG算子(高斯拉普拉斯算子) OpenCV Laplacian函数 构建自己的拉普拉斯算子 利用拉普拉斯算子进行图像的锐化 葵花宝典 在OpenCV2马拉松第14圈--边缘检测(Sobel,prewitt,roberts)  我们已经认识了3个一阶差分算子 拉普拉斯算子是二阶差分算子,为什么要加入二阶的算子呢?试想一下,如果图像中有噪声,噪声在一阶导数处也会取得极大值从而被当作边缘.然而求解这个极大值也不方便,采用二阶导数后,极大值点就为0了,因此值为0的地方就是边界.

OpenCV2马拉松第17圈——边缘检測(Canny边缘检測)

计算机视觉讨论群162501053 转载请注明:http://blog.csdn.net/abcd1992719g 收入囊中 利用OpenCV Canny函数进行边缘检測 掌握Canny算法基本理论 分享Java的实现 葵花宝典 在此之前,我们先阐述一下canny检測的算法.总共分为4部分. (1)处理噪声 一般用高斯滤波.OpenCV使用例如以下核 (2)计算梯度幅值 先用例如以下Sobel算子计算出水平和竖直梯度 我在OpenCV2马拉松第14圈--边缘检測(Sobel,prewitt,ro

OpenCV2马拉松第26圈——FAST特征点检测

计算机视觉讨论群162501053 转载请注明:http://blog.csdn.net/abcd1992719g/article/details/28424579 关于角点检测,我写过两篇文章 openCV2马拉松第19圈--Harris角点检测(自己实现) OpenCV2马拉松第21圈--形态学操作实现角点检测 有兴趣的童鞋可以去看看--- 收入囊中 FAST角点检测原理 使用OpenCV  FAST API检测角点 葵花宝典 对于一个角点来说,应该与周围的大多数像素点有很大的差别 如上图,

OpenCV2马拉松第14圈——边缘检測(Sobel,prewitt,roberts)

收入囊中 差分在边缘检測的角色 Sobel算子 OpenCV sobel函数 OpenCV Scharr函数 prewitt算子 Roberts算子 葵花宝典 差分在边缘检測究竟有什么用呢?先看以下的图片 作为人,我们能够非常easy发现图中红圈有边界,边界处肯定是非常明显,变化陡峭的,在数学中,什么能够表示变化的快慢,自然就是导数,微分了. 想像有例如以下的一维图片. 红圈处变化最陡峭,再看导数图 红圈在最高值,也就是导数能够非常好表示边缘,由于变化非常剧烈 图像中的Sobel算子 是离散差分

openCV2马拉松第19圈——Harris角点检测(自己实现)

计算机视觉讨论群162501053 转载请注明:http://blog.csdn.net/abcd1992719g/article/details/26824529 收入囊中 使用OpenCV的connerHarris实现角点检测 自己实现Harris算法 下面是自己实现的一个效果图 因为阀值设置比较高,所以房屋周围没有找出来 葵花宝典 在此之前,我们讲过边缘的检测,边缘检测的基本原理就是x方向或者y方向梯度变化很大,角点,顾名思义,就是两个方向的梯度变化都很大. 左1,平滑区域,没有边缘和角点

OpenCV2马拉松第10圈——直方图反向投影(back project)

收入囊中 灰度图像的反向投影 彩色图像的反向投影 利用反向投影做object detect 葵花宝典 什么是反向投影?事实上没有那么高大上! 在上一篇博文学到,图像能够获得自己的灰度直方图. 反向投影差点儿相同是逆过程,由直方图得到我们的投影图. 步骤例如以下: 依据模版图像,得到模版图像的灰度直方图. 对灰度直方图对归一化,归一化后是个概率分布,直方图的积分是1 依据概率分布的直方图,求输入图像的投影图,也就是对每个像素点,我们依据灰度值,能够得到其概率 得到的投影图是介于[0,1]之间的,为

OpenCV2马拉松第13圈——模版匹配

收入囊中 在http://blog.csdn.net/abcd1992719g/article/details/25505315这里,我们已经学习了如何利用反向投影和meanshift算法来在图像中查找给定模版图片的位置.meanshift针对的是单张图像,在连续图像序列的跟踪中,camshift(Continuously Adaptive Mean-SHIFT)是一种著名的算法.但在这里,我们先不讨论camshift,而是先讨论最简单的模版匹配. 模版匹配算法 opencv normalize