图像形态学中的几个基本操作:腐蚀、膨胀、开操作、闭操作
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))
先开后闭可以有效除去噪声
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
膨胀、腐蚀、其余形态学操作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() );
#include
#include
#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/