c++ opencv4.5.5 学习笔记(四)形态学操作(膨胀、腐蚀、开操作、闭操作、形态梯度、顶帽以及黑帽)
·
图像形态学中的几个基本操作:腐蚀、膨胀、开操作、闭操作
膨胀
- 该操作包括将图像与某些内核进行卷积,其可以具有任何形状或尺寸,通常为正方形或圆形。
- 内核具有定义的锚点,通常是内核的中心。
- 当内核在图像上扫描时,我们计算由B重叠的最大像素值,并用该最大值替换锚点位置中的图像像素。您可以推断,这种最大化的操作会使图像中的亮区“增长”(因此称为膨胀)。应用扩张我们可以得到: 字母(明亮)扩大了,背景的黑色地区缩小了。

膨胀使物体变大。其实就是选择滑动窗口中像素值最大的点(局部最大值)公式表示:
dst(x,y)=dilate(src(x,y))=max(x′,y′)src(x+x′,y+y′)
腐蚀
- 这个操作是扩张的姊妹。它计算给定内核区域的局部最小值。
- 当内核在图像上扫描时,我们计算由重叠的最小像素值,并用该最小值替换锚点下的图像像素。
- 对于扩张的例子,我们可以将侵蚀算子应用于原始图像(如上所示)。您可以在下面的结果中看到,图像的明亮区域(字母)变得更小,而黑暗区域(背景)变得更大。

腐蚀使物体变小。其实就是选择滑动窗口中像素值最小的点(局部最小值)公式表示:
dst(x,y)=erode(src(x,y))=min(x′,y′)src(x+x′,y+y′)
开操作
- 它是通过图像的腐蚀获得的,随后是膨胀。先腐蚀后膨胀的操作称之为开操作。它具有消除细小物体,在纤细处分离物体和平滑较大物体边界的作用。
dst = open(src,element) = dilate(erode(src,element))
- 用于去除小物体(假设物品是亮色,前景色是黑色),被用来抹除比背景亮的噪点。
- 例如,请查看下面的示例。左侧的图像是原始图像,右侧的图像是应用打开转换后的结果。我们可以观察到,信中角落的小空间往往会消失。

为了清楚起见,我们7x7在相同的原始图像上执行了开操作(矩形结构元素),但是反转,例如白色的对象现在是字母。
开操作 = 腐蚀 + 膨胀 消除部分高亮区域(二值化中的白色区域)
闭操作
- 它是通过图像的膨胀,然后是腐蚀获得的。先膨胀后腐蚀的操作称之为闭操作。它具有填充物体内细小空洞,连接邻近物体和平滑边界的作用。用来抹除比背景暗的噪点。
dst = close(src,element) = erode(dilate(src,element))
- 有用的是去除小孔(暗区)。

在倒置图像上,我们执行了闭操作(7x7矩形结构元素):
闭操作 = 膨胀 + 腐蚀 消除高亮区域的内部黑洞(二值化中的黑色区域)
先开后闭可以有效除去噪声
形态梯度
- 膨胀以后的图像减去腐蚀以后的图像,可以用来提取图片中的边缘。
dst(x,y)=morph_grad(src,element)=dilate(src,element)−erode(src,element)
- 找到对象的轮廓是有用的,如下所示:

顶帽
- 原图减去开运算以后的图像,取出高亮的小目标前景(适用于原始图像背景是暗的,前景是亮的,把明亮的前景突出出来)
dst(x,y)=top_hat(src,element)=src−open(src,element))

黑帽
- 闭运算以后的图像减去原图,取出非高亮的小目标前景。(适用于原始图像背景是亮的,前景是暗的,把暗色的前景突出出来)
dst(x,y)=black_hat(src,element)=close(src,element)−src

