【AI】opencv-python形态学操作合集

6 篇文章 0 订阅
  • 形态学操作作用:在处理图像时特别有用,尤其是在去噪、边缘检测、填充孔洞等场景中。
  • 定义结构元素
    内核的形状,有三种形状可以选择。
    矩形:MORPH_RECT;
    交叉形:MORPH_CROSS;
    椭圆形:MORPH_ELLIPSE;
    在这里插入图片描述
cv2.getStructuringElement(shape, ksize[, anchor])
'''
shape:
cv2.MORPH_RECT:矩形结构元素,这是最常见的选择,所有像素的权重都相等。
cv2.MORPH_ELLIPSE:椭圆结构元素,通常用于图像处理中的各向同性滤波。
cv2.MORPH_CROSS:交叉形状的结构元素,其形状类似一个“+”号,这种结构元素在处理一些特定类型的噪声或细节时可能很有用。

ksize:(x,y)形式的元组

anchor:结构元素的锚点位置,即结构元素的参考点。通常,这是元素的中心。但在某些情况下,你可能希望更改锚点的位置。它是一个包含两个元素的元组,表示锚点的 x 和 y 坐标。如果不提供此参数,则默认为元素的中心。

返回值:一个表示结构元素的二维数组(numpy 数组)
'''
element = cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
print("elemrnt":element ) #输出array

NpKernel = np.uint8(np.zeros((5,5)))
for i in range(5):
	NpKernel[2, i] = 1
	NpKernel[i, 2] = 1
print("NpKernel ",NpKernel )

'''
输出结果两个相同,均是
array([[0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0]], dtype=uint8)
'''

  • 4邻域 & 8邻域
    在这里插入图片描述

  • 腐蚀&膨胀
    腐蚀和膨胀是对白色部分(高亮部分)而言的,不是黑色部分。
    腐蚀和膨胀是两个互为对偶的运算。腐蚀的作用是将目标图像收缩,而膨胀是将图像扩大。

腐蚀是一种消除边界点,使边界向内部收缩的过程。可以用来消除小且无意义的目标物。如果两目标物间有细小的连通,可以选取足够大的结构元素,将细小连通腐蚀掉。
腐蚀操作用于去除图像中的噪声、分割连通区域、减小目标物体的尺寸等。
算法原理:中心像素位置的值根据其八邻域取交运算。(灰度图像仅有0,1两种像素值) 在给定的结构元素(kernel滤波器)下,遍历图像的每个像素,并将其值替换为该像素周围邻域内像素的最小值。结构元素控制了腐蚀的邻域范围和形状。邻域内的任何一个像素为黑色(0),则中心像素也将被置为黑色(0)。

注意在腐蚀膨胀之前需要二值化,区分黑白部分
cv.cvtColor(image, cv.COLOR_BGR2GRAY)
cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
 
cv2.erode(img,kernel,iterations)

膨胀是将目标区域接触的背景点合并到该目标物中,使目标边界向外扩张的处理。膨胀可以用来填补目标区域存在的某些空洞,也可以用来消除包含在目标区域中的小颗粒噪声。膨胀处理是腐蚀处理的对偶或者逆运算。
算法原理:中心像素位置的值根据其八邻域取或运算。卷积核所对应的原图像的像素值只要有一个是1,中心像素值就是1。
膨胀操作的效果取决于结构元素的形状和大小,以及迭代次数。增加迭代次数会使目标物体区域更大,边界更粗糙。通常情况下,一个或两个迭代次数就足够了。
可在腐蚀后使用,在腐蚀操作中,消除噪声的同时,有价值的信息也减少了。因此我们希望将这些有价值的信息增大,可以通过膨胀操作,则膨胀是腐蚀的逆操作。

cv2.dilate(img,kernel,iterations)
第一个参数:img指需要腐蚀的图
第二个参数:kernel指腐蚀操作的内核,默认是一个简单的3X3矩阵,我们也可以利用getStructuringElement()函数指明它的形状
第三个参数:iterations指的是腐蚀次数,省略是默认为1

