基于opencv3.4.7 编程环境win10+VS2017、ubuntu18.04+Codelite

图片膨胀与腐蚀

获取膨胀或者腐蚀的结构元素函数API

Mat getStructuringElement(int shape, Size esize, Point anchor = Point(-1, -1));

API说明

这个函数作用是获得掩膜(类似高斯、均值模糊的卷积核),函数第一个参数表示内核(卷积核)的形状,有三种形状可以选择。

  • 矩形:MORPH_RECT;
  • 交叉形:MORPH_CROSS;
  • 椭圆形:MORPH_ELLIPSE;
    第二和第三个参数分别是内核的尺寸以及锚点的位置。一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得getStructuringElement函数的返回值。对于锚点的位置,有默认值Point(-1,-1),表示锚点位于中心点。element形状唯一依赖锚点位置,其他情况下,锚点只是影响了形态学运算结果的偏移。

膨胀函数API

void Dilate( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 );
void Erode( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 );

API说明

src 输入图像.
dst 输出图像.
element 用于膨胀的结构元素。若为 NULL, 则使用 3×3 长方形的结构元素,默认NULLiterations 膨胀的次数,默认为1

**Erode()腐蚀后Dilate()**膨胀,叫作开操作,那些离散点或游丝线、毛刺就被过滤
**Dilate()膨胀后Erode()**腐蚀,叫作闭操作,那些断裂处就被缝合。

原理

通过getStructuringElement获取膨胀或者腐蚀结构,类似卷积核,膨胀是将卷积核范围内最大值赋值给中心点,腐蚀与之相反。

代码演示
利用滑动条动态调整腐蚀、膨胀力度

#include <iostream>  
#include <fstream>
#include <opencv2/opencv.hpp>

#define Pic_Path "E:\\picture\\"
#define Pic_Name "13.jpg" 

using namespace std;
cv::Mat src, dst,dst1;
int element_size = 0;
int max_size = 21;

void Callback_Demo(int, void*);
void Callback_Demo1(int, void*);
int main(int argc, char **argv)
{
	//获取图片完整路径及名称
	string pic = string(Pic_Path) + string(Pic_Name);
	cout << pic << endl;

	//创建窗口
	cv::namedWindow("原始图片", cv::WINDOW_AUTOSIZE);
	cv::namedWindow("膨胀图片", cv::WINDOW_AUTOSIZE);
	cv::namedWindow("腐蚀图片", cv::WINDOW_AUTOSIZE);

	//获取原始图片
	src = cv::imread(pic.c_str());
	cv::imshow("原始图片", src);

	//创建滑动条 用于动态调整模糊值
	cv::createTrackbar("膨胀调整条", "膨胀图片", &element_size, max_size, Callback_Demo);
	cv::createTrackbar("膨胀调整条", "膨胀图片", &element_size, max_size, Callback_Demo);
	cv::createTrackbar("腐蚀调整条", "腐蚀图片", &element_size, max_size, Callback_Demo1);
	
	//先调用一次回调函数  显示原始图片  否则函数启动时膨胀窗口不显示图片
	Callback_Demo(0, 0);
	Callback_Demo1(0, 0);
	cv::waitKey(0);
	cv::destroyAllWindows();
	return 0;
}


void Callback_Demo(int, void*)
{
	//定义size随着滑动条的数据增长  倍率为*2+1
	int s = element_size * 2 + 1;

	//获得膨胀或者腐蚀的核心  类似卷积核
	//参数1 卷积形状
	//参数2 卷积区域
	//参数3 默认 -1 -1 卷积核中心
	cv::Mat structuringelement = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(s, s),cv::Point(-1, -1));

	//膨胀函数
	//参数1 原图像
	//参数2 目标图像
	//参数3 卷积核
	//参数4 锚点位置 一般为-1 -1 表示中心
	//参数5 
	cv::dilate(src, dst, structuringelement, cv::Point(-1, -1), 1);
	cv::imshow("膨胀图片",dst);
	return;
}

void Callback_Demo1(int, void*)
{
	//定义size随着滑动条的数据增长  倍率为*2+1
	int s = element_size * 2 + 1;

	//获得膨胀或者腐蚀的核心  类似卷积核
	//参数1 卷积形状
	//参数2 卷积区域
	//参数3 默认 -1 -1 卷积核中心
	cv::Mat structuringelement = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(s, s), cv::Point(-1, -1));

	//膨胀函数
	//参数1 原图像
	//参数2 目标图像
	//参数3 卷积核
	//参数4 锚点位置 一般为-1 -1 表示中心
	//参数5 
	cv::erode(src, dst1, structuringelement, cv::Point(-1, -1), 1);
	cv::imshow("腐蚀图片",dst1);
	return;
}

形态学操作(处理二值图效果明显)

