形态学图像处理
- 一、基础知识
- 1.1 什么是形态学操作
- 二、腐蚀与膨胀
- 2.1 腐蚀
- 2.2 膨胀
- 三、开操作与闭操作
- 3.1 开操作
- 3.2 闭操作
- 3.3 实验对比
- 四、一些基本的形态学算法
- 4.1边界提取
- 4.2空洞填充
- 4.3 凸壳
一、基础知识
1.1 什么是形态学操作
数字图像处理中的形态学操作是一组用于处理二值图像(通常是黑白图像)的数学操作,旨在改变图像中物体的形状和结构。形态学操作通常用于图像分割、去噪、特征提取和形状分析等应用中。
二、腐蚀与膨胀
设有两幅图象B,X。若X是被处理的对象,而B是用来处理X的,则称B为结构元素(structure element),又被形象地称做刷子。结构元素通常都是一些比较小的图象。
2.1 腐蚀
腐蚀操作用于减小图像中物体的大小。它将一个结构元素与原始图像卷积,使物体边缘逐渐减小,可以用于去除小噪点或分离邻近物体。
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 将图片转成二值图像
def img2binary_img(img):
param = 177
binary_img = np.ones(img.shape[0:2])
binary_img[img<177] = 0
return binary_img
# 执行腐蚀操作
def img_erode(binary, kernel_size):
#可以修改卷积核大小来增加腐蚀效果,越大腐蚀越强
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(kernel_size,kernel_size))
dst = cv2.erode(binary,kernel)
return dst
img = cv2.imread("img/image.jpg",0)
binary_img = img2binary_img(img)
erode_img_5 = img_erode(binary_img, 5)
erode_img_7 = img_erode(binary_img, 7)
erode_img_9 = img_erode(binary_img, 9)
通过设定不同的滤波器大小,可以发现滤波器尺寸越大,图片中的白色区域越小,反之亦然。
2.2 膨胀
膨胀操作用于增加图像中物体的大小。它将一个结构元素(通常是一个小的二值图像或核)与原始图像进行卷积操作,将物体边缘扩张,增加其面积。该过程可以看做是腐蚀的逆操作。
# 将图片转成二值图像
def img2binary_img(img):
param = 177
binary_img = np.ones(img.shape[0:2])
binary_img[img<177] = 0
return binary_img
# 执行膨胀操作
def img_dilate(binary, kernel_size):
#可以修改卷积核大小来增加膨胀效果,越大膨胀越强
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(kernel_size,kernel_size))
dst = cv2.dilate(binary,kernel)
return dst
img = cv2.imread('img/image.jpg',0)
binary_img = img2binary_img(img)
erode_img_5 = img_dilate(binary_img, 5)
erode_img_7 = img_dilate(binary_img, 7)
erode_img_9 = img_dilate(binary_img, 9)
可以发现卷积核越大,图像的白色区域越大。腐蚀可以去除图像中的噪声,但是会导致图片变小对于腐蚀后的图像进行膨胀处理可以在去除噪声的同时保持原有形状。
三、开操作与闭操作
开操作闭操作简称开闭运算,即开操作=开运算;闭操作=闭运算。说白了就是打腐蚀和膨胀的组合拳。 为什么有了膨胀、腐蚀还要开运算闭运算呢? 其实开闭运算最重要的一点就是,可以保持物体原有大小。然后一个是消除物体外部噪声(开运算)的另一个是增强物体之间连接点(闭运算)的。
3.1 开操作
开运算=腐蚀+膨胀
3.2 闭操作
闭运算 = 膨胀+腐蚀
3.3 实验对比
def img2binary_img(img):
param = 177
binary_img = np.ones(img.shape[0:2])
binary_img[img<177] = 0
return binary_img
img = cv2.imread('img/morph_close.png',0)
binary_img = img2binary_img(img)
kernel = np.ones((5,5),np.uint8)
open_img = cv2.morphologyEx(binary_img, cv2.MORPH_OPEN, kernel)
close_img = cv2.morphologyEx(binary_img, cv2.MORPH_CLOSE, kernel)
根据实验结果可以看出来开运算对于孤立的小点,毛刺等现象,整体形状与位置不会发生太大的变化。而闭运算可以填充小裂缝。
四、一些基本的形态学算法
当处理二值图像时,形态学的主要应用是提取表示和描述形状的有用成分。特别是用形态学方法提取某一区域边界线,连接成分,骨骼,凸壳的算法是十分有效的。此外,区域填充,细化,加粗,裁剪等处理方法也经常与上述算法相结合在预处理和后处理中使用。
4.1边界提取
与边缘检测类似,可以使用canny等边缘检测算法实现:
img = cv2.imread("img/image.jpg",0)
blurred = cv2.GaussianBlur(img,(11,11),0)
gaussImg = cv2.Canny(blurred, 10, 70)
4.2空洞填充
使用空洞填充,可以对图像进行填充。使用函数为泛洪函数。原型为:cv2.floodFill(img, mask, seed, newvalue(BGR), (loDiff1, loDiff2, loDiff3), (upDiff1, upDiff2, upDiff3), flag)
- img:为待使用泛洪算法的图像
- mask:为掩码层,使用掩码可以规定是在哪个区域使用该算法,如果是对于完整图像都要使用,则掩码层大小为原图行数+2,列数+2.是一个二维的0矩阵,边缘一圈会在使用算法是置为1。而只有对于掩码层上对应为0的位置才能泛洪,所以掩码层初始化为0矩阵。【dtype:np.uint8】
- seed:为泛洪算法的种子点,也是根据该点的像素判断决定和其相近颜色的像素点,是否被泛洪处理。
- newvalue:是对于泛洪区域新赋的值(B,G,R)
- (loDiff1,loDiff2,loDiff3):是相对于seed种子点像素可以往下的像素值,即seed(B0,G0,R0),泛洪区域下界为(B0-loDiff1,G0-loDiff2,R0-loDiff3)
- (upDiff1,upDiff2,upDiff3):是相对于seed种子点像素可以往上的像素值,即seed(B0,G0,R0),泛洪区域上界为(B0+upDiff1,G0+upDiff2,R0+upDiff3)
- flag:为泛洪算法的处理模式。
如下图所示使用泛洪函数简单对彩色图像进行填充:
img = cv2.imread("img/image.jpg")
img = img[:, :, [2, 1, 0]]
im_floodfill = img.copy()
h, w = img.shape[:2]
mask = np.zeros((h+2, w+2), np.uint8)
cv2.floodFill(im_floodfill, mask, (220, 250), (0, 255, 255), (100, 100, 100), (50, 50 ,50), cv2.FLOODFILL_FIXED_RANGE)
4.3 凸壳
凸壳是一个包含给定点集中所有点的最小凸多边形或多面体。这个凸多边形或多面体的特点是,任何两点都在它的内部或边界上,而不在外部。