opencv之膨胀与腐蚀
腐蚀和膨胀 Erosion/Dilation
erosion/dilation,用白话说,就是让图像亮的区域收缩和扩张.
原理
- 我们定义一个卷积核矩阵.这个矩阵可以是任何形状的,但通常而言,是矩形或者圆形的.同时要定义一个锚点位置.
- 用这个卷积核矩阵挨个地划过原始图像矩阵,同时更改锚点位置的像素值.
- 锚点位置的像素值更改为卷积核矩阵覆盖的有效像素值中的最大值/最小值(分别对应膨胀/腐蚀).
什么叫"有效"像素值呢?就是卷积核中不为0的那些位置.用公式表达的话,即:
膨胀和腐蚀,说白了就是个求"卷积核所表示的局部"的最大值最小值的过程.
我们来看一个例子:
import cv2
import numpy as np
def test1():
img = np.zeros((10,10,1),np.uint8)
img[3:7,3:7,:] = 255
img[4:6,4:6,:] = 200
kernel1 = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
erosion_dst = cv2.erode(img, kernel1)
print(erosion_dst)
首先我们创建一个10 x 10的图像,像素如下:
[[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 255 255 255 255 0 0 0]
[ 0 0 0 255 200 200 255 0 0 0]
[ 0 0 0 255 200 200 255 0 0 0]
[ 0 0 0 255 255 255 255 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]]
我们创建一个卷积核:
kernel1 = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
getStructuringElement api
三个参数分别为卷积核的形状/大小/锚点位置. 默认锚点在矩阵的中心位置.
形状有三种
上面代码中我们创建的3 x 3矩形卷积核如下
用这个卷积核对原始图像做腐蚀后得到的矩阵如下
即矩阵有如下变化:
[[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 255 255 255 255 0 0 0]
[ 0 0 0 255 200 200 255 0 0 0]
[ 0 0 0 255 200 200 255 0 0 0]
[ 0 0 0 255 255 255 255 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]]
-->
[[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 200 200 0 0 0 0]
[ 0 0 0 0 200 200 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]]
我们考虑第三行第四列img[2,3,:]这个像素.当我们的卷积核矩阵的锚点位置与该像素重合时,我们取周边所有像素的最小值.最小值为0.所以该位置的像素值变为0. 其余位置的像素值同理可求.
我们稍微改一下我们的代码,然后再看一下不同卷积核作用下的不同结果,会理解的更清楚
import cv2
import numpy as np
def test1():
img = np.zeros((10,10,1),np.uint8)
img[3:7,3:7,:] = 255
img[4:6,4:6,:] = 200
kernel1 = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
print(kernel1)
erosion_dst = cv2.erode(img, kernel1)
print(erosion_dst)
def test2():
img = np.zeros((10,10,1),np.uint8)
img[3:7,3:7,:] = 255
img[4:6,4:6,:] = 200
img[2,4,:] = 100
kernel1 = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
erosion_dst = cv2.erode(img, kernel1)
print(erosion_dst)
kernel2 = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
erosion_dst2 = cv2.erode(img, kernel2)
print(erosion_dst2)
test2()
我们把原始图像矩阵改为
[[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 100 0 0 0 0 0]
[ 0 0 0 255 255 255 255 0 0 0]
[ 0 0 0 255 200 200 255 0 0 0]
[ 0 0 0 255 200 200 255 0 0 0]
[ 0 0 0 255 255 255 255 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0]]
用kernal1时,kernal1如下:
以第四行,第五列的像素为例,用卷积核的锚点与之对应,此时计算的是其周围八个像素的最小值,最小值为0.
所以我们得到的矩阵为
当我们用kernal2时,kernal2如下:
对第四行,第五列的像素,用卷积核的锚点与之对应,此时计算的不再是周围八个像素的最小值,而是其正上方,正下方,正左边,正右边的四个像素的最小值.该值为100.
所以我们得到的矩阵为
opencv示例
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
erosion_size = 0
max_elem = 2
max_kernel_size = 21
title_trackbar_element_type = 'Element:\n 0: Rect \n 1: Cross \n 2: Ellipse'
title_trackbar_kernel_size = 'Kernel size:\n 2n +1'
title_erosion_window = 'Erosion Demo'
title_dilatation_window = 'Dilation Demo'
def erosion(val):
erosion_size = cv.getTrackbarPos(title_trackbar_kernel_size, title_erosion_window)
erosion_type = 0
val_type = cv.getTrackbarPos(title_trackbar_element_type, title_erosion_window)
if val_type == 0:
erosion_type = cv.MORPH_RECT
elif val_type == 1:
erosion_type = cv.MORPH_CROSS
elif val_type == 2:
erosion_type = cv.MORPH_ELLIPSE
element = cv.getStructuringElement(erosion_type, (2*erosion_size + 1, 2*erosion_size+1), (erosion_size, erosion_size))
erosion_dst = cv.erode(src, element)
cv.imshow(title_erosion_window, erosion_dst)
def dilatation(val):
dilatation_size = cv.getTrackbarPos(title_trackbar_kernel_size, title_dilatation_window)
dilatation_type = 0
val_type = cv.getTrackbarPos(title_trackbar_element_type, title_dilatation_window)
if val_type == 0:
dilatation_type = cv.MORPH_RECT
elif val_type == 1:
dilatation_type = cv.MORPH_CROSS
elif val_type == 2:
dilatation_type = cv.MORPH_ELLIPSE
element = cv.getStructuringElement(dilatation_type, (2*dilatation_size + 1, 2*dilatation_size+1), (dilatation_size, dilatation_size))
dilatation_dst = cv.dilate(src, element)
cv.imshow(title_dilatation_window, dilatation_dst)
src = cv.imread("/home/sc/disk/keepgoing/opencv_test/j.png")
cv.namedWindow(title_erosion_window)
cv.createTrackbar(title_trackbar_element_type, title_erosion_window , 0, max_elem, erosion)
cv.createTrackbar(title_trackbar_kernel_size, title_erosion_window , 0, max_kernel_size, erosion)
cv.namedWindow(title_dilatation_window)
cv.createTrackbar(title_trackbar_element_type, title_dilatation_window , 0, max_elem, dilatation)
cv.createTrackbar(title_trackbar_kernel_size, title_dilatation_window , 0, max_kernel_size, dilatation)
erosion(0)
dilatation(0)
cv.waitKey()
通过createTrackbar在窗口上创建两个bar,方便我们看不同种类不同大小的卷积核的影响.
cv.createTrackbar(title_trackbar_element_type, title_erosion_window , 0, max_elem, erosion)
cv.createTrackbar(title_trackbar_kernel_size, title_erosion_window , 0, max_kernel_size, erosion)
原始图片:
处理效果:
opencv实现
https://github.com/opencv/opencv/blob/master/modules/imgproc/src/morph.dispatch.cpp
opencv之膨胀与腐蚀的更多相关文章
- opencv 形态学膨胀和腐蚀以及开运算和闭运算
- 图像的膨胀与腐蚀——OpenCV与C++的具体实现
目录 1. 膨胀与腐蚀的原理 2. 膨胀的具体实现 1) OpenCV实现 2) C/C++实现 3) 验证与结果 3. 腐蚀的具体实现 1. 膨胀与腐蚀的原理 膨胀与腐蚀是数学形态学在图像处理中最基 ...
- OpenCV——图像处理入门:膨胀与腐蚀、图像模糊、边缘检测
全部外部依赖项: opencv_aruco341d.lib opencv_bgsegm341d.lib opencv_calib3d341d.lib opencv_bioinspired341d.li ...
- OpenCV膨胀与腐蚀
膨胀与腐蚀 本篇博客主要介绍使用OpenCV中的函数接口实现对一个图片的腐蚀或者膨胀,听起来有点像是对图像进行放大和缩小的意思,如果你也是这样认为,那我只能说你跟我一样肤浅!!在OpenCV中几乎所有 ...
- OpenCV图像处理篇之腐蚀与膨胀
转载请注明出处:http://xiahouzuoxin.github.io/notes 腐蚀与膨胀 腐蚀和膨胀是图像的形态学处理中最主要的操作,之后遇见的开操作和闭操作都是腐蚀和膨胀操作的结合运算. ...
- OpenCV膨胀和腐蚀示例代码
#include<cv.h> #include<highgui.h> int main(int argc, char** argv) { IplImage* img = cvL ...
- 学习 opencv---(9)形态学图像处理(一):膨胀和腐蚀
本篇文章中,我们一起探究了图像处理中,最基本的形态学运算--膨胀与腐蚀.浅墨在文章开头友情提醒,用人物照片做腐蚀和膨胀的素材图片得到的效果会比较惊悚,毁三观的,不建议尝试.......... 一.理论 ...
- Atitit 图像处理—图像形态学(膨胀与腐蚀)
Atitit 图像处理-图像形态学(膨胀与腐蚀) 1.1. 膨胀与腐蚀1 1.2. 图像处理之二值膨胀及应用2 1.3. 测试原理,可以给一个5*5pic,测试膨胀算法5 1.4. Photoshop ...
- paper 76:膨胀、腐蚀、开、闭运算——数字图像处理中的形态学
膨胀.腐蚀.开.闭运算是数学形态学最基本的变换.本文主要针对二值图像的形态学膨胀:把二值图像各1像素连接成分的边界扩大一层(填充边缘或0像素内部的孔):腐蚀:把二值图像各1像素连接成分的边界点去掉从而 ...
随机推荐
- codeforces 766 C. Mahmoud and a Message(简单dp)
题目链接:http://codeforces.com/contest/766/problem/C 题意:给你一个长度为n的字符串,这个字符串只包含小写字母,然后让你把这个字符串进行分割,形成若干个小的 ...
- JavaScript new的运行过程
参考 MDN网站的运算符 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new new 运算符 ...
- adb命令介绍
1.adb logcat -v time -s ActivityManager:I 获取包名和activity 2. adb logcat "ActivityManager" |g ...
- Stealth——01场景的基本搭建以及基础逻辑
版权申明: 本文原创首发于以下网站: 博客园『优梦创客』的空间:https://www.cnblogs.com/raymondking123 优梦创客的官方博客:https://91make.top ...
- 虚IP解决AlWaysON读库服务器过保替换
公司核心交易数据库,使用SQL 2012 AlWaysON的1主4从,有2台(8.14,8.15)从库服务器,已经使用3年多,过保替换,新买的2台服务器已经安装好,一开始方案如下: 服务器(8.14) ...
- 【Offer】[23] 【链表中环的入口结点】
题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 一个链表中包含环,如何找出环的入口结点?  思路分析 判断链表中是否有环:用快慢指针的方法,慢指针走一步,快指针走两步,如果快指针追上 ...
- 【LeetCode】[0002] 【两数之和】
题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 给出两个非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字.如果 ...
- JavaScript中的this到底是怎样的?
this是困惑JavaScript开发者的一大‘毒瘤’,在开发过程中,但凡用到this的时候,我们都会很头疼,那么这个this在JavaScript中到底是怎么样的?身为一个前端coder,这是一个避 ...
- CSS精灵图合成工具
链接:http://pan.baidu.com/s/1o7OUUVo 提取密码:rmnx
- 松软科技课堂:SQL-LEFT-JOIN 关键字
SQL LEFT JOIN 关键字 LEFT JOIN 关键字会从左表 (table_name1) 那里返回所有的行,即使在右表 (table_name2) 中没有匹配的行. LEFT JOIN 关键 ...