补充:numpy中的vstack、hstack、dstack三种堆叠函数的区别
vstack() 函数表示将数组在第一维上进行堆叠(即最外层的方括号),可将arr1和arr2第一维内的部分看作一个整体
hstack() 函数表示将数组在第二维进行堆叠(即第二层方括号),可将arr1和arr2中第二层括号里面的内容看作一个整体
dstack() 函数表示将数组在第三维进行堆叠(即第三层方括号),可将arr1和arr2第三层括号里面的内容看作一个整体
通俗一点的说法就是,vstack是几张图片竖着按顺序摆放(因为行增加),hstack横着摆放,dstack通道叠加(显示不出来)

arr1 = np.array(data1)
arr2 = np.array(data2)
# arr1.shape == [3, 3, 3] 
# arr2.shape == [3, 3, 3]
a = np.vstack((arr1, arr2))
# 此时 a.shape == [6, 3, 3]

cv2.erode(src, kernel, iterations)
'''
src:输入的二值图像,通常为单通道灰度图像。
kernel:腐蚀操作的结构元素,用于定义腐蚀的邻域大小和形状。可以使用 cv2.getStructuringElement() 函数创建不同形状的结构元素。
iterations:腐蚀操作的迭代次数,表示应用腐蚀的重复次数。
'''
#查看原图
img = cv2.imread('file_path')
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 创建结构元素 (3x3 方框形)
kernel = np.ones((3, 3), dtype=np.uint8)

# 执行腐蚀操作
eroded = cv2.erode(img, kernel, iterations=1)

# 显示结果
cv2.imshow('Eroded Image', eroded)
cv2.waitKey(0)
cv2.destroyAllWindows()

#更改iterations的值,来增加迭代次数,迭代次数越多,腐蚀效果越明显。

erosion_1 = cv2.erode(img,kernel,iterations = 1)#1次迭代
erosion_2 = cv2.erode(img,kernel,iterations = 2)#2次迭代
erosion_3 = cv2.erode(img,kernel,iterations = 3)#3次迭代
res = np.hstack((erosion_1,erosion_2,erosion_3))#水平堆砌

cv2.erode(src, kernel, iterations)

  • 开闭运算
    膨胀和腐蚀组合,可以实现开运算(Opening)和闭运算(Closing)。但他们不是可逆的,即先开后闭并不能得到原先的图像。

分开去噪,闭合填充:分离连通的对象,去除图像噪声,即为开运算;闭合连通的对象,填充图像空洞,即为闭运算

开运算是先进行腐蚀操作,再进行膨胀操作。它主要用于去除图像中的噪点、小的干扰物或者分离连通的对象。
闭运算是先进行膨胀操作,再进行腐蚀操作。它主要用于填充图像中的小洞孔或者连接分离的对象。

'''
dst = cv2.morphologyEx(src, op, kernel[, dst[, anchor]])

参数:
src:源图像,必须是单通道的灰度图像。
op:形态学操作的类型,可以是以下几种:
cv2.MORPH_ERODE:腐蚀操作。
cv2.MORPH_DILATE:膨胀操作。
cv2.MORPH_OPEN:开运算。
cv2.MORPH_CLOSE:闭运算。
cv2.MORPH_GRADIENT:形态学梯度。使用后会加重轮廓边缘
cv2.MORPH_TOPHAT:原图像减去膨胀的图像。
cv2.MORPH_HITMISS:结构元素对应的点集比较。
kernel:形态学操作的核,通常是一个矩形、椭圆或十字形的小矩阵。核的大小可以是正奇数。
dst(可选):输出图像,如果未指定,则函数会创建一个新的输出图像。
anchor(可选):核的锚点,默认是核的中心。

'''
# 开:先腐蚀,再膨胀
img = cv2.imread('file_path')

kernel = np.ones((5,5),np.uint8) 
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)

cv2.imshow('opening', opening)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 闭:先膨胀,再腐蚀
img = cv2.imread('file_path')

kernel = np.ones((5,5),np.uint8) 
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)

