Opencv_12 形态学操作

文章目录

      • 一. 结构化元素
      • 二. 腐蚀和膨胀
        • ① 腐蚀和膨胀的原理介绍
        • ② 腐蚀案例
        • ③ 膨胀案例
      • 三. 开闭操作
        • ① 开操作的定义
        • ② 开运算案例
        • ③ 闭运算实例
      • 四.形态学梯度
      • 五. 顶帽
      • 六. 黑帽

一. 结构化元素

结构元素就是在做形态学操作的卷积核,其实更直白一点就是计算的时候的有效区域.就是决定用哪些值去做运算

函数原型:

Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1))
  • 参数解释
  • shape: 结构化元素的形状定义: MORPH_RECT 矩形 MORPH_CROSS 十字形 MORPH_ELLIPSE椭圆形
  • kszie: 结构化元素的大小
  • anchor: 锚点,默认是Point(-1,-1)意思就是中心像素,也可以自己制定
#include "MyOpencv.h"
int main(void)
{
	// 创建一个3*3的矩形,十字,椭圆结构元素
	Mat kernelRect, kernelCross, kernelEllipse;
	kernelRect = cv::getStructuringElement(cv::MORPH_RECT, Size(3, 3), cv::Point(-1, -1));
	kernelCross = cv::getStructuringElement(cv::MORPH_CROSS, Size(3, 3), cv::Point(-1, -1));
	kernelEllipse = cv::getStructuringElement(cv::MORPH_ELLIPSE, Size(3, 3), 
												cv::Point(-1, -1));

	cout << "形状是3 * 3的各种结构化元素: " << endl;
	cout << "矩形卷积核: =  " << endl;
	cout << kernelRect << endl;

	cout << "十字卷积核: = " << endl;
	cout << kernelCross << endl;

	cout << "椭圆卷积核: = " << endl;
	cout << kernelEllipse << endl;


	// 创建一个5*5的矩形,十字,椭圆结构元素
	kernelRect = cv::getStructuringElement(cv::MORPH_RECT, Size(5, 5), 
											cv::Point(-1, -1));
	kernelCross = cv::getStructuringElement(cv::MORPH_CROSS, Size(5, 5), cv::Point(-1, -1));
	kernelEllipse = cv::getStructuringElement(cv::MORPH_ELLIPSE, Size(5, 5), 
												cv::Point(-1, -1));

	cout << "********************************" << endl;
	cout << "形状是5 * 5的各种结构化元素: " << endl;
	cout << "矩形卷积核: =  " << endl;
	cout << kernelRect << endl;

	cout << "十字卷积核: = " << endl;
	cout << kernelCross << endl;

	cout << "椭圆卷积核: = " << endl;
	cout << kernelEllipse << endl;
 
	return 0;
}

结果:
Opencv_12 形态学操作_第1张图片

二. 腐蚀和膨胀

① 腐蚀和膨胀的原理介绍

腐蚀和膨胀都是使用卷积核和原图像做卷积操作,然后取卷积结果的最值,如果是腐蚀操作,就取最小值,如果是膨胀操作就是取最大值.因为原图只有两个像素值0和255,所以腐蚀操作的时候,取最小值是0,给我们的感觉就是一些白色的部分被消除掉了,膨胀相反.

腐蚀的作用:

可以用来消除小且无意义的物体.

② 腐蚀案例

函数原型:

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

参数解释:

  • src: 输入图像
  • dst: 输出图像
  • kernel: 结构化元素
  • anchor: 中心位置锚点
  • iterations: 操作次数,默认值是1
  • boardType: 边缘填充类型
  • boardValue: 填充值(默认即可)
#include "MyOpencv.h"

int main(void)
{
	Mat original = cv::imread("test_04.bmp", IMREAD_GRAYSCALE);
	imshow("Original", original);
	Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));

	// 腐蚀两次
	Mat dst;
	for (int i = 1; i < 5; i++)
	{
		erode(original, dst, kernel, Point(-1, -1), i);
		string imageName = "EroseTimes_";
		imageName += to_string(i);
		imshow(imageName, dst);
	}

	waitKey(0);
	return 0;
}

结果:
Opencv_12 形态学操作_第2张图片
腐蚀的次数越多,白色的部分越少.
使用的核越大,白色的部分也会越少

③ 膨胀案例

函数原型:

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

参数解释:

  • src: 输入图像
  • dst: 输出图像
  • kernel: 结构化元素
  • anchor: 中心位置锚点
  • iterations: 操作次数,默认值是1
  • boardType: 边缘填充类型
  • boardValue: 填充值(默认即可)

膨胀操作的目的一般是扩充边界,比如上面的腐蚀操作,可以消除掉无用的小块,但是整个目标物体可能也被缩小了.这个时候可以使用膨胀操作,让物体的白色区域复原.

#include "MyOpencv.h"
int main(void)
{
	Mat original = cv::imread("test_04.bmp", IMREAD_GRAYSCALE);
	imshow("Original", original);
	Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));

	// 腐蚀两次
	Mat dst;
	erode(original, dst, kernel, Point(-1, -1), 2);

	imshow("Erode", dst);

	Mat dilateDst;
	// 腐蚀之后,目标物体表小了,边瘦了,如何还原呢?可以使用膨胀操作还原
	dilate(dst, dilateDst, kernel, Point(-1, -1), 2);

	imshow("Dilate", dilateDst);

	waitKey(0);
	return 0;
}

