opencv——形态学深究(分析和应用)
摘要:
形态学一般指生物学中研究动物和植物结构的一个分支。用数学形态学(也称图像代数)表示以形态为基础对图像进行分析的数学工具。
基本思想是用具有一定形态的结构元素去度量和提取图像中的对应形状以达到对图像分析和识别的目的。
形态学图像处理的基本运算有:
- 膨胀和腐蚀(膨胀区域填充,腐蚀分割区域)
- 开运算和闭运算(开运算去除噪点,闭运算填充内部孔洞)
- 击中与击不中
- 顶帽变换,黑帽变换
形态学的应用:消除噪声、边界提取、区域填充、连通分量提取、凸壳、细化、粗化等;分割出独立的图像元素,或者图像中相邻的元素;求取图像中明显的极大值区域和极小值区域;求取图像梯度
在讲各种形态学操作之前,先来看看结构元素:
膨胀和腐蚀操作的核心内容是结构元素。(后面的开闭运算等重要的也是结构元素的设计,一个合适的结构元素的设计可以带来很好的处理效果)
OpenCV里面的API介绍:
Mat kernel = getStructuringElement(int shape,Size ksize,Point anchor);
shape //结构元素的定义:形状 (MORPH_RECT \MORPH_CROSS(交叉形) \MORPH_ELLIPSE);
ksize //结构元素大小;
anchor //锚点 默认是Point(-1, -1)意思就是中心像素,也可以自己指定
一,腐蚀和膨胀
腐蚀和膨胀是最基本的形态学操作,腐蚀和膨胀都是针对白色部分(高亮部分)而言的。
- 膨胀就是使图像中高亮部分扩张,效果图拥有比原图更大的高亮区域(是求局部最大值的操作)
- 腐蚀是原图中的高亮区域被蚕食,效果图拥有比原图更小的高亮区域(是求局部最小值的操作)
膨胀与腐蚀能实现多种多样的功能,主要如下:
1、消除噪声
2、腐蚀分割(isolate)出独立的图像元素,膨胀在图像中连接(join)相邻的元素。
3、寻找图像中的明显的极大值区域或极小值区域
4、求出图像的梯度
opencv中膨胀/腐蚀API:(两者相同)
void dilate/erode( const Mat& src, //输入图像(任意通道的)
Mat& dst, //输出图像
const Mat& element, //结构元素
Point anchor=Point(-1,-1), //中心位置锚点
int iterations=1, //操作次数。省略时为默认值1。
int borderType=BORDER_CONSTANT, //边缘填充类型
const Scalar& borderValue //填充值(默认即可)
)
opencv实现:
Mat src1 = imread("D:/opencv练习图片/腐蚀膨胀.png");
Mat src_erode, src_dilate;
imshow("原图", src1);
Mat kernel = getStructuringElement(MORPH_RECT, Size(60, 60), Point(-1, -1));
erode(src1, src_erode, kernel, Point(-1, -1),2);
dilate(src1, src_dilate, kernel, Point(-1, -1),2);
imshow("腐蚀", src_erode);
imshow("膨胀", src_dilate);
膨胀: 腐蚀:
1️⃣腐蚀操作的原理就是求局部最小值的操作,并把这个最小值赋值给参考点指定的像素。这样就会使图像中的高亮区域逐渐减少。
2️⃣膨胀操作的原理就是求局部最大值的操作,并把这个最大值赋值给参考点指定的像素。这样就会使图像中的高亮区域逐渐增长。
二,高阶形态学变换
对于更加高级形态学变换就要用到morphologyEx()函数了,其函数原型如下:
void morphologyEx(
InputArray src, //输入图像
OutputArray dst, //输出图像
int op, //形态学运算类型
InputArray kernel, //结构元素
Point anchor = Point(-1,-1), //锚点
int iterations = 1, //运算次数
int borderType = BORDER_CONSTANT,
)
对于输入参数op(形态学运算类型)有以下几种参数可以设置:
- MORPH_ERODE(腐蚀)
- MORPH_DILATE(膨胀)
- MORPH_OPEN(开运算)
- MORPH_CLOSE(闭运算)
- MORPH_GRADIENT(形态学梯度,即膨胀图减腐蚀图)
- MORPH_TOPHAT(顶帽运算)
- MORPH_BLACKHAT(底帽运算)
- MORPH_HITMISS(击中与击不中)
开运算和顶帽运算
开运算就是先腐蚀膨胀。作用:用来消除图像中细小对象,在纤细点处分离物体和平滑较大物体的边界而有不明显改变其面积和形状。
顶帽运算就是求原图与原图的开运算的差值图像。作用:由于开运算可以消除较暗背景下的较亮区域,那么用原图减开运算后的结果就可以得到原图中灰度较亮的区域(即得到开运算消除的区域)
opencv实现:
Mat src1 = imread("D:/opencv练习图片/开运算.png");
Mat src_open, src_tophat;
imshow("原图", src1);
Mat kernel = getStructuringElement(MORPH_RECT, Size(7, 7), Point(-1, -1));
morphologyEx(src1, src_open, MORPH_OPEN, kernel,Point(-1, -1));//开运算
morphologyEx(src1, src_tophat, MORPH_TOPHAT, kernel, Point(-1, -1));//顶帽运算
imshow("开运算", src_open);
imshow("顶帽运算", src_tophat);
开运算: 顶帽运算:(可以用来观察开运算的效果)
闭运算和底帽运算
闭运算就是先膨胀后腐蚀。作用:用来填充目标内部的细小孔洞(fill hole),将断开的邻近目标连接,在不明显改变物体面积和形状的情况下平滑其边界。
底帽运算就是求原图与原图的闭运算的差值图像。作用:闭运算是去噪点的过程,所以黑帽操作实质上保留的是噪点的部分。
opencv实现:
Mat src1 = imread("D:/opencv练习图片/闭运算.png");
Mat src_close, src_blackhat;
imshow("原图", src1);
Mat kernel = getStructuringElement(MORPH_RECT, Size(7, 7), Point(-1, -1));
morphologyEx(src1, src_close, MORPH_CLOSE, kernel,Point(-1, -1));//闭运算
morphologyEx(src1, src_blackhat, MORPH_BLACKHAT, kernel, Point(-1, -1));//底帽运算
imshow("闭运算", src_close);
imshow("底帽运算", src_blackhat);
闭运算: 底帽运算:
形态学梯度(求二值图边缘)
图像形态学的梯度跟我们前面介绍的图像卷积计算出来的梯度有本质不同,形态学梯度可以帮助我们获得连通组件的边缘与轮廓,实现图像轮廓或者边缘提取。
根据使用的形态学操作不同,形态学梯度又分为:
- 基本梯度(图像膨胀与腐蚀操作之间的差值)
- 内梯度(输入图像与腐蚀之间的差值)
- 外梯度(膨胀与输入图像之间的差值)
opencv实现:
Mat src1 = imread("D:/opencv练习图片/腐蚀膨胀.png");
Mat src_giad1, src_exter,src_inter,src_dilate,src_erode;
imshow("原图", src1);
Mat kernel = getStructuringElement(MORPH_RECT, Size(7, 7), Point(-1, -1));
//基本梯度
morphologyEx(src1, src_giad1, MORPH_GRADIENT, kernel,Point(-1, -1));
imshow("基本梯度", src_giad1);
//外梯度
morphologyEx(src1, src_dilate, MORPH_DILATE, kernel, Point(-1, -1));
subtract(src_dilate, src1, src_exter);//求差值
imshow("外梯度", src_exter);
//内梯度
morphologyEx(src1, src_erode, MORPH_ERODE, kernel, Point(-1, -1));
subtract(src1, src_erode, src_inter);
imshow("内梯度", src_inter);
外梯度: 内梯度:
内外梯度区别不是很大。。。
击中与击不中
形态学的击中击不中操作, 击中击不中也是基础形态学操作组合,它可以实现对象的细化跟剪枝操作,根据结构元素不同,可以提取二值图像中的一些特殊区域,得到我们想要的结果。并且击中击不中操作在二值图像的模式匹配跟发现上也非常有用
Hit-miss算法步骤(两次腐蚀,求交集):
击中击不中变换是形态学中用来检测特定形状所处位置的一个基本工具。它的原理就是使用腐蚀;如果要在一幅图像A上找到B形状的目标,我们要做的是:
- 首先,建立一个比B大的结构元素B1;使用B1对图像A进行腐蚀,得到图像假设为A_B1;
- 其次,用B减去B1,从而得到结构元素B2(B2-B);使用B2对图像A的补集进行腐蚀,得到图像假设为A_B2;
- 然后,A_B1与A_B2取交集;得到的结果就是B的位置。
opencv实战(利用击中与击不中,提取网绳的结点位置):
Mat src = imread("D:/opencv练习图片/击中与击不中.png");
imshow("原图", src);
// 二值图像
Mat gray, binary, hitImg;
cvtColor(src, gray, COLOR_BGR2GRAY);
//高斯滤波
Mat gauss;
GaussianBlur(gray, gauss, Size(5, 5), 0, 0);
//二值化
threshold(gauss, binary, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
imshow("binary", binary);
// 定义结构元素
Mat se = getStructuringElement(MORPH_CROSS, Size(11, 11), Point(-1, -1));
// 击中击不中
morphologyEx(binary, hitImg, MORPH_HITMISS, se);
imshow("击中击不中", hitImg);
//膨胀一下
Mat openImg;
Mat kern2 = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(hitImg, openImg, MORPH_OPEN, kern2, Point(-1, -1), 2);
imshow("dilate", openImg);
//寻找轮廓
vector<vector<Point>>contours;
vector<Vec4i>hie;
findContours(openImg, contours, hie, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
for (size_t i = 0; i < contours.size(); i++)
{
double area = contourArea(contours[i]);
if (area < 20.0)continue;
Rect rect = boundingRect(contours[i]);
rectangle(src, rect, Scalar(0, 0, 255), 1, 8); }
// 显示
imshow("结果", src);
参考链接:(8条消息) Opencv图像识别从零到精通(18)-------击中击不中_小木匠的博客-CSDN博客
OpenCV中一个最容易搞错的形态学操作 - 云+社区 - 腾讯云 (tencent.com)
opencv——形态学深究(分析和应用)的更多相关文章
- [OpenCV-Python] OpenCV 中视频分析 部分 VI
部分 VI视频分析 OpenCV-Python 中文教程(搬运)目录 39 Meanshift 和 和 Camshift 目标 • 本节我们要学习使用 Meanshift 和 Camshift 算法在 ...
- OpenCV源码分析:RGB到其他色彩空间的转换
1.流程调用图 2.部分代码分析 //模板函数进行颜色空间的转换 template <typename Cvt> void CvtColorLoop(const Mat& src, ...
- opencv face-detection 代码分析 (1)人脸识别后的数据
2014,3,16 老师的工作建议如下: 1. 与四民沟通下,把openCV这边的源代码和调用接口发给四民同时抄送给我. 2. 根据openCV的实时检测结果,实现对屏幕的调整(下周一前基本实 ...
- OPENCV形态学算法-2
一.漫水填充算法 该算法通过一个指定的种子点,来分析整张图片上的像素,并设置像素差异阈值,在阈值类的点,最后变成相同的颜色.该方法通过上下限和连通方式来达到不同的连通效果. 该方法常用与标记和分离图像 ...
- OPENCV形态学操作1
形态学操作是指基于形状的一系列图像处理操作,包括膨胀,腐蚀,二值化,开运算,闭运算,顶帽算法,黑帽算法,形态学梯度等,最基本的形态学操作就是膨胀和腐蚀. 一.膨胀 首先需要明确一个概念,膨胀和腐蚀都是 ...
- opencv 形态学操作应用-提取水平与垂直线
adaptiveThreshold(~gray_src, binImg, , ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, , -); #include <ope ...
- opencv::形态学操作
形态学操作 开操作- open 闭操作- close 形态学梯度- Morphological Gradient 顶帽 – top hat 黑帽 – black hat 开操作- open 先腐蚀后膨 ...
- 基于OpenCV.Net连通域分析进行文本块分割
上一次通过投影的方式进行了文本块分割,(见 https://www.cnblogs.com/BoyTNT/p/11812323.html )但这种方法有很大的局限性,要求分行清晰.不能有字符跨多行.不 ...
- OpenCV常用函数分析
1. 聚类:将拥有最相似属性的数据归为一类. K-means聚类: python调用格式:compacness, labels, centers = cv2.kmeans(data, K, crite ...
随机推荐
- 【MCU】移植AT32库&FreeRTOS教程
目录 前言 1. 移植AT库 1.1 移植内核相关文件 1.2 移植芯片型号相关文件 1.3 移植芯片外设驱动库 1.4 移植配置文件及中断回调函数文件 2. 移植FreeRTOS源码 2.1 获取 ...
- python3使用kivy生成安卓程序
技术背景 虽然现在苹果占据了很大一部分的市场,但是从销量数据来看,安卓还是占据了人口的高地.这里我们介绍一个用python的kivy+buildozer来进行安卓APP开发的简单教程,从整个过程中来看 ...
- Python简单实现杨辉三角
n=input("请输入要打印的行数")n=int(n)for x in range(0,n+1): p=1 print(''.rjust(n-x),end="" ...
- Java【IO流、字节流、字符流】
1.内存是临时存储 Input输入(读取) output输出(输出) 流:数据(字符字节)1个字符=2个字节 1个字节=8个二进制位 输入:把硬盘中的数据读取到内存中 输出:把内存中的数据写入到硬盘中 ...
- dubbo的spi思想是什么?
spi,简单来说,就是service provider interface,说白了是什么意思呢,比如你有个接口,现在这个接口有3个实现类,那么在系统运行的时候对这个接口到底选择哪个实现类呢?这就需要s ...
- Day09_41_集合_Set
Set集合 Set集合 - Set集合的特点是无序不可重复.Set集合类似于一个罐子,程序可以依次把多个对象"丢进"Set集合,而Set集合通常不能记住元素的添加顺序. - Set ...
- Apache HTTP Server与Tomcat整合学习记录
Apache HTTP Server与Tomcat整合 个人环境:Windows10,JDK8,Tomcat8.5,Apache2.4,JK模块1.2.4 前言 其实网上有很多教程,但问题是得每次 ...
- vue中利用.env文件存储全局环境变量,以及配置vue启动和打包命令
目录 1,前言 2,.env文件的作用 3,配置.env文件 4,配置启动命令 5,获取.env中的全局变量 5,实际用处 1,前言 分享一下vue项目中利用.env文件存储全局环境变量,以及利于项目 ...
- OO第一单元总结——求导
一.基于度量分析程序结构 (一)第一次作业 (1)设计思路 本次作业只涉及到简单幂函数通过加减运算而复合而成的函数,因此笔者自然的把函数分成了函数本体以及单个的项两个部分,在笔者的设计中两个类的功能如 ...
- 基于MATLAB的手写公式识别(7)
今天晚上通过对原有T4模型的修改实现: 1.可以识别真彩图形.(这基本是一样大的,通过这个了解图像分割的原理) 2.在识别心脑管血药类的基础上实现数字的识别.(了解图像识别原理,熟练掌握图像分割技术) ...