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 ...
随机推荐
- 使用python的虚拟环境virtualenv
技术背景 在前面几篇博客中我们介绍了容器的使用(博客1.博客2.博客3.博客4.博客5),容器是一种系统级的隔离方案,更多的强调资源上的隔离.而这里我们要介绍的python的虚拟环境,更加强调的是依赖 ...
- 使用Gensim库对文本进行词袋、TF-IDF和n-gram方法向量化处理
Gensim库简介 机器学习算法需要使用向量化后的数据进行预测,对于文本数据来说,因为算法执行的是关于矩形的数学运算,这意味着我们必须将字符串转换为向量.从数学的角度看,向量是具有大小和方向的几何对象 ...
- day-01-初识Python与条件判断
cpu 内存 硬盘 操作系统 cpu:计算机的运算和计算中心,相当于人类大脑.飞机 内存:暂时存储数据,临时加载数据应用程序,4G,8G,16G,32G 速度快,高铁,断电即消失.造价很高 ...
- ON DUPLICATE KEY UPDATE作用
ON DUPLICATE KEY UPDATE作用 先声明一点,ON DUPLICATE KEY UPDATE为Mysql特有语法,这是个坑 语句的作用,当insert已经存在的记录时,执行Updat ...
- java面试-公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解
一.公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解 公平锁:多个线程按照申请的顺序来获取锁. 非公平锁:多个线程获取锁的先后顺序与申请锁的顺序无关.[ReentrantLock 默认非公平.s ...
- Java基础 Java-IO流 深入浅出
建议阅读 重要性由高到低 Java基础-3 吃透Java IO:字节流.字符流.缓冲流 廖雪峰Java IO Java-IO流 JAVA设计模式初探之装饰者模式 为什么我觉得 Java 的 IO 很复 ...
- C语言-内存函数的实现(一)之memcpy
C语言中的内存函数有如下这些 memcpy memmove memcmp memset 下面看看memcpy函数 memcpy 我们想想,之前有那个字符串拷贝的函数,即strcpy函数.都有拷贝的函数 ...
- Selenium 3 常用 API
元素定位 获取页面元素属性 元素判断 元素操作 操作输入框/单击 双击 下拉框操作 键盘操作 鼠标操作 单选框操作 多选框操作 拖动窗口 操作 JS 框 切换 frame 使用 JS 操作页面对象 操 ...
- 爬虫简介、requests 基础用法、urlretrieve()
1. 爬虫简介 2. requests 基础用法 3. urlretrieve() 1. 爬虫简介 爬虫的定义 网络爬虫(又被称为网页蜘蛛.网络机器人),是一种按照一定的规则,自动地抓取万维网信息的程 ...
- F - Lakes in Berland(BFS)
The map of Berland is a rectangle of the size n × m, which consists of cells of size 1 × 1. Each cel ...