7:OpenCV—图像形态学处理
OpenCV的形态学操作(对象图像进行处理)
包括图像的**腐蚀**、**膨胀**、**开**、**闭**、**形态学梯度、顶帽、黑帽、分支主题、结构元素**等操作。
1.1、膨胀
用3×3的核去扫描二值图像,当核与图像中的前景像素(值为1的像素)有**交集**时,则将二值图像中对应的卷积核中心位置的像素值置为1。
拓展:卷积核可以**为任意形状(除1×1)**,且重置点可以选用卷积核中的**任意位置**,有‘**交集‘**就对重置点位置像素置1。
1.2、腐蚀
用3×3的核去扫描二值图像,仅当核的与前景像素有**完全重合区域**时,将二值图像中对应的卷积核中心位置的像素保留,其余情况下,将中心位置的像素置0。
拓展:卷积核可以**为任意形状**,且**重置点**可以选用卷积核中的**任意位置。**
膨胀与腐蚀的区别:膨胀只要**有交集就触发**,而腐蚀**必须是重置点与前景像素有完全重合区域才保留**。
1.3、开与闭
开:腐蚀再膨胀,去除微小干扰块。
闭:膨胀再腐蚀,填充闭合区域。
1.4、形态学梯度
内梯度:原图 - 腐蚀图
外梯度:膨胀图 - 原图
这里opencv只能直接实现基本梯度,在使用API:morphologyEx 时,调用MORPH_GRADIENT方法即可。
内梯度、外梯度没有直接的API,一般通过已有API间接实现。
1.5、其余形态学操作
顶帽:原图 - 开操作后的图
黑帽:闭操作后的图 - 原图
注:顶帽和黑帽操作用于**获取图像**中的**微小细节**。
击中击不中: 通过特定模板,仅当输入的图像中,**有与模板一模一样的块**时,被击中的输入图像区域才会被保留。
使用API:**morphologyEx** 时,分别调用M**ORPH_TOPHAT 、MORPH_BLACKHAT、MORPH_HITMISS**方法即可实现。
void cv::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()
)
- src:输入图像,图像的通道数可以是任意的,但是图像的数据类型必须是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F之一。
- dst:形态学操作后的输出图像,与输入图像具有相同的尺寸和数据类型。
- op:形态学操作类型的标志,可以选择的标志及含义在表6-6中给出。
- kernel:结构元素,可以自己生成,也可以用getStructuringElement()函数生成。
- anchor:中心点在结构元素中的位置,默认参数为结构元素的几何中心点
- iterations:处理的次数
- borderType:像素外推法选择标志,取值范围在表3-5中给出。默认参数为BORDER_DEFAULT,表示不包含边界值倒序填充。
- borderValue:使用边界不变外推法时的边界值。
该函数根据结构元素对输入图像进行多种形态学操作,在处理多通道图像时每个通道独立进行处理。
函数的第一个参数为待形态学处理的图像,图像通道数可以是任意的,但是图像的数据类型必须是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F之一。
函数第二个参数为形态学处理后的输出图像,与输入图像具有相同的尺寸和数据类型。
函数第三个参数是形态学操作类型的选择标志,可以选择的形态学操作类型有开运算、闭运算、形态学梯度、顶帽运算、黑帽运算以及击中击不中变换,详细的参数在表6-6给出。
函数第四个和第五个参数都是与结构元素相关的参数,第四个参数为结构元素,使用的结构元素尺寸越大效果越明显,第四个参数为结构元素的中心位置,第五个参数的默认值为Point(-1,-1),表示结构元素的几何中心处为结构元素的中心点。
函数第六个参数是使用结构元素处理的次数,处理次数越多效果越明显。
函数第七个参数是图像像素外推法的选择标志,
第八个参数为使用边界不变外推法时的边界值,这两个参数对图像中主要部分的形态学操作没有影响,因此在多数情况下使用默认值即可。
测试代码
#include <iostream> #include <opencv2/opencv.hpp> #include <QDebug>using namespace cv; using namespace std;int main() {//用于验证形态学应用的二值化矩阵Mat src = (Mat_<uchar>(9, 12) << 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);namedWindow("src", WINDOW_NORMAL); //可以自由调节显示图像的尺寸imshow("src", src);// 创建3X3矩形核元素Mat kernel = getStructuringElement(0, Size(3,3));// 对象矩阵进行膨胀操作Mat dilateImg;morphologyEx(src, dilateImg, MORPH_DILATE, kernel);namedWindow("dilateWd", WINDOW_NORMAL); //可以自由调节显示图像的尺寸imshow("dilateWd", dilateImg);// 对象矩阵进行腐蚀操作Mat erodeImg;morphologyEx(src, erodeImg, MORPH_ERODE, kernel);namedWindow("erodeWd", WINDOW_NORMAL); //可以自由调节显示图像的尺寸imshow("erodeWd", erodeImg);// 对象矩阵进行开操作Mat openImg;morphologyEx(src, openImg, MORPH_OPEN, kernel);namedWindow("openWd", WINDOW_NORMAL); //可以自由调节显示图像的尺寸imshow("openWd", openImg);// 对象矩阵进行闭操作Mat closeImg;morphologyEx(src, closeImg, MORPH_CLOSE, kernel);namedWindow("closeWd", WINDOW_NORMAL); //可以自由调节显示图像的尺寸imshow("closeWd", closeImg);// 对象矩阵进行开操作Mat topHatImg;morphologyEx(src, topHatImg, MORPH_TOPHAT, kernel);namedWindow("topHatWd", WINDOW_NORMAL); //可以自由调节显示图像的尺寸imshow("topHatWd", topHatImg);// 对象矩阵进行闭操作Mat blackImg;morphologyEx(src, blackImg, MORPH_BLACKHAT, kernel);namedWindow("blackWd", WINDOW_NORMAL); //可以自由调节显示图像的尺寸imshow("blackWd", blackImg);// 对象矩阵进行梯度运算操作Mat gradientImg;morphologyEx(src, gradientImg, MORPH_GRADIENT, kernel);namedWindow("gradientWd", WINDOW_NORMAL); //可以自由调节显示图像的尺寸imshow("gradientWd", gradientImg);waitKey(0);return 0; }