OpenCV C++ 图像形态学处理实战:腐蚀、膨胀及七种高级运算详解

许南星
许南星
发布时间:2026-10-15 | 3人浏览过
原创

数字图像处理中,形态学操作是基于形状的分析工具。本文基于 OpenCV 和 C++,详解图像腐蚀、膨胀的原理与代码实现,并介绍利用 morphologyEx 进行开运算、闭运算、顶帽变换、黑帽变换及形态学梯度的实用技巧,提供从基础到进阶的完整解决方案。

结果或目标:掌握形态学核心操作

形态学处理主要用于提取图像中对分割和描述有意义的区域分量,如边界、轮廓、凸包等。其核心在于使用结构元素(Kernel)与输入图像进行卷积操作。我们将依次实现腐蚀、膨胀及其组合运算,并通过自定义函数理解底层逻辑,最后统一通过标准库函数完成复杂变换。

准备条件

在进行形态学操作前,建议先将图像转换为二值图像(黑白图像),因为形态学操作在二值图像上的视觉效果最为明显且稳定。需要包含 #include <opencv2/opencv.hpp> 命名空间为 cv。常用的结构元素可通过 cv::getStructuringElement 获取,支持矩形(MORPH_RECT)、十字形(MORPH_CROSS)和椭圆形(MORPH_ELLIPSE)。

真实操作顺序

第1步:图像腐蚀(Erosion)

目的:收缩或细化前景物体,常用于去除白色噪声点或断开连接。

原理:用结构元素扫描图像,当结构元素覆盖区域内所有像素均为前景色(白色/高值)时,锚点对应像素保留前景;否则变为背景色(黑色/低值)。简而言之,取局部最小值。

使用内置 erode 函数

入口:直接调用 cv::erode。

// 构造 3x3 矩形结构元素
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
// 执行腐蚀,迭代3次以增强效果
Mat image_erosion;
erode(image_bw, image_erosion, element, Point(-1, -1), 3);
imshow("image_erosion", image_erosion);

参数说明:src 为输入图,dst 为输出图,kernel 为结构元素,iterations 为迭代次数(越大腐蚀越严重),anchor 默认中心 Point(-1,-1)。

自定义腐蚀实现

通过遍历局部窗口寻找最小值模拟该过程:

void erode_my(Mat &src, Mat &dst, int size) {
    for (int i = 0; i < src.rows; ++i) {
        for (int j = 0; j < src.cols; ++j) {
            uchar minV = 255;
            // 遍历邻域寻找最小像素值
            for (int yi = i - size / 2; yi <= i + size / 2; ++yi) {
                for (int xi = j - size / 2; xi <= j + size / 2; ++xi) {
                    if (xi < 0 || xi >= src.cols || yi < 0 || yi >= src.rows) continue;
                    minV = min(minV, src.at<uchar>(yi, xi));
                }
            }
            dst.at<uchar>(i, j) = minV;
        }
    }
}

当结构尺寸扩大至 9x9 时,自定义函数效果与内置函数基本一致。展示对比:

第2步:图像膨胀(Dilation)

目的:扩张前景物体边缘,填充孔洞或连接邻近物体。

原理:若结构元素覆盖区域内存在任意前景像素,则锚点对应变为前景。简而言之,取局部最大值。膨胀与腐蚀互为对偶运算。

使用内置 dilate 函数

Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
Mat image_dilate;
// 执行膨胀,迭代9次显著扩大主体
;dilate(image_bw, image_dilate, element, Point(-1, -1), 9);
imshow("image_dilate", image_dilate);

自定义膨胀实现

void dilate_my(Mat& src, Mat& dst, int size) {
    for (int i = 0; i < src.rows; ++i) {
        for (int j = 0; j < src.cols; ++j) {
            uchar maxV = 0;
            // 遍历邻域寻找最大像素值
            for (int yi = i - size / 2; yi <= i + size / 2; ++yi) {
                for (int xi = j - size / 2; xi <= j + size / 2; ++xi) {
                    if (xi < 0 || xi >= src.cols || yi < 0 || yi >= src.rows) continue;
                    maxV = max(maxV, src.at<uchar>(yi, xi));
                }
            }
            dst.at<uchar>(i, j) = maxV;
        }
    }
}

