c 语言编腐蚀膨胀程序,opencv之膨胀与腐蚀

腐蚀和膨胀 Erosion/Dilation

erosion/dilation,用白话说,就是让图像亮的区域收缩和扩张.

原理

我们定义一个卷积核矩阵.这个矩阵可以是任何形状的,但通常而言,是矩形或者圆形的.同时要定义一个锚点位置.

用这个卷积核矩阵挨个地划过原始图像矩阵,同时更改锚点位置的像素值.

锚点位置的像素值更改为卷积核矩阵覆盖的有效像素值中的最大值/最小值(分别对应膨胀/腐蚀).

什么叫"有效"像素值呢?就是卷积核中不为0的那些位置.用公式表达的话,即:

b5b34703e3509160b314cda6237c421d.png

09bbb2edb66e366b482372525dadd991.png

膨胀和腐蚀,说白了就是个求"卷积核所表示的局部"的最大值最小值的过程.

我们来看一个例子:

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

a85363694bdf0db493181949bdcd3452.png

三个参数分别为卷积核的形状/大小/锚点位置. 默认锚点在矩阵的中心位置.

形状有三种

49f43b99d1ba8b3e39d3ab7c70674b9b.png

上面代码中我们创建的3 x 3矩形卷积核如下

2b97c0fac640a84d7c008aee3f937172.png

用这个卷积核对原始图像做腐蚀后得到的矩阵如下

0232f3db570556ddf553341f666030a5.png

即矩阵有如下变化:

[[ 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如下:

1d5be6680c00b7f0158f0c6ea96233cf.png

以第四行,第五列的像素为例,用卷积核的锚点与之对应,此时计算的是其周围八个像素的最小值,最小值为0.

所以我们得到的矩阵为

8392f68efbc139bc67cff5e4fbc87ca3.png

当我们用kernal2时,kernal2如下:

2a8e132c4e8a3d4bd9ac1327372de015.png

对第四行,第五列的像素,用卷积核的锚点与之对应,此时计算的不再是周围八个像素的最小值,而是其正上方,正下方,正左边,正右边的四个像素的最小值.该值为100.

所以我们得到的矩阵为

489e9f0262c519fe8929440d3504bd46.png

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)

原始图片:

e25796d31b47e6c8863124fd21c56ea8.png

处理效果:

ae5d1a805200a72ed4b18117aca63bc3.png

opencv实现

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[opencv之膨胀与腐蚀]http://www.zyiz.net/tech/detail-92785.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值