opencv学习笔记11-opencv图像形态学处理
一、图像形态学处理:
一种基于图像形状与结构的图像是通过二值图进行分析的方法设计而成的。其中包含了若干关键的操作步骤:腐蚀、膨胀、开闭运算以及特定顺序下的组合操作(开运算是先进行腐蚀再进行膨胀;而闭运算是先执行膨胀再完成腐蚀)。
示例使用图片:(将硬币看为了背景)

示例图片:(将硬币看为了前景,可用于硬币计数)

二、结构元素:
(1)函数原型:
CV_EXPORTS_W Mat getStructuringElement(int shape, Size ksize,
Point anchor = Point(-1,-1));
cpp
(2)函数功能:
返回用于形态学操作的指定大小和形状的结构元素。
(3)参数:
- shape:确定结构元素的形式(即形状),该属性可取自 `#MorphShapes`` 一维枚举集合中的一个成员(即 MORPH_RECT、MORPH_CROSS 或 MORPH_ELLIPSE)。
- ksize:由 Size 类型定义的参数表示该结构体的空间尺寸。
- anchor:确定该结构体内部锚定位置的方式,默认情况下设置为 Point(-1, -1),即位于该结构体几何中心位置上。
- 对于十字形情况而言,则由于对称性原因,在此基础之上调整会影响其形态。
- 其他情况下,则其形态学操作的结果偏移主要取决于锚定位置的选择。
三、腐蚀:
- 腐蚀过程会缩减目标物体的大小并切除边界部分的同时还能去除微小物体及细节部分。
- 腐蚀运算通过将结构元素滑动至图像表面并仅在结构元素完全覆盖前景区域(即非零值区域)时保留中心像素来实现。
(1)函数原型:
CV_EXPORTS_W void erode( InputArray src, OutputArray dst,
InputArray kernel, Point anchor = Point(-1,-1),
int iterations = 1, int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
cpp
(2)函数功能:
通过使用特定的结构元素对图像进行腐蚀。
(3)参数:
输入源图像 src 可以具有任意通道数量;其深度必须是 `CV_8U CV_16U CV_16S CV_32F 或 CV_64F 之一。
dst:输出图像,其大小和类型应与 src 相同。
kernel:形态学腐蚀操作中使用的核型结构元素,在图像处理过程中决定被处理区域像素邻域的影响范围形状。若未指定element,默认采用3×3矩形形态学结构元素;该形态学核可以通过调用#getStructuringElement函数来获取
anchor参数预设为 Point(-1, -1) 表示该定位点位于结构元素的中心。
iterations:腐蚀操作应用的次数。
borderType:采用外推策略来计算超出图像范围的像素值。#BorderTypes 提供了多种边界处理方式,然而当前版本中未支持 BORDER_WRAP 方式。
borderValue:在常数边界情况下的边界值。
(4)腐蚀操作的影响:
a.前景(白色区域) :
- 腐蚀操作主要作用于前景区域及其周边区域中的边缘部分。当结构元素未能完全覆盖住前景对象边界上的像素时,在此情况下这些像素会被移除从而导致目标物体尺寸发生缩减。
- 在腐蚀过程中那些体积较小且细节较为脆弱的小型物体或微小纹理也有可能被彻底去除。
- 这种操作不仅能够有效减少目标物体边界的复杂性还能使整体形状趋于圆滑并呈现更加规整的状态。
b.背景(黑色区域) :
- 通常情况下,在大多数情况下(或一般而言),腐蚀操作不会影响到整个background区域;然而,在某些特定条件下(如结构element较大且接触到了边缘),可能会引起显著变化。
- 当 foreground objects与background极为接近时;腐蚀operation可能导致这些目标与background分离,并使得background区域更加扩展。
(5)代码示例:
#include <opencv2/core/utils/logger.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/objdetect.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);
//读取图片并转化为灰度图
Mat srcMat = imread("C:\ Users\ 86173\ Desktop\ TI\ Coin.jpg", 0);
//判断读取图片是否失败
if (srcMat.empty()) {
cout << "fail to read pic!" << endl;
return 0;
}
//定义图像容器
Mat image;
Mat erode_image;
//二值化
threshold(srcMat,image, 100, 255, THRESH_OTSU);
//定义结构元素
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
//腐蚀
erode(image, erode_image, element, Point(-1, -1), 1);
//显示结果
imshow("二值化", image);//二值化
imshow("腐蚀", erode_image);//腐蚀
waitKey(0);
destroyAllWindows();
return 0;
}
cpp