高级形态学变换:
开运算
先腐蚀,再膨胀,可清除一些小东西(亮的),放大局部低亮度的区域
闭运算
先膨胀,再腐蚀,可清除小黑点
形态学梯度
膨胀图与腐蚀图之差,提取物体边缘
顶帽
原图像-开运算图,突出原图像中比周围亮的区域
黑帽
闭运算图-原图像,突出原图像中比周围暗的区域腐蚀用于分割(isolate)独立的图像元素,
膨胀用于连接(join)相邻的元素腐蚀、膨胀可用于去噪(低尺寸结构元素的腐蚀操作很容易去掉分散的椒盐噪声点),图像轮廓提取、图像分割、寻找图像中的明显的极大值区域或极小值区域等,腐蚀和膨胀是最基本的形态学算子
结构元素
就相当于我们在滤波中所涉及到的模板(卷积核),也就是说它是一个给定像素的矩阵,这个矩阵可以是任意形状的,一般情况下都是正方形,圆形或者菱形的但是在结构元素中有一个中心点(也叫做anchor point)。和模板中心一样,处理后的结果赋值给和这个中心点对齐的像素点。处理的过程也是基本相同。结构元素和卷积模板的区别在于,膨胀是以集合运算为基础的,卷积是以算数运算为基础的。(OpenCV里面的腐蚀膨胀都是针对白色目标区域的)
膨胀:用结构元素的中心点对准当前正在遍历的这个像素,然后取当前结构元素所覆盖下的原图对应区域内的所有像素的最大值,用这个最大值替换当前像素值,给图像中的对象边界添加像素,使二值图像扩大一圈

  1. 用结构元素,扫描图像的每一个像素
  2. 用结构元素与其覆盖的二值图像做“与”操作
  3. 如果都为0,结果图像的该像素为0。否则为1
    也就是在结构元素覆盖范围下,只要有一个像素符和结构元素像素相同,那么中心点对应点就为1,否则为0

腐蚀:用结构元素的中心点对准当前正在遍历的这个像素,然后取当前结构元素所覆盖下的原图对应区域内的所有像素的最小值,用这个最小值替换当前像素值,删除对象边界的某些像素,使二值图像减小一圈

  1. 用结构元素,扫描图像的每一个像素
  2. 用结构元素与其覆盖的二值图像做“与”操作
  3. 如果都为1,结果图像的该像素为1。否则为0
    也就是查找被处理图像中能不能找到和结构元素相同的矩阵。如果存在那么中心点所对应的点就为1,否则为0

腐蚀:删除对象边界的某些像素
膨胀:给图像中的对象边界添加像素

函数API
CV_EXPORTS_W 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() );参数介绍

  • src 原图像
  • dst 结果输出图像
  • op 表示形态学运算的类型:
•   
• CV_MORPH_OPEN – 开运算(Opening operation)
• CV_MORPH_CLOSE – 闭运算(Closing operation)
• CV_MORPH_GRADIENT - 形态学梯度(Morphological gradient)
• CV_MORPH_TOPHAT - 顶帽(Top hat)
• CV_MORPH_BLACKHAT - 黑帽(Black hat)
• kernel 结构元素
• anchor 结构元素的原点,默认值(-1,-1)
• iterations 迭代次数默认值为1
• borderType 用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_CONSTANT。
• borderValue 当边界为常数时的边界值,有默认值morphologyDefaultBorderValue()

示例代码

#include <iostream>  
#include <fstream>
#include <opencv2/opencv.hpp>

#define Pic_Path "E:\\picture\\"
#define Pic_Name "15.png" 
using namespace std;

int main(int argc, char **argv)
{
	cv::Mat src, dst;
	//获取图片完整路径及名称
	string pic = string(Pic_Path) + string(Pic_Name);
	cout << pic << endl;

	//获取原始图片
	src = cv::imread(pic.c_str());
	if (src.empty())
		return - 1;
	cv::imshow("原始图片", src);

	cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(21, 21), cv::Point(-1, -1));
	
	cv::dilate(src, dst, kernel, cv::Point(-1, -1), 1);
	cv::imshow("膨胀图片", dst);
	cv::erode(src, dst, kernel, cv::Point(-1, -1), 1);
	cv::imshow("腐蚀图片", dst);

	cv::morphologyEx(src, dst, CV_MOP_OPEN,kernel);
	cv::imshow("开操作图片", dst);
	
	cv::morphologyEx(src, dst, CV_MOP_CLOSE, kernel);
	cv::imshow("闭操作图片", dst);

	cv::morphologyEx(src, dst,CV_MOP_GRADIENT, kernel);
	cv::imshow("梯度图片", dst);

	cv::morphologyEx(src, dst, CV_MOP_TOPHAT, kernel);
	cv::imshow("顶帽图片", dst);

	cv::morphologyEx(src, dst, CV_MOP_BLACKHAT, kernel);
	cv::imshow("黑帽图片", dst);
	cv::waitKey(0);
	cv::destroyAllWindows();
	return 0;
}