腐蚀和膨胀 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之膨胀与腐蚀的更多相关文章

  1. opencv 形态学膨胀和腐蚀以及开运算和闭运算

  2. 图像的膨胀与腐蚀——OpenCV与C++的具体实现

    目录 1. 膨胀与腐蚀的原理 2. 膨胀的具体实现 1) OpenCV实现 2) C/C++实现 3) 验证与结果 3. 腐蚀的具体实现 1. 膨胀与腐蚀的原理 膨胀与腐蚀是数学形态学在图像处理中最基 ...

  3. OpenCV——图像处理入门:膨胀与腐蚀、图像模糊、边缘检测

    全部外部依赖项: opencv_aruco341d.lib opencv_bgsegm341d.lib opencv_calib3d341d.lib opencv_bioinspired341d.li ...

  4. OpenCV膨胀与腐蚀

    膨胀与腐蚀 本篇博客主要介绍使用OpenCV中的函数接口实现对一个图片的腐蚀或者膨胀,听起来有点像是对图像进行放大和缩小的意思,如果你也是这样认为,那我只能说你跟我一样肤浅!!在OpenCV中几乎所有 ...

  5. OpenCV图像处理篇之腐蚀与膨胀

    转载请注明出处:http://xiahouzuoxin.github.io/notes 腐蚀与膨胀 腐蚀和膨胀是图像的形态学处理中最主要的操作,之后遇见的开操作和闭操作都是腐蚀和膨胀操作的结合运算. ...

  6. OpenCV膨胀和腐蚀示例代码

    #include<cv.h> #include<highgui.h> int main(int argc, char** argv) { IplImage* img = cvL ...

  7. 学习 opencv---(9)形态学图像处理(一):膨胀和腐蚀

    本篇文章中,我们一起探究了图像处理中,最基本的形态学运算--膨胀与腐蚀.浅墨在文章开头友情提醒,用人物照片做腐蚀和膨胀的素材图片得到的效果会比较惊悚,毁三观的,不建议尝试.......... 一.理论 ...

  8. Atitit 图像处理—图像形态学(膨胀与腐蚀)

    Atitit 图像处理-图像形态学(膨胀与腐蚀) 1.1. 膨胀与腐蚀1 1.2. 图像处理之二值膨胀及应用2 1.3. 测试原理,可以给一个5*5pic,测试膨胀算法5 1.4. Photoshop ...

  9. paper 76:膨胀、腐蚀、开、闭运算——数字图像处理中的形态学

    膨胀.腐蚀.开.闭运算是数学形态学最基本的变换.本文主要针对二值图像的形态学膨胀:把二值图像各1像素连接成分的边界扩大一层(填充边缘或0像素内部的孔):腐蚀:把二值图像各1像素连接成分的边界点去掉从而 ...

随机推荐

  1. PAT L1-043. 阅览室

    L1-043. 阅览室 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 天梯图书阅览室请你编写一个简单的图书借阅统计程序.当读者 ...

  2. 【Offer】[63] 【股票的最大利润】

    题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少? 例如,一只股票在某些时间节点的价格为{9, ...

  3. debug 模式缓慢

    debug 模式启动服务器,然后在 breakopints下可以看到打的断点.清除全部重启服务器,问题解决.

  4. 013 turtle程序语法元素分析

    目录 一.概述 二.库引用与import 2.1 库引用 2.2 使用from和import保留字共同完成库引用 2.3 两种库引用方法比较 2.4 使用import和as保留字共同完成库引用 三.t ...

  5. Navicate for mysql如何导入一个sql文件

    我在做的项目是宜立方商城的项目,现在需要把见表的sql文件导入到navicate中去,步骤如下: ①新建一个数据库,如下: ②在数据库名字上右键,选择运行sql文件 ③选择如下sql文件 ④刷新之后:

  6. C# 表达式树分页扩展(三)

    一.前言 前面我们知道了表达树的基本知识,也明白了怎么遍历和修改一个表达式,这里我们就一个实际的场景来进行功能开发. 表达式系列目录 C# 表达式树讲解(一) C# 表达式树遍历(二) C# 表达式树 ...

  7. Android数据列表展示之 RecylerView

    一.概述 1.RecyclerView是什么? RecyclerView是一种新的视图组,目标是为任何基于适配器的视图提供相似的渲染方式.该控件用于在有限的窗口中展示大量数据集,它被作为ListVie ...

  8. 大数据平台搭建 - cdh5.11.1 - hue安装及集成其他组件

    一.简介 hue是一个开源的apache hadoop ui系统,由cloudear desktop演化而来,最后cloudera公司将其贡献给了apache基金会的hadoop社区,它基于pytho ...

  9. Java8虚拟机(JVM)内存溢出实战

    前言 相信很多JAVA中高级的同学在面试的时候会经常碰到一个面试题 你是如何在工作中对JVM调优和排查定位问题的? 事实上,如果用户量不大的情况下,在你的代码还算正常的情况下,在工作中除非真正碰到与J ...

  10. netty源码解解析(4.0)-22 ByteBuf的I/O

        ByteBuf的I/O主要解决的问题有两个: 管理readerIndex和writerIndex.这个在在AbstractByteBuf中解决. 从内存中读写数据.ByteBuf的不同实现主要 ...