目录
前言
一、膨胀(Dilation)与 腐蚀(Erosion)
二、形态学操作
1、开操作(Opening)
2、闭操作(Closing)
3、形态学梯度(Morphological Gradient)
4、顶帽 ( top hat)
5、黑帽 ( black hat)
6、相关的API
7、代码演示
三、形态学操作应用-提取水平与垂直线
1、原理方法
2、实现步骤
前言
1、了解图像形态学
图像形态学操作是一种基于图像形状的图像处理方法,常用于图像分割、边缘检测、图像增强等领域。
2、图像形态学主要包括腐蚀(Erosion)、膨胀(Dilation)、开运算(Opening)、闭运算(Closing)等操作。
除了以上基本操作,还有其他形态学操作,如击中击不中变换(Hit-or-Miss Transform)、顶帽运算(Top Hat Transform)和黑帽运算(Black Hat Transform)等。
这些图像形态学操作可以通过OpenCV库中的函数进行实现,例如cv::erode
、cv::dilate
、cv::morphologyEx
等函数。
3、膨胀与腐蚀是图像处理中最常用得形态学手段。
一、膨胀(Dilation)与 腐蚀(Erosion)
通俗来讲:膨胀是用来处理缺陷问题,腐蚀用来处理毛刺问题。
所以膨胀过后的图像边界看起来更加清晰;腐蚀后的图像去除噪点,边界模糊了。
1、膨胀含义:
将图像中的前景物体进行扩张,通过在图像上滑动一个结构元素,当结构元素与前景物体有重叠时,将该像素置为1(白色)。膨胀操作可以填充物体内部的空洞,同时使物体边界变得更加清晰。
跟卷积操作类似,假设有图像A和结构元素B,结构元素B在A上面移动,其中B定义其中心为锚点,计算B覆盖下A的最大像素值用来替换锚点的像素,其中B作为结构体可以是任意形状。
2、腐蚀含义:
将图像中的前景物体进行收缩,通过在图像上滑动一个结构元素,当结构元素完全覆盖住前景物体时,将该像素置为0(黑色)。腐蚀操作可以去除小的噪点,同时使物体边界变得模糊。
腐蚀跟膨胀操作的过程类似,唯一不同的是以最小值替换锚点重叠下图像的像素值。
3、相关的API:
(1)getStructuringElement(int shape, Size ksize, Point anchor)
- 形状 (MORPH_RECT \MORPH_CROSS \MORPH_ELLIPSE)
- 大小
- 锚点 默认是Point(-1, -1)意思就是中心像素
(2)dilate(src, dst, kernel)
(3)erode(src, dst, kernel)
4、相关代码演示
#include<opencv2\opencv.hpp>
#include<iostream>int main()
{cv::Mat image = cv::imread("char.jpg", cv::IMREAD_GRAYSCALE);if (image.empty()){std::cout << "Failed to read image" << std::endl;return -1;}// 定义腐蚀和膨胀的核(结构元素)cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));// 腐蚀操作cv::Mat eroded_image;cv::erode(image, eroded_image, kernel);// 膨胀操作cv::Mat dilated_image;cv::dilate(image, dilated_image, kernel);cv::imshow("Original Image", image);cv::imshow("Eroded Image", eroded_image);cv::imshow("Dilated Image", dilated_image);cv::waitKey(0);cv::destroyAllWindows();return 0;
}
效果展示:
二、形态学操作
1、开操作(Opening)
先进行腐蚀操作,再进行膨胀操作。开运算可以消除小的噪点,并保持物体的整体形状不变。
(1)先腐蚀后膨胀
(2)可以去掉小的对象,假设对象是前景色,背景是黑色
2、闭操作(Closing)
先进行膨胀操作,再进行腐蚀操作。闭运算可以填充物体内部的空洞,并保持物体的整体形状不变。
(1)先膨胀后腐蚀(bin2)
(2)可以填充小的洞(fill hole),假设对象是前景色,背景是黑色
3、形态学梯度(Morphological Gradient)
(1)膨胀减去腐蚀
(2)又称为基本梯度(其它还包括-内部梯度、方向梯度)
4、顶帽 ( top hat)
顶帽 是原图像与开操作之间的差值图像
5、黑帽 ( black hat)
黑帽是闭操作图像与源图像的差值图像
6、相关的API
morphologyEx(src, dest, CV_MOP_BLACKHAT, kernel);
// 函数原型:
void morphologyEx (
InputArray src, // 输入图像,可以是单通道灰度图像或多通道彩色图像。
OutputArray dst, // 输出图像,与输入图像具有相同的尺寸和类型。
int op, // 形态学操作类型,可以是以下常量之一:
InputArray kernel, // 结构元素,用于定义形态学操作的形状和大小。可以使用
cv::getStructuringElement
函数创建不同形状的结构元素。Point anchor = Point(-1,-1), // 锚点位置,默认为(-1,-1),表示结构元素的中心。
int iterations = 1, // 形态学操作的迭代次数,默认为1。
int borderType = BORDER_CONSTANT, // 边界类型,默认为
BORDER_CONSTANT
,表示使用常数值进行边界扩展。const Scalar& borderValue = morphologyDefaultBorderValue() // 边界值,默认为
morphologyDefaultBorderValue()
,表示使用默认的边界值。);
其中:
op
:形态学操作类型,可以是以下常量之一:
cv::MORPH_ERODE
:腐蚀操作
cv::MORPH_DILATE
:膨胀操作
cv::MORPH_OPEN
:开运算
cv::MORPH_CLOSE
:闭运算
cv::MORPH_GRADIENT
:形态学梯度
cv::MORPH_TOPHAT
:顶帽运算
cv::MORPH_BLACKHAT
:黑帽运算
7、代码演示
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>using namespace cv;
int main(int argc, char** argv) {Mat src, dst;src = imread("D:/vcprojects/images/bin2.png");if (!src.data) {printf("could not load image...\n");}namedWindow("input image", CV_WINDOW_AUTOSIZE);imshow("input image", src);char output_title[] = "morphology demo";namedWindow(output_title, CV_WINDOW_AUTOSIZE);Mat kernel = getStructuringElement(MORPH_RECT, Size(11, 11), Point(-1, -1));morphologyEx(src, dst, CV_MOP_BLACKHAT, kernel);imshow(output_title, dst);waitKey(0);return 0;
}
效果展示:(黑帽 CV_MOP_BLACKHAT)
三、形态学操作应用-提取水平与垂直线
1、原理方法
图像形态学操作时候,可以通过自定义的结构元素实现结构元素 对输入图像一些对象敏感、另外一些对象不敏感,这样就会让敏 感的对象改变而不敏感的对象保留输出。
通过使用两个最基本的 形态学操作 – 膨胀与腐蚀,使用不同的结构元素实现对输入图像 的操作、得到想要的结果。
(1)膨胀,输出的像素值是结构元素覆盖下输入图像的最大像素值
二值图像与灰度图像上的膨胀操作:
(2)腐蚀,输出的像素值是结构元素覆盖下输入图像的最小像素值
二值图像与灰度图像上的腐蚀操作
(3)结构元素
1)上述膨胀与腐蚀过程可以使用任意的结构元素
2)常见的形状:矩形、园、直线、磁盘形状、砖石形状等各种自定义形状。
2、实现步骤
(1)输入图像彩色图像 imread
(2)转换为灰度图像 – cvtColor
(3)转换为二值图像 – adaptiveThreshold
(4)定义结构元素
(5)开操作 (腐蚀+膨胀)提取 水平与垂直线
(1)输入图像彩色图像 imread
(2)转换为灰度图像 – cvtColor
(3)转换为二值图像 – adaptiveThreshold
adaptiveThreshold(
Mat src, // 输入的灰度图像
Mat dest, // 二值图像
double maxValue, // 二值图像最大值
int adaptiveMethod // 自适应方法,只能其中之一 –
// ADAPTIVE_THRESH_MEAN_C ,APTIVE_THRESH_GAUSSIAN_C
int thresholdType,// 阈值类型
int blockSize, // 块大小
double C // 常量C 可以是正数,0,负数
)
(4)定义结构元素
一个像素宽的水平线 - 水平长度 width/30
一个像素宽的垂直线 – 垂直长度 height/30
(5)开操作 (腐蚀+膨胀)提取 水平与垂直线
后处理
1)bitwise_not(Mat bin, Mat dst)像素取反操作,255 – SrcPixel
2)模糊(blur)
3、代码演示
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
int main(int argc, char** argv) {Mat src, dst;src = imread("D:/vcprojects/images/chars.png");if (!src.data) {printf("could not load image...\n");return -1;}char INPUT_WIN[] = "input image";char OUTPUT_WIN[] = "result image";namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);imshow(INPUT_WIN, src);Mat gray_src;cvtColor(src, gray_src, CV_BGR2GRAY);imshow("gray image", gray_src);Mat binImg;adaptiveThreshold(~gray_src, binImg, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);imshow("binary image", binImg);// 水平结构元素Mat hline = getStructuringElement(MORPH_RECT, Size(src.cols / 16, 1), Point(-1, -1));// 垂直结构元素Mat vline = getStructuringElement(MORPH_RECT, Size(1, src.rows / 16), Point(-1, -1));// 矩形结构Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));Mat temp;erode(binImg, temp, kernel);dilate(temp, dst, kernel);// morphologyEx(binImg, dst, CV_MOP_OPEN, vline);// 背景变色bitwise_not(dst, dst);// 结果更加圆滑些//blur(dst, dst, Size(3, 3), Point(-1, -1));imshow("Final Result", dst);waitKey(0);return 0;
}
效果展示:
(1)水平结构元素:
先腐蚀后膨胀,相当于一开始把垂直的元素擦掉,所以就保留了水平的线。
Mat hline = getStructuringElement(MORPH_RECT, Size(src.cols / 16, 1), Point(-1, -1));
erode(binImg, temp, hline)
dilate(temp, dst, hline);
等同于:
morphologyEx(binImg, dst, CV_MOP_OPEN, hline);
(2)垂直结构元素
先腐蚀后膨胀,相当于一开始把水平的元素擦掉,所以就保留了垂直的线。
Mat vline = getStructuringElement(MORPH_RECT, Size(1, src.rows / 16), Point(-1, -1));
morphologyEx(binImg, dst, CV_MOP_OPEN, vline);
(3)矩形结构
矩形大小的干扰项都去掉。
Mat kernel = getStructuringElement(MORPH_RECT, Size(4, 4), Point(-1, -1));
morphologyEx(binImg, dst, CV_MOP_OPEN, kernel);