OpenCV图像形态学(一)-形态学操作

索引目录

  • 膨胀与腐蚀
    • 膨胀
    • 腐蚀
  • 开运算和闭运算
    • 开运算
    • 闭运算
  • 形态学梯度
  • 击中与击不中变换
  • 顶帽与黑帽变换
    • 顶帽
    • 黑帽
  • 参考文献

通过阈值化分割可以得到二值图,但往往会出现图像中物体形态不完整,变的残缺,可以通过形态学处理,使其变得丰满,或者去除掉多余的像素。形态学的应用:消除噪声、边界提取、区域填充、连通分量提取、凸壳、细化、粗化等;分割出独立的图像元素,或者图像中相邻的元素;求取图像中明显的极大值区域和极小值区域;求取图像梯度

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() )

op:
MORPH_OPEN 开运算
MORPH_CLOSE 闭运算
MORPH_GRADIENT 形态学梯度
MORPH_TOPHAT 顶帽
MORPH_BLACKHAT 黑帽
MORPH_ERODE 腐蚀
MORPH_DILATE 膨胀

kernel形态运算的内核,一般由getStructuringElement函数生成,有三种形状
MORPH_RECT 矩形
MORPH_CROSS 交叉形
MORPH_ELLIPSE 椭圆形

膨胀与腐蚀

是形态学的基本操作,在灰度图像中也是如此,在二值图像中腐蚀和膨胀定义为对图像进行translation以后的“与”和“或”的逻辑操作结果,在灰度图像中,为了保存灰度信息,“与”和“或”操作被对应的替换成了“最大值”和“最小值”操作这样就给出了灰度图像中腐蚀和膨胀的操作定义。

膨胀

桥接断裂,修复断裂的结构元

void dilate( InputArray src,
          OutputArray dst,
          InputArray kernel,
          Point anchor = Point(-1,-1),
          int iterations = 1,
          int borderType = BORDER_CONSTANT,
          const Scalar& borderValue = morphologyDefaultBorderValue());

OpenCV图像形态学(一)-形态学操作_第1张图片

腐蚀

将小于结构元的图像细节从图像中去除

void erode( InputArray src,
          OutputArray dst,
          InputArray kernel,
          Point anchor = Point(-1,-1),
          int iterations = 1,
          int borderType = BORDER_CONSTANT,
          const Scalar& borderValue = morphologyDefaultBorderValue() );

OpenCV图像形态学(一)-形态学操作_第2张图片

开运算和闭运算

开运算

先腐蚀后膨胀的过程。可以用来消除黑色背景中的白色斑点(背景中的白点),在纤细点处分离物体,并且平滑物体的轮廓、断开较窄的狭颈

morphologyEx( InputArray src, OutputArray dst,MORPH_OPEN,element)

闭运算

先膨胀后腐蚀,能够消除白色背景中的黑色斑点(前景中的黑点),一般会弥合较窄的尖端和细长的沟壑,消除小的孔洞,填补轮廓线的断裂。它有助于关闭前景物体内部的小孔,或物体上的小黑点。

morphologyEx( InputArray src, OutputArray dst,MORPH_CLOSE,element)

形态学梯度

膨胀(image)-腐蚀(image),是膨胀图减去腐蚀图的差,将团块(blob)边缘凸显,用来保留物体的边缘轮廓。
可以计算的梯度常见如下四种:
基本梯度:
基本梯度是用膨胀后的图像减去腐蚀后的图像得到差值图像,称为梯度图像也是OpenCV中支持的计算形态学梯度的方法,而此方法得到梯度有被称为基本梯度。
内部梯度:
是用原图像减去腐蚀之后的图像得到差值图像,称为图像的内部梯度。
外部梯度:
是用图像膨胀之后再减去原来的图像得到的差值图像,称为图像的外部梯度。
方向梯度:
方向梯度是使用X方向与Y方向的直线作为结构元素之后得到图像梯度,用X方向直线做结构元素分别膨胀与腐蚀之后得到图像求差值之后称为X方向梯度,用Y方向直线做结构元素分别膨胀与腐蚀之后得到图像求差值之后称为Y方向梯度。
OpenCV图像形态学(一)-形态学操作_第3张图片
在这里插入图片描述
在这里插入图片描述