cv2.imshow('closing', closing)
cv2.waitKey(0)
cv2.destroyAllWindows()


  • 顶帽黑帽运算
    顶帽 = 原始图像 - 开运算结果(先腐蚀后膨胀)
    黑帽 = 闭运算(先膨胀后腐蚀) - 原始图像

顶帽和黑帽运算在图像处理中具有以下作用:
边缘检测和轮廓提取:形态学梯度运算可以用来提取图像中的边缘和轮廓,顶帽和黑帽运算都是形态学梯度运算的一种,它们可以通过突出图像中物体的边缘和轮廓来提高图像的清晰度和对比度。
噪声消除:顶帽和黑帽运算可以用来进行噪声消除,尤其是对于那些亮度和暗度不均匀的图像,这两种运算都可以有效地消除噪声。
斑块提取和分离:对于一些特定的应用,比如在医学图像处理中,顶帽和黑帽运算可以用来提取和分离某些特定的斑块,如肺结节等。
图像增强:通过改变图像的亮度和对比度,顶帽和黑帽运算可以增强图像的视觉效果,使图像更清晰、更易于观察和理解。

kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))              #定义矩形结构元素(核大小为3效果好)
TOPHAT_img = cv2.morphologyEx(gray_img, cv2.MORPH_TOPHAT, kernel)    
#顶帽运算 作用:仅剩下噪点
BLACKHAT_img = cv2.morphologyEx(gray_img, cv2.MORPH_BLACKHAT, kernel) 
#黒帽运算 作用:仅剩下应填充的白色孔洞(在原图中为黑色空洞)

bitwiseXor_gray = cv2.bitwise_xor(gray_img,TOPHAT_img)#异或,相当于原图尽可能去除噪点

  • 边缘检测
    检测图像中的边缘和拐角
    (实际用:Canny检测边缘 Harris检测角点 等)

形态学检测边缘的原理很简单:在膨胀时,图像中的物体会想周围“扩张”;腐蚀时,图像中的物体会“收缩”。由于这两幅图像其变化的区域只发生在边缘。所以这时将两幅图像相减,得到的就是图像中物体的边缘。

import cv2
import numpy 

image = cv2.imread("jianzhu.png",cv2.IMREAD_GRAYSCALE)

kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
dilate_img = cv2.dilate(image, kernel)
erode_img = cv2.erode(image, kernel) 

"""
我选了一张较好的图片,有的图片要去噪(高斯模糊)
将两幅图像相减获得边;cv2.absdiff参数:(膨胀后的图像,腐蚀后的图像)
上面得到的结果是灰度图,将其二值化以便观察结果
反色,对二值图每个像素取反
"""
absdiff_img = cv2.absdiff(dilate_img,erode_img);
retval, threshold_img = cv2.threshold(absdiff_img, 40, 255, cv2.THRESH_BINARY); 
result = cv2.bitwise_not(threshold_img); 

cv2.imshow("jianzhu",image)
cv2.imshow("dilate_img",dilate_img)
cv2.imshow("erode_img",erode_img)
cv2.imshow("absdiff_img",absdiff_img)
cv2.imshow("threshold_img",threshold_img)
cv2.imshow("result",result)

cv2.waitKey(0)
cv2.destroyAllWindows()

  • 拐角检测
    原理:
  1. 先用十字形的结构元素膨胀像素,这种情况下只会在边缘处“扩张”,角点不发生变化。
  2. 接着用菱形的结构元素腐蚀原图像,导致只有在拐角处才会“收缩”,而直线边缘都未发生变化。
  3. 用X形膨胀原图像,角点膨胀的比边要多。
  4. 用方块腐蚀时,角点恢复原状,而边要腐蚀的更多。所以当两幅图像相减时,只保留了拐角处。
import cv2 

image = cv2.imread("./jianzhu.png",0)
original_image = image.copy()
#构造5×5的结构元素,分别为十字形、菱形、方形和X型
cross = cv2.getStructuringElement(cv2.MORPH_CROSS,(5, 5))