(6)结果:
(白色为前景,黑色为背景,)

四、膨胀:
膨胀操作会导致目标区域尺寸的提升。该操作朝着边界外方向进行扩展。这有助于填补目标区域中的小孔,并且有时能连接相邻的目标区域。膨胀通常不会影响背景区域,除非所使用的内核规模较大以至于触及到了背景与目标区域之间的边界。
(1)函数原型:
CV_EXPORTS_W void dilate( InputArray src, OutputArray dst,
InputArray kernel, Point anchor = Point(-1,-1),
int iterations = 1, int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
cpp
(2)函数功能:
该函数用于执行图像膨胀操作,并属于形态学处理的一种方法。它有助于增大图像中前景对象的尺寸。
**(3)**原地模式 :
- 该函数实现原地模式(in-place mode),即为输入图像
src和输出图像dst共享同一块内存空间。
(4)参数:
- src:输入图像源(
CV_8U、CV_16U、CV_16S、CV_32F或CV_64F之一)。**- dst:输出图像数据源(与
src类型和大小一致)。** - kernel:用于膨胀操作的膨胀结构元素(若未指定则默认采用
3 x 3矩形结构元素;可由getStructuringElement函数生成)。** - anchor:膨胀操作中所使用的形态学结构元素内锚点位置(默认为结构元素中心点)。**
- iterations:执行膨胀操作的总次数(默认为一次)。**
- borderType:指定边界外推方法(目前不支持
BORDER_WRAP边界类型;详情参见BorderTypes)。** - borderValue:在常数值边界处理方式下使用的常数值。
- dst:输出图像数据源(与
(5)代码示例:
#include <opencv2/core/utils/logger.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/objdetect.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);
//读取图片并转化为灰度图
Mat srcMat = imread("C:\ Users\ 86173\ Desktop\ TI\ Coin.jpg", 0);
//判断读取图片是否失败
if (srcMat.empty()) {
cout << "fail to read pic!" << endl;
return 0;
}
//定义图像容器
Mat image;
Mat erode_image;
//二值化
threshold(srcMat,image, 100, 255, THRESH_OTSU);
//定义结构元素
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
//膨胀
dilate(image, erode_image, element, Point(-1, -1), 1);
//显示结果
imshow("二值化", image);//二值化
imshow("膨胀", erode_image);//膨胀
waitKey(0);
destroyAllWindows();
return 0;
}
cpp

(6)结果:

五、开运算:
- 执行高级形态学变换,先腐蚀再膨胀
(1)函数原型:
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() );
cpp
(2)函数功能 :
该函数基于腐蚀和膨胀运算构建基础操作框架,并支持复杂的形态学处理。
(3)参数:
- src:输入图像可包含任意数量的通道其深度应为
CV_8UCV_16UCV_16SCV_32F或CV_64F中的一种。 - dst:输出图像需与输入图像src具有相同的尺寸和数据类型。
- op:该操作类型见#MorphTypes。
- kernel:结构核用于定义形态学操作的形状和尺寸可由#getStructuringElement获取。
- anchor:结构核内锚定点的位置负值表示锚定点位于结构核中心。
- iterations:确定腐蚀与膨胀操作执行的次数设置。
- borderType:指定边界外推策略以确定超出图像范围像素值的方法见#BorderTypes其中BORDER_WRAP不被支持。
- borderValue:在常数边界情况下指定边界值默认情况下该值具有特殊意义。
(4)注意事项:
迭代次数本质上是腐蚀或膨胀操作被重复执行的数量。举个例子来说,在形态学开操作中(#MORPH_OPEN),两次迭代的过程等同于先连续进行两次腐蚀操作后再进行两次膨胀操作(这与先腐蚀后膨胀再膨胀的操作顺序不同)。
(5)形态学操作类型(#MorphTypes 枚举类型的说明):
a.MORPH_ERODE:
- 腐蚀操作。减少前景对象的尺寸,移除前景边缘的像素。
b.MORPH_DILATE:
- 膨胀操作。增加前景对象的尺寸,填充前景内部的空洞。
c.MORPH_OPEN:
- 开运算法则:通过先执行腐蚀操作再进行膨胀操作的方式进行处理。该方法能够有效地去除微小的物体和细节,并且有助于分离相邻的对象。
- 数学表达式为:
- Erosion followed by dilation is known as opening operation.

d.MORPH_CLOSE:
- 形态学闭运算。先进行膨胀操作再执行腐蚀操作,有助于消除微小的孔隙并填补间隙,并连接断裂区域中的对象。
数学表达式为:

e.MORPH_GRADIENT:
- 梯度算子。开运算后的图像与闭运算后的图像相减能够清晰地勾勒出目标物体的边界。
- 数学表达式如下:
数学表达式为:
G = Dilation(E) - Erosion(E)

f.MORPH_TOPHAT:
\text{顶帽图像} = \text{原图像} - \text{开运算结果}

g.MORPH_BLACKHAT:
- 开闭操作。用闭运算的结果减去原始图像来突出显示前景之外的区域或背景部分。
- 数学表达式为:

h.MORPH_HITMISS:
属于一种特殊的数学形态学操作,在数字图像处理领域具有重要应用价值。它仅适用于单色分辨率图像,并且在实现上较为简便易行。该方法常用于对特定形状进行匹配和检测,并且能够有效地提取目标区域信息
(6)示例代码:
#include <opencv2/core/utils/logger.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/objdetect.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);
//读取图片并转化为灰度图
Mat srcMat = imread("C:\ Users\ 86173\ Desktop\ TI\ Coin.jpg", 0);
//判断读取图片是否失败
if (srcMat.empty()) {
cout << "fail to read pic!" << endl;
return 0;
}
//定义图像容器
Mat image;
Mat erode_image;
//二值化
threshold(srcMat,image, 100, 255, THRESH_OTSU);
//定义结构元素
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
//闭运算
morphologyEx(image, erode_image, MORPH_CLOSE, element, Point(-1, -1), 1);
//显示结果
imshow("二值化", image);//二值化
imshow("闭运算", erode_image);//闭运算
waitKey(0);
destroyAllWindows();
return 0;
}
cpp

(7)结果

六、闭运算:
- 执行高级形态学变换,先膨胀再腐蚀。
(1)函数同开运算。
(2)示例代码:
#include <opencv2/core/utils/logger.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/objdetect.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);
//读取图片并转化为灰度图
Mat srcMat = imread("C:\ Users\ 86173\ Desktop\ TI\ Coin.jpg", 0);
//判断读取图片是否失败
if (srcMat.empty()) {
cout << "fail to read pic!" << endl;
return 0;
}
//定义图像容器
Mat image;
Mat erode_image;
//二值化
threshold(srcMat,image, 100, 255, THRESH_OTSU);
//定义结构元素
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
//开运算
morphologyEx(image, erode_image, MORPH_OPEN, element, Point(-1, -1), 1);
//显示结果
imshow("二值化", image);//二值化
imshow("开运算", erode_image);//开运算
waitKey(0);
destroyAllWindows();
return 0;
}
cpp

(3)结果:

