形态学处理的相关内容
(1)基于图像形态进行处理的一般方法
(2)这些处理方法基本是对二进制图像进行处理
(3)卷积核决定着图像处理后的结果
形态学图像处理
(1)腐蚀(简单来说就是黑色图像的部分腐蚀掉白色部分,黑色部分变大)和膨胀(与腐蚀相反,白色部分变大)
(2)开运算:就是先腐蚀后膨胀这样一个组合运算
(3)闭运算:就是先膨胀后腐蚀这样一个组合运算
(4)顶帽,黑帽
图像二值化
为什么要学习二值? 刚刚在上面就提到,我们在对图像进行形态学处理的时候需要对图像处理,而这个图像最好就是二进制图像。
图像二值化相关知识
(1)二值化就是将图像每个像素变成两种值。如0,255
(2)全局二值化 :就是对整张图片进行操作,超过一定的值就变成255,低于这个值就变成0。不让中间有灰度图像。
(3)局部二值化:就是对图像先分割成很多块,每一块都不一样。
二值化API:threshold(img,thresh,maxVal,type)
img:就是图像,是灰度图
thresh:阈值
maxVal:高于阈值变maxVal,低于阈值变0
type:THRESH_BINARY 高于阈值变最大值低于变最小值 THRESH_BINARY_INV与前一种反向高于变最小值,低于变最大值 THRESH_TRUNC THRESH_TPZERO THRESH_TOZERO_INV
上图中第一个图像时原图,第二个与第三个是 THRESH_BINARY,THRESH_BINARY_INV。我们可以看出当高于阈值时,BINARY变成设定最大值,BINARY_INV变成设定最小值,低于阈值时,BINARY变成设定最小值,BINARY_INV变成设定最大值。第三个是TRUNC ,它其实就不是二值化图像了,它在低于阈值时不变,高于阈值时全部变为设定的阈值,进行消峰处理。第四个和第五个是THRESH_TPZERO_INV,THRESH_TPZERO,TPZERO_INV在未达到阈值时不变,达到阈值时变为最小值,TPZERO在未达到阈值时变为最小值,达到阈值时不变。
图像二值化实战代码
import cv2
import numpy as np
img = cv2.imread('../MM/fushipzhang.png')
img1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# #自己设置阈值大小 thresh
ret, dst = cv2.threshold(img1, 100, 255, cv2.THRESH_BINARY)
# # ret,dst=cv2.threshold(img1,100,255,cv2.THRESH_BINARY_INV) #黑白颜色变换
# print(ret)
cv2.imshow('img', img)
cv2.imshow('gray', img1)
cv2.imshow('dst', dst)
cv2.waitKey(0)
最终输出的结果如上,大家可以自己选择不同的阈值进行尝试,看看会出现什么样的区别。
腐蚀
腐蚀的相关知识
腐蚀的原理:其实腐蚀就是一个卷积核去扫描整个图像,只有当卷积核扫描到的全为1的时候,此时卷积核中心才为1,否则只要有0就为0.也就是说,当我扫描图像时,扫描全为白色时,才为白色,否则就是黑色,因此可以想象出来,黑色注定会腐蚀掉原图中旁边有黑色的白色。
这就是进过腐蚀后出现的现象,可以看出,黑色腐蚀了一部分的白色。
腐蚀的API: erode(img,kernel,iterations=1)
img:对哪张图像进行膨胀
kernel:卷积核大小
iterations:卷积的次数
腐蚀实战代码
import cv2
import numpy as np
img = cv2.imread('../MM/erode.png')
# 腐蚀 矩阵中全为1 只有当图像中一块全为1时 才会被腐蚀为1 (一块白才为白) kernel是卷积核
# #手动设置卷积核
kernel=np.ones((9,9),np.uint8)
img1 = cv2.erode(img, kernel, iterations=1)
cv2.imshow('img', img)
cv2.imshow('img1', img1)
cv2.waitKey(0)
我们思考是否和我们原理是相同的,黑色注定会腐蚀掉旁边的白色,所以从第一张图到第二张图,蜘蛛白色的八肢被腐蚀掉,并且黑色的眼睛变大了。大家也可以改变kernel的大小,看看会出现什么情况。
卷积核的类型
卷积核类型相关知识
刚刚我们在腐蚀操作中自己设置了卷积核,但其实opencv有自带的卷积核,我们可以直接调用
获得卷积核API:getStructuringElement(type,size)
type:卷积核类型 MORPH_RACT(矩形) MORPH_ELLIPSE(椭圆形) MORPH_CROSS(十字形)
size:卷积核大小(3,3)(5,5)……
卷积核类型实战代码
import cv2
import numpy as np
img = cv2.imread('../MM/erode.png')
# 从opencv中获得卷积核 cv2.getStructuringElement(type,size)
# MORPH_RECT矩形 MORPH_ELLIPSE椭圆形 MORPH_CROSS交叉十字 size值为(3,3).(5,5)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 9))
# kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (9, 9))
# kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (9, 9))
# print(kernel) #结果是一个全1的九成九的矩阵
img1 = cv2.erode(img, kernel, iterations=1)
cv2.imshow('img', img)
cv2.imshow('img1', img1)
cv2.waitKey(0)
此时我们选取的时 MORPH_RACT(矩形) 这样的卷积核,并且我们设置的大小时(9,9),此时得出的图片与我们腐蚀部分自己设置的kernel最终结果时相同的,因为都是9x9的矩阵。大家也可以尝试不同的type看看结果有什么不同。
膨胀
膨胀的相关知识
膨胀就是把白色膨胀了,在卷积核扫过的区域只要有白色就变成白色。所以可以看出上图经过膨胀后白色变大了。
膨胀API:dilate(img,kernel,iterations=1)
img:对哪个图像进行膨胀
kernel:卷积核大小
iterations:卷积的次数
膨胀实战代码
import cv2
import numpy as np
img = cv2.imread('../MM/erode.png')
# 膨胀 只要矩阵内有1(白)整个区域都会变成白色
# kernel=np.ones((3,3),np.uint8)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7))
dst = cv2.dilate(img, kernel, iterations=1)
cv2.imshow('img', img)
cv2.imshow('dst', dst)
# cv2.imshow('dst1',dst1)
cv2.waitKey(0)
原本的小瘦子变成了小胖子。白色的部分进行了膨胀,得到了我们想要的结果。
大家思考在正常情况下,我先腐蚀,再膨胀,如果其中kernel是相同的,type是相同的,那是否会得到相同的结果?
不一定,如果进行腐蚀,图像每个部分的特征都保留下来了,那进行相反的膨胀结果是相同的,但是如果想我们上面这个图,蜘蛛的眼睛进过膨胀消失了,相反的腐蚀不会出现眼睛了,那结果就不相同了。
开运算
开运算=腐蚀+膨胀
开运算相关知识
开运算有什么用?
上图就是开运算的作用,在保持我需要的图像不变的情况下,消除旁边白色的噪点。
先腐蚀,黑色把白色的小点腐蚀掉后,此时中间的图像也会变瘦,之后进行膨胀,中间图像恢复到原状,但是由于一开始腐蚀已经去掉了白色的小点,那膨胀并不会使消失的小白点出现,所以就完成了保留主要图案,消除白色小点的任务。
开运算API: morphologyEx(img,MORPH_OPEN,kernel)
img:对哪张图片进行开运算
MORPH_OPEN:开运算
kernel:卷积核大小
开运算实战代码
import cv2
import numpy as np
img = cv2.imread('../MM/erode.png')
# 膨胀 只要矩阵内有1(白)整个区域都会变成白色
# kernel=np.ones((3,3),np.uint8)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7))
# #开运算 (先腐蚀后膨胀)(有很多白色的噪点,通过开运算进行消除)
dst = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey(0)
开运算先腐蚀,把脚都给腐蚀掉了,膨胀也没恢复回来。
闭运算
闭运算=膨胀+腐蚀
闭运算相关知识
闭运算有什么用?
把不要的黑色小点去掉。
如图中,中心这个人的图像希望保留,但是人里面的黑色小点想要去除。就可以使用闭运算。
先膨胀,白色把黑色的小点膨胀掉后,此时中间的图像会变胖,之后进行腐蚀,中间图像恢复到原状,但是由于一开始膨胀已经去掉了黑色的小点,那腐蚀并不会使消失的小黑点出现,所以就完成了保留主要图案,消除黑色小点的任务。
闭运算API: morphologyEx(img,MORPH_CLOSE,kernel)
img:对哪张图片进行开运算
MORPH_CLOSE:闭运算
kernel:卷积核大小
闭运算实战代码
import cv2
import numpy as np
img = cv2.imread('../MM/erode.png')
# kernel=np.ones((3,3),np.uint8)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7))
# #闭运算(先膨胀后腐蚀)(有很多黑色的噪点,通过闭运算进行消除)
dst1 = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv2.imshow('img', img)
cv2.imshow('dst1', dst1)
cv2.waitKey(0)
开运算先膨胀,把小蜘蛛的小眼睛给膨胀消失了,后腐蚀使蜘蛛大小恢复。
形态学梯度
梯度=原图—腐蚀
形态学梯度相关知识
腐蚀会使原来的人变小,那用原图减去变小后的图片,就得到了这个人的边沿。
梯度API:morphologyEx(img,MORPH_GRADIENT,kernel)
形态学梯度实战代码
import cv2
import numpy as np
img = cv2.imread('../MM/erode.png')
# kernel=np.ones((3,3),np.uint8)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
# #梯度 (原图-腐蚀后的图)
dst = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey(0)
大家思考是不是应该得到上面的图像,首先进行腐蚀四肢变细了,后面使用原图减去腐蚀的图像得到结果。
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7))
我把kernel大小改成7x7,结果会变成下图。
是否是这样的,大家思考?
顶帽运算与黑帽运算
顶帽运算与黑帽运算相关知识
顶帽=原图—开运算
只想要这个小的方块,不想要大的,就可以使用顶帽运算 。
顶帽运算API:morphologyEx(img,MORPH_TOPHAT,kernel)
黑帽=原图—闭运算
得到大块中的黑色的小噪点。
黑帽运算API:morphologyEx(img,MORPH_BLACKHAT,kernel)
顶帽运算与黑帽运算实战代码
顶帽:
import cv2
import numpy as np
img = cv2.imread('../MM/tophat.png')
# kernel=np.ones((3,3),np.uint8)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (19, 19))
# dst = cv2.dilate(img, kernel, iterations=1)
# 顶帽运算(原图-开运算)保留了白色的噪点
dst = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey(0)
顶帽运算后留下了小的方块,但是在这种操作中需要注意kernel大小的选择,需要进行尝试。
黑帽:
import cv2
import numpy as np
img = cv2.imread('../MM/dotinj.png')
# kernel=np.ones((3,3),np.uint8)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7))
# 黑帽运算(原图-闭运算)保留了黑色的噪点
dst = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey(0)
得到黑色的小噪点。