openCV学习笔记(2)

以下所有操作建议使用png格式的原始图片,使用jpg图片虽然不会出错,但一些操作的结果不太好,原因未知,可能是png格式保留信息更多?

(1)图像形态学

--腐蚀操作

先读进来原始图像

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread("circle.jpg")
plt.imshow(img)
plt.show()

openCV学习笔记(2)

 

 图像是一个⚪周围有一些杂乱的线

我们进行腐蚀操作cv.erode(图像,卷积核,操作次数),看看结果

kernel = np.ones((30,30),np.uint8)#设置一个卷积核大小为(30,30),指定的核越大,边缘被腐蚀的可能性越大
erosion1 = cv.erode(img,kernel,iterations = 1)#执行一次腐蚀
erosion2 = cv.erode(img,kernel,iterations = 2)#执行两次腐蚀
erosion3 = cv.erode(img,kernel,iterations = 3)
res = np.hstack((erosion1,erosion2,erosion3))
plt.imshow(res)
plt.show()

openCV学习笔记(2)

 

可以看到杂线条没了,且“想内塌陷”

 --膨胀操作,我们在腐蚀的结果上膨胀

kernel = np.ones((30,30),np.uint8)
dilate1 = cv.dilate(img,kernel,iterations = 1)
dilate2 = cv.dilate(img,kernel,iterations = 2)
dilate3 = cv.dilate(img,kernel,iterations = 3)
dilate4 = cv.dilate(img,kernel,iterations = 4)
res = np.hstack((dilate1,dilate2,dilate3,dilate4))
plt.imshow(res)
plt.show()

openCV学习笔记(2)

 

 可以发现,第一次膨胀后我们得到了一个完整的⚪但我们的杂线条已经消失了,再继续进行膨胀,图像越来越大

--开运算和闭运算

开运算就是先腐蚀再膨胀

闭运算就是先膨胀再腐蚀

拿原始图像来看一下效果

开运算结果:

opening = cv.morphologyEx(img,cv.MORPH_OPEN,kernel)
plt.imshow(opening)
plt.show()

openCV学习笔记(2)

 

 闭运算结果:

closing = cv.morphologyEx(img,cv.MORPH_CLOSE,kernel)
plt.imshow(closing)
plt.show()

openCV学习笔记(2)

 

 --图像梯度运算

#梯度运算等于膨胀-腐蚀
kernel = np.ones((7,7),np.uint8)
gradient = cv.morphologyEx(img,cv.MORPH_GRADIENT,kernel)
plt.imshow(gradient)
plt.show()

openCV学习笔记(2)

 这样我们就得到了图像的轮廓了

--礼帽和黑帽

礼帽 = 原始输入 - 开运算结果(开运算为先腐蚀再膨胀结果为原始的不带杂线的,最终结果为那些原始图像的杂线)
黑帽 = 闭运算 - 原始输入 (闭运算为先膨胀再腐蚀结果为原始图像加深杂线,最终为原始整体轮廓)

#礼帽
tophat = cv.morphologyEx(img,cv.MORPH_TOPHAT,kernel)
plt.imshow(tophat)
plt.show()

openCV学习笔记(2)

#黑帽
blackhat = cv.morphologyEx(img,cv.MORPH_BLACKHAT,kernel)
plt.imshow(blackhat)
plt.show()

openCV学习笔记(2)

 (2)图像梯度处理

超级详细的讲解:https://blog.csdn.net/poem_qianmo/article/details/25560901

--sobel算子

sobel原型:Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]]) -> dst

src:图片

ddepth:图像深度,当 ddepth为-1时, 输出图像将和输入图像有相同的深度。输入8位图像则会截取顶端的导数

openCV学习笔记(2)

 

 dx =1代表水平方向,dy=1代表竖直方向

ksize:代表算子大小

import cv2 as cv
import numpy as np
def cvshow(img):
    cv.imshow("img",img)
    cv.waitKey(0)
    cv.destroyAllWindows()
img = cv.imread("pie.png")
cvshow(img)
#进行SObel算子
sobel = cv.Sobel(img,cv.CV_64F,1,0,ksize=3)
sobel = cv.convertScaleAbs(sobel)#取绝对值
cvshow(sobel)

当我们不加取绝对值时,结果为一半,加上取绝对值就可以获取到完整的

openCV学习笔记(2)openCV学习笔记(2)

 

 这里建议分别算X方向的sobel和Y方向的sobel再加一起,这样会比直接dx=1,dy=1一起算的更清晰

--Scharr算子和laplacian算子

import cv2 as cv
import numpy as np
def cvshow(img):
    cv.imshow("img",img)
    cv.waitKey(0)
    cv.destroyAllWindows()
img = cv.imread("car.jpg")
scharr_x = cv.Scharr(img,cv.CV_64F,1,0)
scharr_y = cv.Scharr(img,cv.CV_64F,0,1)
scharr_x = cv.convertScaleAbs(scharr_x)
scharr_y = cv.convertScaleAbs(scharr_y)
scharr_xy = cv.addWeighted(scharr_x,0.5,scharr_y,0.5,0)

laplacian = cv.Laplacian(img,cv.CV_64F)
laplacian = cv.convertScaleAbs(laplacian)
res = np.hstack((scharr_xy,laplacian))
cvshow(res)

openCV学习笔记(2)

 

 左边为scharr算子,右边为拉普拉多算子,右边差不多只有主体

 

再对比一下3个的效果,从左至右分别为sobel,scharr,laplacian

import cv2 as cv
import numpy as np
def cvshow(img):
    cv.imshow("img",img)
    cv.waitKey(0)
    cv.destroyAllWindows()
img = cv.imread("lena.jpg",0)
sobel_x = cv.Sobel(img,cv.CV_64F,1,0,ksize=3)
sobel_y = cv.Sobel(img,cv.CV_64F,0,1,ksize=3)
sobel_x = cv.convertScaleAbs(sobel_x)
sobel_y = cv.convertScaleAbs(sobel_y)
sobel = cv.addWeighted(sobel_x,0.5,sobel_y,0.5,0)

scharr_x = cv.Scharr(img,cv.CV_64F,1,0)
scharr_y = cv.Scharr(img,cv.CV_64F,0,1)
scharr_x = cv.convertScaleAbs(scharr_x)
scharr_y = cv.convertScaleAbs(scharr_y)
scharr_xy = cv.addWeighted(scharr_x,0.5,scharr_y,0.5,0)

laplacian = cv.Laplacian(img,cv.CV_64F)
laplacian = cv.convertScaleAbs(laplacian)
res = np.hstack((sobel,scharr_xy,laplacian))
cvshow(res)

openCV学习笔记(2)

 

 整体来看,scharr算子保留了最多的细节,但是连通噪点也一起保留了下来,sobel算子保留了大部分最主要的轮廓信息,laplacian只有最主体的信息

以上这一切的处理正是为了我们真正做轮廓处理做准备

 

上一篇:(五)OpenCV-Python学习—边缘检测1


下一篇:翻译:《实用的Python编程》02_06_List_comprehension