int main()
{
//首先读入图像,并二值化
    cv::Mat srcImage = cv::imread("../pictures/000177.png",cv::IMREAD_GRAYSCALE);
    cv::threshold(srcImage,srcImage,125,255,cv::THRESH_BINARY);
 
    cv::imshow("srcImage",srcImage);
 
    //获取进行形态学操作的核
    cv::Mat elementRect;
    elementRect = cv::getStructuringElement(cv::MORPH_RECT,cv::Size(3,3),cv::Point(-1,-1));
 
    //膨胀
    cv::Mat dilateImage;
    cv::dilate(srcImage,dilateImage,elementRect);
    //cv::morphologyEx(srcImage,dilateImage,cv::MORPH_DILATE,elementRect);
 
    //腐蚀
    cv::Mat erodeImage;
    cv::erode(srcImage,erodeImage,elementRect);
    //cv::morphologyEx(srcImage,dilateImage,cv::MORPH_ERODE,elementRect);
 
 
    //1.计算基本梯度:膨胀后的图像减去腐蚀后的图像
    cv::Mat basicGradient;
    cv::subtract(dilateImage, erodeImage, basicGradient, cv::Mat());
    //cv::morphologyEx(srcImage,basicGradient,cv::MORPH_GRADIENT,elementRect);//两者等效
    cv::imshow("basicGradient", basicGradient);
 
    //2.计算内部梯度:原图像减去腐蚀之后的图像
    cv::Mat internalGradientImg;
    cv::subtract(srcImage, erodeImage, internalGradientImg, cv::Mat());
    cv::imshow("internalGradientImg", internalGradientImg);
 
    //3.计算外部梯度:膨胀后的图像减去原图像
    cv::Mat externalGradientImg;
    cv::subtract(dilateImage, srcImage, externalGradientImg, cv::Mat());
    cv::imshow("externalGradientImg", externalGradientImg);
 
    //4.方向梯度:使用X方向与Y方向的直线作为结构元素---------
    //cv::Mat hse = getStructuringElement(cv::MORPH_RECT, cv::Size(srcImage.cols / 16, 1),cv::Point(-1,-1));
    //cv::Mat vse = getStructuringElement(cv::MORPH_RECT, cv::Size(1, srcImage.rows / 16),cv::Point(-1,-1));
    cv::Mat hse = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 1),cv::Point(-1,-1));
    cv::Mat vse = getStructuringElement(cv::MORPH_RECT, cv::Size(1, 3),cv::Point(-1,-1));
    cv::Mat  xDirectImg, yDirectImg;
    //4.1 X 方向梯度:膨胀与腐蚀之后得到图像求差值
    cv::erode(srcImage, erodeImage, hse);
    cv::dilate(srcImage, dilateImage, hse);
    cv::subtract(dilateImage, erodeImage, xDirectImg, cv::Mat());
    cv::imshow("xDirectImg", xDirectImg);
    //cv::imshow("dilateImage",dilateImage);
    //cv::imshow("erodeImage",erodeImage);
    //4.2 Y 方向梯度:膨胀与腐蚀之后得到图像求差值
    cv::erode(srcImage, erodeImage, vse);
    cv::dilate(srcImage, dilateImage, vse);
    cv::subtract(dilateImage, erodeImage, yDirectImg, cv::Mat());
    cv::imshow("yDirectImg", yDirectImg);
 
    cv::waitKey(0);
    return 0;
}

击中与击不中变换

采用两个结构基元H,M,作为一个结构元素对B= (H, M) ,一个探测目标内部,一个探测目标外部。当且仅当H平移到某一点可填入X的内部, M平移到该点可填入A的外部时,该点才在击中击不中变换的输出中。则击中击不中变换为:用B1去腐蚀A,然后用B2去腐蚀A的补集,得到的结果相减就是击中击不中变换。
击中其实是一种模板匹配,如果一个结构元(模板)与图像中的一个连通区域完全相等,那么腐蚀的结果将是一个点,这就算是“击中”了,因为找到了完全一致的模式(模式的含义去查一下吧,这里的模式和模式识别的模式含义相同),但如果模板与联通区域去不完全相同,但腐蚀后的结果还是一个点,我们也称为一种“击中”,但不是严格的击中,比如我们的模板是一个直径为10的实心圆形,连通区域是一个直径为10的实心圆和一个直径为1的实心圆的并列排布,其腐蚀结果也是一个点,但其不是完美的击中,要找到完美的击中,必须在模板外面加个边框(或者是背景),这样的结果就不会出现不完美击中,我们可以选模板外一圈黑色的背景(红色背景)作为边框,与上述连通区域做击中操作,很明显。
OpenCV图像形态学(一)-形态学操作_第4张图片

应用:①物体识别:将击中基元设计成为需要识别的图像的样子,击不中基元设计为击中基元取反后的样子,然后用这两个基元对图像进行检测即可。②图像细化:将图像变细,就像取到了图像的骨架。

 morphologyEx(input_image, output_image, MORPH_HITMISS, kernel);

顶帽与黑帽变换

顶帽

礼帽(image)=image-开运算(image),是原图减去“开运算”的结果图之差,突出了比原图轮廓周围区域更亮的区域,用来分离比邻近点亮一些的斑块。顶帽变换用于凸显暗背景上的亮物体。对二值图来说,进行顶帽变换或之后底帽变换看起来就像是加一个阴影,有一种立体的效果。

morphologyEx( InputArray src, OutputArray dst,MORPH_TOPHAT,element)

黑帽

黑帽(image)=闭运算(image)-image,是闭运算的结果减去原图像之差,突出了比原图轮廓周围区域更暗的区域。黑帽运算用来分离比邻近点暗一些的斑块,黑帽变换可以用于凸显亮背景上的暗物体。二值图效果与顶帽变换相比,就是一个方向相反的阴影。

morphologyEx( InputArray src, OutputArray dst,MORPH_BLACKHAT,element)

参考文献

  1. http://blog.csdn.net/tonyshengtan
  2. https://blog.csdn.net/u012851419/article/details/78026596
  3. https://blog.csdn.net/leonardohaig/article/details/87723821

你可能感兴趣的:(学习Opencv4.4.0)