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 ...
随机推荐
- 封装Vue纵向表头左右结构的table表格
我们前端开发人员在使用表格的过程中,大概率碰到的都是表格头部在表格的最上边,然后呈一行展示,紧接着就是表格的每一行的每一个单元格来展示具体内容的场景,很少会遇到表格的头部呈纵向一行展示,也就是说表格的 ...
- Kubernetes,kubectl常用命令详解
kubectl概述 祭出一张图,转载至 kubernetes-handbook/kubectl命令概述 ,可以对命令族有个整体的概念. 环境准备 允许master节点部署pod,使用命令如下: kub ...
- Java String系列
String详解, String和CharSequence区别, StringBuilder和StringBuffer的区别 (String系列之1) StringBuilder 详解 (String ...
- 一文简述Java IO
Java IO 本文记录了在学习Java IO过程中的知识点,用于复习和快速查阅,不够详细的部分可能会在后续补充. 什么是流 流:内存与存储设备(外存)之间传输数据的通道 IO:输入流输出流(如rea ...
- 【CTF】WDCTF-finals-2017 3-11 writeup
题目来源:WDCTF-finals-2017 题目链接:https://adworld.xctf.org.cn/task/answer?type=misc&number=1&grade ...
- 交换机之间的通信 VLAN和trunk
只有 PC0和PC2可通信,PC1和PC3可通信 将PC0和PC2加入同一个VLAN 将PC1和PC3加入同一个VLAN 将左边的交换机的Fa0/3口开启trunk模式即可(如下图)
- Salesforce学习之路(七)Visualforce结合Reports展示图表
Salesforce作为一款CRM系统,个人觉得最重要的环境便是在于数据的展示和联动,而Salesforce也本身提供了相当强大的功能,Report在展示图表的方面十分强大,前段时间更是宣布以157亿 ...
- 1148 Werewolf - Simple Version
Werewolf(狼人杀) is a game in which the players are partitioned into two parties: the werewolves and th ...
- windows下使用tail -f 命令查看实时日志
经常在linux后台进行日志分析的同学对tail -f 这个命令肯定不陌生了,监控实时系统日志简直不要太方便.但是作为一个自动化测试工程师,我们的代码实际上在本地跑就够了,不需要部署,但是window ...
- 【MybatisPlus】使用Wrappers条件构造器构造or和and
模糊查询中,会有针对一个数据,需要查询数据库的多个字段的情况,例如: 上图中的平台名称和平台进程在数据表中是两个不同的字段, 如果不使用Mybatisplus,仅使用Mybatis,则只有通过写xml ...