同样在 9x9 尺寸下,自定义膨胀效果与内置函数吻合:

第3步:开运算与闭运算

开运算(Opening):先腐蚀后膨胀。作用是平滑轮廓、断开狭窄连接、消除细小噪声(假设前景为白)。

原图与开运算效果:

可通过两次调用的方式实现,也可直接使用形态学通用函数:

Mat open_image;
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(image_bw, open_image, MORPH_OPEN, kernel); // 方法二:推荐

闭运算(Closing):先膨胀后腐蚀。作用是填充前景物体内的小孔、连接邻近物体。

Mat close_image;
morphologyEx(image_bw, close_image, MORPH_CLOSE, kernel); // 方法二:推荐

第4步:高级形态学变换

以下操作均可通过 cv::morphologyEx 一次性完成,定义明确且效率更高。

1. 顶帽变换(Top Hat)

原理:原始图像 - 开运算结果。用于分离比周围亮一些的区域,常用来提取噪声或背景不均匀时的文字前景。

手动实现逻辑如下:

// 方法一:内置标志位
morphologyEx(image_bw, top_hat, MORPH_TOPHAT, kernel); 

// 方法二:显式减法
subtract(image_bw, open_image, top_hat_manual); 
// 或使用绝对差值检测差异
absdiff(image_bw, open_image, top_hat_diff);

2. 黑帽变换(Black Hat)

原理:闭运算结果 - 原始图像。用于提取前景内部的小孔或深色斑点。

// 方法一:内置标志位
morphologyEx(image_bw, black_hat, MORPH_BLACKHAT, kernel);

// 方法二:闭运算减原图
subtract(close_image, image_bw, black_hat_manual); 
// 注意顺序:闭-原

3. 形态学梯度(Morphological Gradient)

原理:膨胀图 - 腐蚀图。能够勾勒出物体的轮廓边界,适合二值图像的边界提取。

// 方法一:内置标志位
morphologyEx(image_bw, gradient, MORPH_GRADIENT, kernel);

// 方法二:膨胀减腐蚀
absdiff(dilated_img, eroded_img, gradient_manual); 

morphologyEx 函数参数详解

该函数是形态学操作的统一入口,原型如下:

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
);
  • op 关键枚举值:
    • MORPH_ERODE (0):腐蚀
    • MORPH_DILATE (1):膨胀
    • MORPH_OPEN (2):开运算
    • MORPH_CLOSE (3):闭运算
    • MORPH_GRADIENT (4):梯度
    • MORPH_TOPHAT (5):顶帽
    • MORPH_BLACKHAT (6):黑帽
    • MORPH_HITMISS (7):击中-击不中
  • borderType 边框处理方式:
    • BORDER_CONSTANT:固定值填充(默认)
    • BORDER_REPLICATE:边缘复制
    • BORDER_REFLECT:镜像反射

完成判断

运行上述代码后,观察窗口显示的结果:

  • 腐蚀后的物体应当变小,孤立噪点消失;
  • 膨胀后的物体变大,断裂处连接;
  • 开运算去除了毛刺但保持了物体大致面积;
  • 闭运算填平了内部空洞;
  • 顶帽和黑帽分别突出了亮背景和暗背景下的微小特征;
  • 梯度清晰展示了物体边缘。

简要总结

形态学处理是计算机视觉预处理的关键环节。对于简单的腐蚀和膨胀,可直接使用 erode 和 dilate;而对于组合逻辑复杂的开闭运算及顶帽、黑帽等操作,推荐使用 morphologyEx 以提高代码可读性和执行效率。理解结构元素的大小与形状对最终图像处理结果的直接影响,有助于在实际项目中调整参数以达到最佳效果。

以上就是 OpenCV C++ 图像形态学处理(含腐蚀、膨胀、开闭运算及高级变换)的详细内容,更多关于 OpenCV 数字图像处理基于 C++ 的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表