OpenCV学习教程之形态学操作

目标

本文尝试解答如下问题:

如何使用OpenCV函数 morphologyEx 进行形态学操作:

  • 开运算 (Opening)
  • 闭运算 (Closing)
  • 形态梯度 (Morphological Gradient)
  • 顶帽 (Top Hat)
  • 黑帽(Black Hat)

原理

Note :以下内容来自于Bradski和Kaehler的大作 Learning OpenCV 。
前一我们讨论了两种最基本的形态学操作:

  • 腐蚀 (Erosion)
  • 膨胀 (Dilation)

运用这两个基本操作,我们可以实现更高级的形态学变换。这篇文档将会简要介绍OpenCV提供的5种高级形态学操作:

开运算 (Opening)

  • 开运算是通过先对图像腐蚀再膨胀实现的。

     dst = open( src, element) = dilate( erode( src, element ) )
    
  • 能够排除小团块物体(假设物体较背景明亮)

  • 请看下面,左图是原图像,右图是采用开运算转换之后的结果图。 观察发现字母拐弯处的白色空间消失。
    在这里插入图片描述

闭运算(Closing)

  • 闭运算是通过先对图像膨胀再腐蚀实现的。

     dst = close( src, element ) = erode( dilate( src, element ) )
    
  • 能够排除小型黑洞(黑色区域)。
    在这里插入图片描述

形态梯度(Morphological Gradient)

  • 膨胀图与腐蚀图之差

     dst = morph_{grad}( src, element ) = dilate( src, element ) - erode( src, element )
    
  • 能够保留物体的边缘轮廓,如下所示

在这里插入图片描述

顶帽(Top Hat)

  • 原图像与开运算结果图之差

     dst = tophat( src, element ) = src - open( src, element )
    

    在这里插入图片描述

黑帽(Black Hat)

  • 闭运算结果图与原图像之差

     dst = blackhat( src, element ) = close( src, element ) - src
    

在这里插入图片描述

源码

#include "pch.h"
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace std;
using namespace cv;

//全局变量
Mat src, dst, temp,tempGray;

int morph_elem = 0;
int morph_size = 0;
int morph_operator = 0;
int const max_operator = 4;
int const max_elem = 2;
int const max_kernel_size = 21;

const char* window_name = "Morphology Transformation Demo";

//函数声明
void Morphology_Operations(int, void*);

int main()
{
	temp = imread("C:\\Users\\wuyuzon\\Desktop\\Pictures\\lyf.jpg");
	if (!temp.data) { return -1; }

	cvtColor(temp, tempGray, CV_BGR2GRAY);//转化为灰度图
	threshold(tempGray, src, 100, 255, CV_THRESH_BINARY);//转化为二值图像

	namedWindow(window_name, CV_WINDOW_AUTOSIZE);
	//创建选择具体操作的trackbar
	createTrackbar("Operator:\n 0: Opening - 1 : Closing \n 2: Gradient - 3 : Top Hat \n 4: Black Hat",
		window_name, &morph_operator, max_operator, Morphology_Operations);
	//创建内核大小的trackbar
	createTrackbar("Element:\n 0: Rect - 1: Cross - 2: Ellipse",
		window_name, &morph_size, max_kernel_size, Morphology_Operations);

	//启动默认值
	Morphology_Operations(0, 0);

	waitKey(0);

	return 0;
}

void Morphology_Operations(int, void*)
{
	//MORPH_X的取值范围是:2,3,4,5,6
	int operation = morph_operator + 2;

	Mat element = getStructuringElement(morph_elem, Size(2 * morph_size + 1, 2 * morph_size + 1), Point(morph_size, morph_size));

	//运行指定形态学操作
	morphologyEx(src, dst, operation, element);

	imshow(window_name, dst);

}

解释

1、看一下程序的总体流程:

  • 装载图像
  • 创建显示形态学操作的窗口
  • 创建3个trackbar获取用户参数

第一个trackbar “Operator” 返回用户选择的形态学操作类型 (morph_operator).

createTrackbar("Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat",
           window_name, &morph_operator, max_operator,
           Morphology_Operations );

第二个trackbar “Element” 返回 morph_elem, 指定内核形状:

createTrackbar( "Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name,
            &morph_elem, max_elem,
            Morphology_Operations );

第三个trackbar “Kernel Size” 返回内核大小(morph_size)

createTrackbar( "Kernel size:\n 2n +1", window_name,
            &morph_size, max_kernel_size,
            Morphology_Operations );
  • 每当任一标尺被移动, 用户函数 Morphology_Operations
    就会被调用,该函数获取trackbar的当前值运行指定操作并更新显示结果图像。

      /**
     * @函数 Morphology_Operations
     */
     void Morphology_Operations( int, void* )
     {
       // 由于 MORPH_X的取值范围是: 2,3,4,5 和 6
       int operation = morph_operator + 2;
     
       Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
     
       /// 运行指定形态学操作
       morphologyEx( src, dst, operation, element );
       imshow( window_name, dst );
      }
    

运行形态学操作的核心函数是 morphologyEx 。在本例中,我们使用了4个参数(其余使用默认值):

src : 原 (输入) 图像
dst: 输出图像
operation: 需要运行的形态学操作。 我们有5个选项:

  • Opening: MORPH_OPEN : 2

  • Closing: MORPH_CLOSE: 3

  • Gradient: MORPH_GRADIENT: 4

  • Top Hat: MORPH_TOPHAT: 5

  • Black Hat: MORPH_BLACKHAT: 6

你可以看到, 它们的取值范围是 <2-6>, 因此我们要将从tracker获取的值增加(+2):

int operation = morph_operator + 2;

element: 内核,可以使用函数:get_structuring_element:getStructuringElement <> 自定义。

结果

  • 在编译上面的代码之后, 我们可以运行结果,将图片路径输入。这里使用图像: baboon.png:
    在这里插入图片描述
  • 这里是显示窗口的两个截图。第一幅图显示了使用交错内核和 开运算 之后的结果, 第二幅图显示了使用椭圆内核和 黑帽 之后的结果。
    在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值