OpenCV 【十八】图像平滑处理/腐蚀与膨胀(Eroding and Dilating)/开闭运算,形态梯度,顶帽,黑帽运算
图像滤波总结(面试经验总结)https://blog.csdn.net/Darlingqiang/article/details/79507468
目录
part one 图像平滑处理
1原理
2代码
3效果
part two 腐蚀与膨胀(Eroding and Dilating)
1原理
2代码
3运行结果
part three更多形态学变换¶
1 原理
2 代码
3 结果
part one 图像平滑处理
1原理
平滑 也称 模糊, 是一项简单且使用频率很高的图像处理方法。
平滑处理的用途有很多, 但是在本教程中我们仅仅关注它减少噪声的功用 (其他用途在以后的教程中会接触到)。
平滑处理时需要用到一个 滤波器 。 最常用的滤波器是 线性 滤波器,线性滤波处理的输出像素值 (i.e.
) 是输入像素值 (i.e.
)的加权和 :
称为 核, 它仅仅是一个加权系数。
不妨把 滤波器 想象成一个包含加权系数的窗口,当使用这个滤波器平滑处理图像时,就把这个窗口滑过图像。
滤波器的种类有很多, 这里仅仅提及最常用的:
1.1归一化块滤波器 (Normalized Box Filter)
最简单的滤波器, 输出像素值是核窗口内像素值的 均值 ( 所有像素加权系数相等)
核如下:
1.2高斯滤波器 (Gaussian Filter)
最有用的滤波器 (尽管不是最快的)。 高斯滤波是将输入数组的每一个像素点与 高斯内核 卷积将卷积和当作输出像素值。
还记得1维高斯函数的样子吗?
假设图像是1维的,那么观察上图,不难发现中间像素的加权系数是最大的, 周边像素的加权系数随着它们远离中间像素的距离增大而逐渐减小。
Note
2维高斯函数可以表达为 :
其中 为均值 (峰值对应位置),
代表标准差 (变量 和 变量
各有一个均值,也各有一个标准差)
1.3中值滤波器 (Median Filter)
中值滤波将图像的每个像素用邻域 (以当前像素为中心的正方形区域)像素的 中值 代替 。
1.4双边滤波 (Bilateral Filter)
目前我们了解的滤波器都是为了 平滑 图像, 问题是有些时候这些滤波器不仅仅削弱了噪声, 连带着把边缘也给磨掉了。 为避免这样的情形 (至少在一定程度上 ), 我们可以使用双边滤波。
类似于高斯滤波器,双边滤波器也给每一个邻域像素分配一个加权系数。 这些加权系数包含两个部分, 第一部分加权方式与高斯滤波一样,第二部分的权重则取决于该邻域像素与当前像素的灰度差值。
详细的解释可以查看 链接
2代码
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace std;
using namespace cv;
/// 全局变量
int DELAY_CAPTION = 15000;
int DELAY_BLUR = 100;
int MAX_KERNEL_LENGTH = 31;
Mat src; Mat dst;
char window_name[] = "Filter Demo 1";
/// 函数申明
int display_caption(char* caption);
int display_dst(int delay);
/**
* main 函数
*/
int main(int argc, char** argv)
{namedWindow(window_name, CV_WINDOW_AUTOSIZE);
/// 载入原图像src = imread("C:\\Users\\guoqi\\Desktop\\ch7\\4.jpg", 1);
if (display_caption("Original Image") != 0) { return 0; }
dst = src.clone();if (display_dst(DELAY_CAPTION) != 0) { return 0; }/// 使用 均值平滑if (display_caption("Homogeneous Blur") != 0) { return 0; }
for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2){blur(src, dst, Size(i, i), Point(-1, -1));if (display_dst(DELAY_BLUR) != 0) { return 0; }}
/// 使用高斯平滑if (display_caption("Gaussian Blur") != 0) { return 0; }
for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2){GaussianBlur(src, dst, Size(i, i), 0, 0);if (display_dst(DELAY_BLUR) != 0) { return 0; }}
/// 使用中值平滑if (display_caption("Median Blur") != 0) { return 0; }
for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2){medianBlur(src, dst, i);if (display_dst(DELAY_BLUR) != 0) { return 0; }}
/// 使用双边平滑if (display_caption("Bilateral Blur") != 0) { return 0; }
for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2){bilateralFilter(src, dst, i, i * 2, i / 2);if (display_dst(DELAY_BLUR) != 0) { return 0; }}
/// 等待用户输入display_caption("End: Press a key!");
waitKey(0);return 0;
}
int display_caption(char* caption)
{dst = Mat::zeros(src.size(), src.type());putText(dst, caption,Point(src.cols / 4, src.rows / 2),CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255));
imshow(window_name, dst);int c = waitKey(DELAY_CAPTION);if (c >= 0) { return -1; }return 0;
}
int display_dst(int delay)
{imshow(window_name, dst);int c = waitKey(delay);if (c >= 0) { return -1; }return 0;
}
createTrackbar 的使用
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
using namespace std;
using namespace cv;
//拖动条回调函数
void onChangeTrackBar(int pos, void *data)
{//强制类型转换Mat srcImage = *(cv::Mat*)(data);Mat dstImage;//根据拖动条的值对传入图像进行二值化threshold(srcImage, dstImage, pos, 255, 0);imshow("threshold", dstImage);
}
int main()
{//读取图像Mat srcImage = imread("C:\\Users\\guoqi\\Desktop\\ch7\\1.jpg", IMREAD_UNCHANGED);if (!srcImage.data) {cout << "read failed" << endl;system("pause");return -1;}//原图像转换灰度图Mat srcGray;cvtColor(srcImage, srcGray, CV_RGB2GRAY);namedWindow("threshold");//创建窗口imshow("threshold", srcGray);//创建滑动条createTrackbarcreateTrackbar("pos", "threshold",0, 255, onChangeTrackBar, &srcImage);waitKey(0);return 0;
}
3效果
part two 腐蚀与膨胀(Eroding and Dilating)
1原理
1.1形态学操作¶
简单讲,形态学操作就是基于形状的一系列图像处理操作。将 结构元素 作用于输入图像来产生输出图像。
最基本的形态学操作有二:腐蚀与膨胀(Erosion 与 Dilation)。 他们的运用广泛:
消除噪声
分割(isolate)独立的图像元素,以及连接(join)相邻的元素。
寻找图像中的明显的极大值区域或极小值区域。
通过以下图像,我们简要来讨论一下膨胀与腐蚀操作(译者注:注意这张图像中的字母为黑色,背景为白色,而不是一般意义的背景为黑色,前景为白色):
1.2膨胀
此操作将图像
与任意形状的内核 (
),通常为正方形或圆形,进行卷积。
内核
有一个可定义的 锚点, 通常定义为内核中心点。
进行膨胀操作时,将内核
划过图像,将内核
覆盖区域的最大相素值提取,并代替锚点位置的相素。显然,这一最大化操作将会导致图像中的亮区开始”扩展” (因此有了术语膨胀 dilation )。对上图采用膨胀操作我们得到:
背景(白色)膨胀,而黑色字母缩小了。
1.3腐蚀
腐蚀在形态学操作家族里是膨胀操作的孪生姐妹。它提取的是内核覆盖下的相素最小值。
进行腐蚀操作时,将内核
划过图像,将内核
覆盖区域的最小相素值提取,并代替锚点位置的相素。
以与膨胀相同的图像作为样本,我们使用腐蚀操作。从下面的结果图我们看到亮区(背景)变细,而黑色区域(字母)则变大了。
2代码
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "highgui.h"
#include <stdlib.h>
#include <stdio.h>
using namespace cv;
/// 全局变量
Mat src, erosion_dst, dilation_dst;
int erosion_elem = 0;
int erosion_size = 0;
int dilation_elem = 0;
int dilation_size = 0;
int const max_elem = 2;
int const max_kernel_size = 21;
/** Function Headers */
void Erosion(int, void*);
void Dilation(int, void*);
/** @function main */
int main(int argc, char** argv)
{/// Load 图像src = imread("C:\\Users\\guoqi\\Desktop\\ch7\\1.jpg", IMREAD_UNCHANGED);
if (!src.data){return -1;}
/// 创建显示窗口namedWindow("Erosion Demo", CV_WINDOW_AUTOSIZE);namedWindow("Dilation Demo", CV_WINDOW_AUTOSIZE);cvMoveWindow("Dilation Demo", src.cols, 0);
/// 创建腐蚀 TrackbarcreateTrackbar("Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Erosion Demo",&erosion_elem, max_elem,Erosion);
createTrackbar("Kernel size:\n 2n +1", "Erosion Demo",&erosion_size, max_kernel_size,Erosion);
/// 创建膨胀 TrackbarcreateTrackbar("Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Dilation Demo",&dilation_elem, max_elem,Dilation);
createTrackbar("Kernel size:\n 2n +1", "Dilation Demo",&dilation_size, max_kernel_size,Dilation);
/// Default startErosion(0, 0);Dilation(0, 0);
waitKey(0);return 0;
}
/** @function Erosion */
void Erosion(int, void*)
{int erosion_type;if (erosion_elem == 0) { erosion_type = MORPH_RECT; }else if (erosion_elem == 1) { erosion_type = MORPH_CROSS; }else if (erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }
Mat element = getStructuringElement(erosion_type,Size(2 * erosion_size + 1, 2 * erosion_size + 1),Point(erosion_size, erosion_size));
/// 腐蚀操作erode(src, erosion_dst, element);imshow("Erosion Demo", erosion_dst);
}
/** @function Dilation */
void Dilation(int, void*)
{int dilation_type;if (dilation_elem == 0) { dilation_type = MORPH_RECT; }else if (dilation_elem == 1) { dilation_type = MORPH_CROSS; }else if (dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }
Mat element = getStructuringElement(dilation_type,Size(2 * dilation_size + 1, 2 * dilation_size + 1),Point(dilation_size, dilation_size));///膨胀操作dilate(src, dilation_dst, element);imshow("Dilation Demo", dilation_dst);
}
3运行结果
part three更多形态学变换¶
这篇文档将会简要介绍OpenCV提供的5种高级形态学操作:
1 原理
1.1开运算 (Opening)
开运算是通过先对图像先腐蚀再膨胀
实现的。
能够排除小团块物体(假设物体较背景明亮)
请看下面,左图是原图像,右图是采用开运算转换之后的结果图。 观察发现字母拐弯处的白色空间消失。
1.2闭运算(Closing)
闭运算是通过先对图像
先膨胀再腐蚀
实现的。能够排除小型黑洞(黑色区域)。
1.3形态梯度(Morphological Gradient)
膨胀图与腐蚀图之差
能够保留物体的边缘轮廓,如下所示:
1.4顶帽(Top Hat)
原图像与开运算结果图之差
1.5黑帽(Black Hat)
闭运算结果图与原图像之差
2 代码
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
using namespace cv;
/// 全局变量
Mat src, dst;
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;
char* window_name = "Morphology Transformations Demo";
/** 回调函数申明 */
void Morphology_Operations(int, void*);
/** @函数 main */
int main(int argc, char** argv)
{/// 装载图像src = imread("C:\\Users\\guoqi\\Desktop\\ch7\\7.jpg", IMREAD_UNCHANGED);
if (!src.data){return -1;}
/// 创建显示窗口namedWindow(window_name, CV_WINDOW_AUTOSIZE);
/// 创建选择具体操作的 trackbarcreateTrackbar("Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat", window_name, &morph_operator, max_operator, Morphology_Operations);
/// 创建选择内核形状的 trackbarcreateTrackbar("Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name,&morph_elem, max_elem,Morphology_Operations);
/// 创建选择内核大小的 trackbarcreateTrackbar("Kernel size:\n 2n +1", window_name,&morph_size, max_kernel_size,Morphology_Operations);
/// 启动使用默认值Morphology_Operations(0, 0);
waitKey(0);return 0;
}
/**
* @函数 Morphology_Operations
*/
void Morphology_Operations(int, void*)
{// 由于 MORPH_X的取值范围是: 2,3,4,5 和 6int 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);
}
看一下程序的总体流程:
装载图像
创建显示形态学操作的窗口
创建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 和 6int 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 <> 自定义。
3 结果
这里是显示窗口的两个截图。第一幅图显示了使用交错内核和 开运算 之后的结果, 第二幅图显示了使用椭圆内核和 黑帽 之后的结果。
椭圆内核和 黑帽 之后的结果。
OpenCV 【十八】图像平滑处理/腐蚀与膨胀(Eroding and Dilating)/开闭运算,形态梯度,顶帽,黑帽运算相关推荐
- C++ OpenCV形态学操作--开闭操作,形态学梯度,顶帽,黑帽
https://my.oschina.net/u/4582134/blog/4582844
- OpenCV之imgproc 模块. 图像处理(1)图像平滑处理 腐蚀与膨胀(Eroding and Dilating) 更多形态学变换 图像金字塔 基本的阈值操作
图像平滑处理 目标 本教程教您怎样使用各种线性滤波器对图像进行平滑处理,相关OpenCV函数如下: blur GaussianBlur medianBlur bilateralFilter 原理 No ...
- OpenCV腐蚀和膨胀Eroding and Dilating
OpenCV腐蚀和膨胀Eroding and Dilating 腐蚀和膨胀Eroding and Dilating 目标 形态运算 膨胀 侵蚀 代码 解释 腐蚀功能 膨胀功能 结果 腐蚀和膨胀Erod ...
- OpenCV学习笔记(八):形态学morpholgy(2):开/闭运算,形态学梯度、顶帽/黑帽morphologyEx()
OpenCV学习笔记(八):形态学morpholgy(2):开.闭运算,形态学梯度.顶帽.黑帽:morphologyEx() 数学形态学(Mathematical morphology) 是一门建立在 ...
- 形态学滤波:(1)腐蚀与膨胀 (2)开运算,闭运算,形态学梯度,顶帽,黑帽...
一.形态学概述 图像处理中的形态学一般指的是数学形态学. 数学形态学是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论.其基本运算包括:二值腐蚀和膨胀,二值开闭运算,骨架抽 ...
- python+OpenCv笔记(七):图像的形态学操作(腐蚀与膨胀、开闭运算、礼帽与黑帽)
一.腐蚀与膨胀 腐蚀就是原图中高亮的部分被蚕食,效果图拥有比原图更小的高亮区域. 腐蚀的作用是:消除物体边界点,使目标缩小,可以消除小于结构元素的噪声点. 膨胀就是使原图中高亮的部分扩张,效果图拥有比 ...
- Open_CV形态学运算专题 (腐蚀膨胀、开闭运算、梯度运算、顶帽运算黑帽运算 )【Python-Open_CV系列(十)】
Open_CV形态学运算专题 之 腐蚀&膨胀.开&闭运算.梯度运算.顶帽运算黑帽运算 [Python-Open_CV系列(十)] 文章目录 1. 腐 ...
- C# EMGU 3.4.1学习笔记(三)综合示例:形态学滤波(腐蚀/膨胀、开运算/闭运算、顶帽运算/黑帽运算)
以下是<OpenCV3编程入门>中6.4.9的示例程序的C# + EMGU 3.4.1版: 有任何问题或疑问,欢迎交流探讨. using System; using System.Coll ...
- OpenCV形态学变换函数morphologyEx()黑帽运算的使用
OPenCV版本:4.4 IDE:VS2017 功能描述 简述:执行先进的形态学的变换的黑帽运算. 函数 cv::morphologyEx使用腐蚀和膨胀的作为基本的操作来进行高级的形态学的变换. 任何 ...
最新文章
- 动画requestAnimationFrame
- linux flush 保证 磁盘,linux cache介绍及控制
- Qt C++属性类型提供给 QML调用(三)
- iis8.5 php mysql_Win2012 R2 IIS8.5+PHP(FastCGI)+MySQL运行环境搭建教程
- python生成元组_python 列表生成、元组、字典
- java的类属性默认有this 但容易与参数重名 所以需要显性的加上this 以分区别
- 爬虫项目之豆瓣电影排行榜前10页
- VS code 调试配置01 Debugging
- 重构真的能提高代码质量吗?
- pyqt5 qwidget 边框_实战PyQt5: 116-画刷类QBrush
- CSS中expression怎么用? CSS expression详解
- Win10无法访问Ubuntu18.04的smb解决
- 如何写好PRD文档?
- NDTTS-II变压器综合试验系统
- 送抖音直播云挤地铁教程
- VS2015程序出现缺少dll文件解决方法
- 李俊计算机哈佛大学,李俊-中国科学院大学-UCAS
- porphet论文_时间序列神器之争:Prophet VS LSTM
- ImportError: DLL load failed while importing _ctypes conda
- 实分析笔记(1):康托尔基数理论
热门文章
- python海龟画笔如何运行_Python海龟绘图:turtle的简单使用
- python列表元素交换位置_python删除列表元素5种方法,你会的是错误法还是最优解?...
- C语言指针(就做个笔记)
- java json发送文件_关于java:REST API设计在同一请求中将JSON数据和文件发送到api...
- Python,OpenCV图像处理超好用的工具包imutils
- C++:多线程中的小白(2)线程启动、结束、创建线程、join、detach
- LabVIEW图像分割算法(基础篇—6)
- java 类定义_JAVA类与对象(二)----类定义基础
- cordova版本更新_ionic4 APP版本更新
- ADPRL - 近似动态规划和强化学习 - Note 7 - Approximate Dynamic Programming