先顶帽后黑猫可以增强对比度
C++ Code API
膨胀、腐蚀、其余形态学操作API
/**
*获取,卷积核
*shape 卷积核形状
MORPH_RECT 矩形
MORPH_CROSS 十字形
MORPH_ELLIPSE 椭圆形
*ksize 大小
*anchor 锚点位置
**/
Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));
/**
*膨胀
*src:源图
*dst:结果
*kernel:运算核
*anchor:锚点位置
*iterations:迭代次数
*borderType:边界扩充类型
*borderValue:边界扩充值
**/
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 结果
*kernel:运算核
*anchor 锚点位置
*iterations 迭代次数
*borderType:边界扩充类型
*borderValue:边界扩充值
**/
void erode( InputArray src, OutputArray dst, InputArray kernel,
Point anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
/**
*形态学操作
*src 源图
*dst 结果
*op 运算类型
MORPH_CLOSE 闭
MORPH_OPEN 开
MORPH_GRADIENT 梯度
MORPH_TOPHAT 顶帽
MORPH_BLACKHAT 黑帽
MORPH_DILATE 膨胀
MORPH_ERODE 腐蚀
*kernel:运算核
*anchor 锚点位置
*iterations 迭代次数
*borderType:边界扩充类型
*borderValue:边界扩充值
**/
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() );
实操代码
lena图片
测试代码
#include <opencv.hpp>
#include <iostream>
#define WINDOWNAME "【效果图】"
int g_nStructElementSize = 3;
int g_nTrackbarNumber = 0;
int anchor = -1;
int model = 0;
cv::Mat g_srcImage, g_dstImage;
std::map<int, int> SizeShape;
std::map<int, int> ProcessModel;
std::map<int, std::string> ModelName;
void Process()
{
//MORPH_RECT 矩形
//MORPH_CROSS 十字形
//MORPH_ELLIPSE 椭圆形
SizeShape[0] = cv::MORPH_RECT;
SizeShape[1] = cv::MORPH_CROSS;
SizeShape[2] = cv::MORPH_ELLIPSE;
//cv::MORPH_CLOSE 闭
//cv::MORPH_OPEN 开
//cv::MORPH_GRADIENT 梯度
//cv::MORPH_TOPHAT 顶帽
//cv::MORPH_BLACKHAT 黑帽
//cv::MORPH_DILATE 膨胀
//cv::MORPH_ERODE 腐蚀
ProcessModel[0] = cv::MORPH_CLOSE;
ProcessModel[1] = cv::MORPH_OPEN;
ProcessModel[2] = cv::MORPH_GRADIENT;
ProcessModel[3] = cv::MORPH_TOPHAT;
ProcessModel[4] = cv::MORPH_BLACKHAT;
ProcessModel[5] = cv::MORPH_DILATE;
ProcessModel[6] = cv::MORPH_ERODE;
ModelName[0] = "MORPH_CLOSE";
ModelName[1] = "MORPH_OPEN";
ModelName[2] = "MORPH_GRADIENT";
ModelName[3] = "MORPH_TOPHAT";
ModelName[4] = "MORPH_BLACKHAT";
ModelName[5] = "MORPH_DILATE";
ModelName[6] = "MORPH_ERODE";
cv::Mat element;
if (anchor >= (2 * g_nStructElementSize))
{
anchor = 2 * g_nStructElementSize;
}
element = cv::getStructuringElement(SizeShape[model], cv::Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize + 1),cv::Point(anchor, anchor));
cv::morphologyEx(g_srcImage, g_dstImage, ProcessModel[g_nTrackbarNumber], element);
cv::putText(g_dstImage, ModelName[g_nTrackbarNumber],cv::Point(0, 40), cv::FONT_HERSHEY_COMPLEX, 0.8, cv::Scalar(25,25, 255), 1, 1);
cv::imshow(WINDOWNAME, g_dstImage);
}
void on_ElementSizeChange(int, void*)
{
Process();
}
void on_TrackbarNumChange(int, void*)
{
Process();
}
void on_AnchorChange(int, void*)
{
Process();
}
void on_ModelChange(int, void*)
{
Process();
}
int main()
{
std::string filename = "Standard_image/lena.jpg";
g_srcImage = cv::imread(filename, cv::IMREAD_GRAYSCALE);
//显示原始图
const char* pName1 = "图";
cv::namedWindow(pName1);
cv::imshow(pName1, g_srcImage);
cv::namedWindow(WINDOWNAME);
cv::createTrackbar("处理方法", WINDOWNAME, &g_nTrackbarNumber, 6, on_TrackbarNumChange);
cv::createTrackbar("锚点位置", WINDOWNAME, &anchor, 10, on_AnchorChange);
cv::createTrackbar("内核形状", WINDOWNAME, &model, 2, on_ModelChange);
cv::createTrackbar("内核尺寸", WINDOWNAME, &g_nStructElementSize, 21, on_ElementSizeChange);
cv::waitKey(0);
}
闭操作效果
开操作效果
形态梯度效果
顶帽效果
黑帽效果
膨胀效果
腐蚀效果
最后感谢大佬的分享:
https://blog.csdn.net/fan1102958151/article/details/106996717/
更多推荐
所有评论(0)