结果:
Opencv_12 形态学操作_第3张图片

三. 开闭操作

① 开操作的定义

  1. 先腐蚀后膨胀
  2. 作用: 分离物体,消除小区域. 消除噪声,去除小的干扰块,而不影响原来的图像

② 开运算案例

函数原型:

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=2

案例:
Opencv_12 形态学操作_第4张图片
例如,这个图片,使用开操作可以消除周围的小圆孔.同时尽可能最大程度的保留原来的圆孔

#include "MyOpencv.h"

int main(void)
{
	Mat original = imread("test_05.bmp", IMREAD_GRAYSCALE);
	imshow("Original", original);

	Mat opened;
	Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));

	for (int index = 1; index < 4; index++)
	{
		string imageName = "ClosedTimes_";
		imageName += to_string(index);
		morphologyEx(original, opened,MORPH_RECT, kernel, Point(-1, -1), index);
		imshow(imageName, opened);
	}

	waitKey(0);
	return 0;
}

结果:
Opencv_12 形态学操作_第5张图片

③ 闭运算实例

先膨胀后腐蚀,可以填充小对象,经常用来填充前景物体中的小洞,或者是前景物体上的小黑点.
Opencv_12 形态学操作_第6张图片
代码:

#include "MyOpencv.h"

int main(void)
{
	Mat original = imread("test_06.bmp", IMREAD_GRAYSCALE);
	imshow("Original", original);

	Mat kernel = getStructuringElement(MORPH_RECT, Size(4, 4), Point(-1, -1));
	Mat closed;
	for (int index = 1; index < 4; index++)
	{
		morphologyEx(original, closed, MORPH_CLOSE, kernel, Point(-1, -1), index);
		imshow("ClosedTimes" + to_string(index), closed);
	}

	waitKey(0);
	return 0;
}

结果:
Opencv_12 形态学操作_第7张图片

四.形态学梯度

形态学梯度就是膨胀减去腐蚀.

形态学梯度有称为了基本梯度,对二值图像进行形态学梯度操作可以将团块(blob)的边缘突出来,可以保留物体的边缘轮廓.

Opencv_12 形态学操作_第8张图片

#include "MyOpencv.h"

int main(void)
{
	Mat original = imread("test_07.bmp", IMREAD_GRAYSCALE);
	imshow("Origianl", original);

	for (int index = 1; index < 4; index++)
	{
		Mat gradient;
		Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
		morphologyEx(original, gradient, MORPH_GRADIENT, kernel, Point(-1, -1), index);
		imshow("GradientTimes_" + to_string(index),gradient);
	}
	waitKey(0);
	return 0;
}

五. 顶帽

顶帽操作是原图像和开操作之间的差值图像

Opencv_12 形态学操作_第9张图片
开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图像中减去开运算后的图,得到的效果图突出了比原型轮廓周围的区域更明亮的区域.

顶帽运算往往用来分离邻近点亮一些的斑块.当一幅图像具有大幅的背景的时候,而微小物品比较有规律的时候,可以用顶帽运算进行提取小物品
Opencv_12 形态学操作_第10张图片
使用顶帽操作,可以将周围的这种白色的小块提取出来

#include "MyOpencv.h"

int main(void)
{
	Mat original = imread("test_08.bmp", IMREAD_GRAYSCALE);
	imshow("Original", original);
	Mat opened, tophat;
	Mat kernel = getStructuringElement(MORPH_RECT, Size(7, 7), Point(-1, -1));

	for (int i = 1; i < 4; i++)
	{
		morphologyEx(original, opened, MORPH_OPEN, kernel, Point(-1, -1), i);
		morphologyEx(original, tophat, MORPH_TOPHAT, kernel, Point(-1, -1), i);
		imshow("OpenedTimes_" + to_string(i), opened);
		imshow("TophatTiems_" + to_string(i), tophat);
	}

	waitKey(0);
	return 0;
}

结果:
Opencv_12 形态学操作_第11张图片

六. 黑帽

黑帽(Black Hat)运算为闭运算的结果与原图像之差
黑帽运算后的效果图是突出了比原图轮廓周围区域更暗的区域,用来分离比邻近点暗一些的斑块
Opencv_12 形态学操作_第12张图片

实例:
Opencv_12 形态学操作_第13张图片
黑帽操作,可以提取里面的小的黑色的斑块

#include "MyOpencv.h"

int main(void)
{
	Mat original = imread("test_09.bmp", IMREAD_GRAYSCALE);
	imshow("Original", original);
	Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
	Mat closed, blackHat;

	for (int i = 1; i < 4; i++)
	{
		morphologyEx(original, closed, MORPH_CLOSE, kernel, Point(-1, -1), i);
		morphologyEx(original, blackHat, MORPH_BLACKHAT, kernel, Point(-1, -1), i);
		imshow("ClosedTimes_" + to_string(i), closed);
		imshow("BlackHatTimes_" + to_string(i), blackHat);
	}


	waitKey(0);
	return 0;
}

Opencv_12 形态学操作_第14张图片

你可能感兴趣的:(Opencv_C++,opencv,计算机视觉,c++)