图像的膨胀(dilation)和腐蚀(erosion)是两种基本的形态学运算,主要用来寻找图像中的极大区域和极小区域.其中膨胀类似与 '领域扩张' ,将图像的高亮区域或白色部分进行扩张,其运行结果图比原图的高亮区域更大.腐蚀类似 '领域被蚕食' ,将图像中的高亮区域或白色部分进行缩减细化,其运行结果图比原图的高亮区域更小.
膨胀的运算符是“⊕”,其定义如下: 注释:0:黑色,1: 白色;
该公式表示用B来对图像A进行膨胀处理,其中B是一个卷积模板或卷积核,其形状可以为正方形或圆形,通过模板B与图像A进行卷积计算,扫描图像中的每一个像素点,用模板元素与二值图像元素做“与”运算,如果都为0,那么目标像素点为0,否则为1。从而计算B覆盖区域的像素点最大值,并用该值替换参考点的像素值实现膨胀。下图是将左边的原始图像A膨胀处理为右边的效果图A⊕B。 这一步卷积是怎么计算出来得? 带问
完整代码如下所示:
import numpy as np import cv2 as cv #膨胀 #读取图像 img1=cv.imread("oldcat.jpg",0) #将图像进行反向二值化操作,即将白色部分变为黑色,黑色部分变为白色 ret,img2=cv.threshold(img1,80,255,cv.THRESH_BINARY_INV) #定义一个3*3的卷积核 kernel=np.ones((3,3),np.uint8) #图像腐蚀:cv2.dilate(输入图像,卷积核,iterations=腐蚀的次数) dilation=cv.dilate(img2,kernel,iterations=1) #在图像上添加文本,方便分清每个操作相对应的图像 cv.putText(img1,"original",(150,230),cv.FONT_HERSHEY_COMPLEX,1,(0,0,255),2,8) #将原图像和膨胀操作的图像放在同一个窗口显示 glay=np.hstack((img1,dilation)) cv.imshow("glay",glay) cv.waitKey(0) cv.destroyAllWindows()输出结果如下所示:
图像去噪通常需要先腐蚀后膨胀,这又称为开运算.
erosion = cv2.erode(src, kernel) result = cv2.dilate(erosion, kernel)腐蚀的运算符是“-”,其定义如下:
该公式表示图像A用卷积模板B来进行腐蚀处理,通过模板B与图像A进行卷积计算,得出B覆盖区域的像素点最小值,并用这个最小值来替代参考点的像素值。如图所示,将左边的原始图像A腐蚀处理为右边的效果图A-B。
处理结果如下图所示:
图像腐蚀主要使用的函数为erode,其原型如下:
dst = cv2.erode(src, kernel, iterations)参数
dst表示处理的结果,src表示原图像,kernel表示卷积核,iterations表示迭代次数。完整代码如下所示:
#腐蚀 #读取图像 img1=cv.imread("oldcat.jpg") #将图像进行反向二值化操作,即将白色部分变为黑色,黑色部分变为白色 ret,img2=cv.threshold(img1,80,255,cv.THRESH_BINARY_INV) #定义一个3*3的卷积核 kernel=np.ones((3,3),np.uint8) #图像腐蚀:cv2.erode(输入图像,卷积核,iterations=腐蚀的次数) erosion=cv.erode(img2,kernel,iterations=1) #在图像上添加文本,方便分清每个操作相对应的图像 cv.putText(img1,"original",(150,230),cv.FONT_HERSHEY_COMPLEX,1,(0,0,255),2,8) cv.putText(erosion,"erosion",(150,230),cv.FONT_HERSHEY_COMPLEX,1,(0,0,255),2,8) #将原图像和腐蚀操作的图像放在同一个窗口显示 glay=np.hstack((img1,erosion)) cv.imshow("glay",glay) cv.waitKey(0) cv.destroyAllWindows()输出结果如下图所示:
import cv2 as cv import numpy as np def top_hat_demo(image): '顶帽' gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY) #构建形态学元素 提高内核矩阵(10,10)可以提取更多元素 kernel=cv.getStructuringElement(cv.MORPH_RECT,(10,10)) #黑帽处理 dst=cv.morphologyEx(gray,cv.MORPH_TOPHAT,kernel) #如果图像较黑可以用图像增强看看效果 cimage=np.array(gray.shape,np.uint8) cimage=50 dst=cv.add(dst,cimage) cv.imshow('top_hat',dst) def black_hat_demo(image): '黑帽' gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY) #构建形态学元素 提高内核矩阵(10,10)可以提取更多元素 kernel=cv.getStructuringElement(cv.MORPH_RECT,(10,10)) #黑帽处理 dst=cv.morphologyEx(gray,cv.MORPH_BLACKHAT,kernel) #如果图像较黑可以用图像增强看看效果 cimage=np.array(gray.shape,np.uint8) cimage=50 dst=cv.add(dst,cimage) cv.imshow('black_hat',dst) src = cv.imread("girl.jpg") cv.imshow("原来", src) # black_hat_demo(src) top_hat_demo(src) cv.waitKey(0) cv.destroyAllWindows()
凸包是指一个凸多边形,这个凸多边形将图片中所有的白色像素点都包含在内。
函数为:
skimage.morphology.convex_hull_image(image)
输入为二值图像,输出一个逻辑二值图像。在凸包内的点为True, 否则为False
import matplotlib.pyplot as plt from skimage import data,color,morphology #生成二值测试图像 img=color.rgb2gray(data.horse()) img=(img<0.5)*1 chull = morphology.convex_hull_image(img) #绘制轮廓 fig, axes = plt.subplots(1,2,figsize=(8,8)) ax0, ax1= axes.ravel() ax0.imshow(img,plt.cm.gray) ax0.set_title('original image') ax1.imshow(chull,plt.cm.gray) ax1.set_title('convex_hull image')convex_hull_image()是将图片中的所有目标看作一个整体,因此计算出来只有一个最小凸多边形。如果图中有多个目标物体,每一个物体需要计算一个最小凸多边形,则需要使用convex_hull_object()函数。
函数格式:skimage.morphology.convex_hull_object(image, neighbors=8)
输入参数image是一个二值图像,neighbors表示是采用4连通还是8连通,默认为8连通。
import matplotlib.pyplot as plt from skimage import data,color,morphology,feature #生成二值测试图像 img=color.rgb2gray(data.coins()) #检测canny边缘,得到二值图片 edgs=feature.canny(img, sigma=3, low_threshold=10, high_threshold=50) chull = morphology.convex_hull_object(edgs) #绘制轮廓 fig, axes = plt.subplots(1,2,figsize=(8,8)) ax0, ax1= axes.ravel() ax0.imshow(edgs,plt.cm.gray) ax0.set_title('many objects') ax1.imshow(chull,plt.cm.gray) ax1.set_title('convex_hull image') plt.show()在二值图像中,如果两个像素点相邻且值相同(同为0或同为1),那么就认为这两个像素点在一个相互连通的区域内。而同一个连通区域的所有像素点,都用同一个数值来进行标记,这个过程就叫连通区域标记。在判断两个像素是否相邻时,我们通常采用4连通或8连通判断。在图像中,最小的单位是像素,每个像素周围有8个邻接像素,常见的邻接关系有2种:4邻接与8邻接。4邻接一共4个点,即上下左右,如下左图所示。8邻接的点一共有8个,包括了对角线位置的点,如下右图所示。
在skimage包中,我们采用measure子模块下的label()函数来实现连通区域标记。
函数格式:
skimage.measure.label(image,connectivity=None)
参数中的image表示需要处理的二值图像,connectivity表示连接的模式,1代表4邻接,2代表8邻接。
输出一个标记数组(labels), 从0开始标记。
import numpy as np import scipy.ndimage as ndi from skimage import measure,color import matplotlib.pyplot as plt #编写一个函数来生成原始二值图像 def microstructure(l=256): n = 5 x, y = np.ogrid[0:l, 0:l] #生成网络 mask = np.zeros((l, l)) generator = np.random.RandomState(1) #随机数种子 points = l * generator.rand(2, n**2) mask[(points[0]).astype(np.int), (points[1]).astype(np.int)] = 1 mask = ndi.gaussian_filter(mask, sigma=l/(4.*n)) #高斯滤波 return mask > mask.mean() data = microstructure(l=128)*1 #生成测试图片 labels=measure.label(data,connectivity=2) #8连通区域标记 dst=color.label2rgb(labels) #根据不同的标记显示不同的颜色 print('regions number:',labels.max()+1) #显示连通区域块数(从0开始标记) fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4)) ax1.imshow(data, plt.cm.gray, interpolation='nearest') ax1.axis('off') ax2.imshow(dst,interpolation='nearest') ax2.axis('off') fig.tight_layout() plt.show()skimage.measure.regionprops(label_image)
返回所有连通区块的属性列表,常用的属性列表如下表:
属性名称类型描述areaint区域内像素点总数bboxtuple边界外接框(min_row, min_col, max_row, max_col)centroidarray 质心坐标convex_areaint凸包内像素点总数convex_imagendarray和边界外接框同大小的凸包 coordsndarray区域内像素点坐标Eccentricity float离心率equivalent_diameter float和区域面积相同的圆的直径euler_numberint 区域欧拉数extent float区域面积和边界外接框面积的比率filled_areaint区域和外接框之间填充的像素点总数perimeter float区域周长labelint区域标记有些时候,我们只需要一些大块区域,那些零散的、小块的区域,我们就需要删除掉,则可以使用morphology子模块的remove_small_objects()函数。
函数格式:skimage.morphology.remove_small_objects(ar, min_size=64, connectivity=1, in_place=False)
参数:
ar: 待操作的bool型数组。
min_size: 最小连通区域尺寸,小于该尺寸的都将被删除。默认为64.
connectivity: 邻接模式,1表示4邻接,2表示8邻接
in_place: bool型值,如果为True,表示直接在输入图像中删除小块区域,否则进行复制后再删除。默认为False.
返回删除了小块区域的二值图像。
import numpy as np import scipy.ndimage as ndi from skimage import morphology import matplotlib.pyplot as plt #编写一个函数来生成原始二值图像 def microstructure(l=256): n = 5 x, y = np.ogrid[0:l, 0:l] #生成网络 mask = np.zeros((l, l)) generator = np.random.RandomState(1) #随机数种子 points = l * generator.rand(2, n**2) mask[(points[0]).astype(np.int), (points[1]).astype(np.int)] = 1 mask = ndi.gaussian_filter(mask, sigma=l/(4.*n)) #高斯滤波 return mask > mask.mean() data = microstructure(l=128) #生成测试图片 dst=morphology.remove_small_objects(data,min_size=300,connectivity=1) fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4)) ax1.imshow(data, plt.cm.gray, interpolation='nearest') ax2.imshow(dst,plt.cm.gray,interpolation='nearest') fig.tight_layout() plt.show()转载:https://www.cnblogs.com/denny402/p/5166258.html