diamond = cv2.getStructuringElement(cv2.MORPH_RECT,(5, 5))
diamond[0, 0] = 0
diamond[0, 1] = 0
diamond[1, 0] = 0
diamond[4, 4] = 0
diamond[4, 3] = 0
diamond[3, 4] = 0
diamond[4, 0] = 0
diamond[4, 1] = 0
diamond[3, 0] = 0
diamond[0, 3] = 0
diamond[0, 4] = 0
diamond[1, 4] = 0
#构造菱形diamond

square = cv2.getStructuringElement(cv2.MORPH_RECT,(5, 5))  #构造方形结构元素

x = cv2.getStructuringElement(cv2.MORPH_CROSS,(5, 5)) #x型    

#尽可能扩张边缘、缩减角点
dilate_cross_img = cv2.dilate(image,cross)                #使用cross膨胀image
erode_diamond_img = cv2.erode(dilate_cross_img, diamond)  #紧接着用菱形腐蚀图像 

#尽可能扩张角点、缩减边缘
dilate_x_img = cv2.dilate(image, x)                       #使用X膨胀image
erode_square_img = cv2.erode(dilate_x_img,square)         #紧接着用方形腐蚀图像 

#都是先膨胀后腐蚀,所以是闭运算
result = cv2.absdiff(erode_square_img, erode_diamond_img)          #将两幅闭运算的图像相减获得角
retval, result = cv2.threshold(result, 40, 255, cv2.THRESH_BINARY) #使用阈值获得二值图

'''
size:返回图像的像素总数:行数*列数*通道数 
shape:如果是彩色图像,则返回(行数,列数,通道数)的数组;如果是灰度图像,则返回(行数,列数)的数组 
'''
#在原图上用半径为5的圆圈将点标出。
for j in range(result.size):#由于是灰度图像,size=row*col
    y = int(j / result.shape[0]) 
    #相当于得到每个row下标
    x = int(j % result.shape[0])
    #相当于得到每个col
    if result[x, y] == 255:                                        #result[] 只能传入整型
        cv2.circle(image,(y,x),5,(255,0,0))
'''
cv2.circle(image, center, radius, color, thickness)
 
image:它是要在其上绘制圆的图像。
center:它是圆的中心坐标。坐标表示为两个值的元组,即(X坐标值,Y坐标值)。
radius:它是圆的半径。
color:它是要绘制的圆的边界线的颜色。对于BGR,我们通过一个元组。例如:(255,0,0)为蓝色。
thickness:它是圆边界线的粗细像素。厚度-1像素将以指定的颜色填充矩形形状。

cv2.line(img, pt1,pt2,color,thickness,lineType)
img:背景图
pt1:直线起点坐标
pt2:直线终点坐标
color:当前绘画的颜色。如在BGR模式下,传递(255,0,0)表示蓝色画笔。灰度图下,只需要传递亮度值即可。
thickness:画笔的粗细,线宽。若是-1表示画封闭图像,如填充的圆。默认值是1.
lineType:线条的类型,
如8-connected类型、anti-aliased线条(反锯齿),默认情况下是8-connected样式ide,cv2.LINE_AA表示反锯齿线条,在曲线的时候视觉效果更佳。

cv2.rectangle(img,pt1,pt2,color,thickness)
img:背景图
pt1:直线起点坐标
pt2:直线终点坐标
color:当前绘画的颜色。如在BGR模式下,传递(255,0,0)表示蓝色画笔。灰度图下,只需要传递亮度值即可。
thickness:画笔的粗细,线宽。若是-1表示画封闭图像,如填充的圆。默认值是1.

cv2.putText(img, text, org, fontFace, fontScale, color, thickness=None, lineType=None, bottomLeftOrigin=None)
img:背景图
text:要绘制的文字字符串
org:图像中文本字符串的左下角坐标
fontFace:字体类型,字体选择:FONT_HERSHEY_SIMPLEX、normal size sans-serif font、small size 							sans-serif font、FONT_HERSHEY_COMPLEX
fontScale:字体比例因子乘以特定字体的基本大小
color:文字颜色
thickness:用于绘制文本的线条的粗徐
lineType:线型

'''

cv2.imshow("original_image", original_image)
cv2.imshow("Result", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值