OpenCV(python)一键入门--十四篇
本系列OpenCV博客旨在以最简单的方式分享OpenCV知识,欢迎大家交流和提出指导意见
1:轮廓发现
import cv2 as cv
import numpy as np
def threshold_demo(image):
# 去噪声(模糊)+二值化
dst = cv.GaussianBlur(image,(3, 3), 0) #高斯模糊
gray = cv.cvtColor(dst, cv.COLOR_BGR2GRAY) #转灰度
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_OTSU | cv.THRESH_BINARY) #二值化
cv.imshow("binary", binary)
return binary
def canny_demo(image):
#Canny
t = 100
canny_output = cv.Canny(image, t, t * 2) #canny
cv.imshow("canny_output", canny_output)
return canny_output
src = cv.imread("D:/coin.jpg")
cv.imshow("input", src)
#可以选择两种不同函数进行测试
binary = threshold_demo(src)
#binary = canny_demo(src)
# 轮廓发现
#不同版本的返回值会有所出入
#out, contours, hierarchy = cv.findContours(binary, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
contours, hierarchy = cv.findContours(binary, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
cv.drawContours(src, contours, -1, (0, 0, 255), 2) #绘制轮廓
cv.imshow("contours-demo", src)
cv.waitKey(0)
cv.destroyAllWindows()
1):cv.findContours
在不同版本中,会有不同的返回值。我使用的版本为4.1.1.26,在这里就不会有“out”的返回值——即图像的返回
函数原型:cv.findContours(image, mode, method, contours=None, hierarchy=None, offset=None)
“返回的图像” , 获取的轮廓, 轮廓的层次信息 = cv.findContours(输入的二值图像,轮廓检索模式,轮廓近似办法)
轮廓检索模式:
轮廓近似方法:
(以上内容参考自:https://www.baidu.com/link?url=VPbAGREL2cwaW3fEmU7dhc4AlM_7JjWrX2r9q0j3XrbFVDbBXGbyfk5u-jgvG6XYx_LeGQS1kf52-DhAKY-Kt_&wd=&eqid=adbfdcb4000074d00000000661037a1e)
2):cv.drawContours
可以看成:
cv.drawContours(需要绘制的图像,(findContours给出的)图像轮廓,绘制第几个轮廓【-1表示绘制全部】,绘制的RGB值,轮廓宽度)
效果如下:
其中,图一是模糊二值化过后的效果,图二是canny边缘检测的结果
2:轮廓外接矩形——二值图像的分析
import cv2 as cv
import numpy as np
def canny_demo(image):
t = 80
canny_output = cv.Canny(image, t, t * 2)
cv.imshow("canny_output", canny_output)
return canny_output
src = cv.imread("D:/coin.jpg")
binary = canny_demo(src)
k = np.ones((3, 3), dtype=np.uint8)
binary = cv.morphologyEx(binary, cv.MORPH_DILATE, k)
# 轮廓发现
contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for c in range(len(contours)):
rect = cv.minAreaRect(contours[c])
cx, cy = rect[0]
box = cv.boxPoints(rect)
box = np.int64(box) #将值从float强行转换转成整数类型
cv.drawContours(src,[box],0,(0,0,255),2)
cv.circle(src, (np.int32(cx), np.int32(cy)), 2, (255, 0, 0), 2, 8, 0)
cv.imshow("contours_analysis", src)
cv.waitKey(0)
cv.destroyAllWindows()
代码中几个新面孔:cv.morphologyEx,cv.minAreaRect,cv.boxPoints
1):cv.morphologyEx 形态学变换
morphologyEx是OpenCV为形态变换提供了单独的函数。它是基于数学形态学基础之上建立的图像处理技术。数学形态学是由一组形态学的代数运算子组成的,它的基本运算有4个: 膨胀(或扩张)、腐蚀(或侵蚀)、开运算和闭运算。其函数原型如下:
cv.morphologyEx(src, op, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None)
src:需要腐蚀和膨胀的图像
op:形态学处理类型
kernel:核矩阵
dst:返回结果矩阵,
anchor:核矩阵锚点,不传值或传值为(-1,-1)则取核矩阵的中心位置作为锚点
iterations:迭代次数,每多迭代一次相当于以该值为1返回的结果作为src、以iterations为1、其他参数保持不变再次调用腐蚀或膨胀函数一次
borderType:扩充边界的模式,缺省值None表示不进行边界扩充
borderValue:当borderType=cv2.BORDER_CONSTANT时,扩充边界的元素以borderValue填充
简单来看,也可以看成:
cv.morphologyEx(需要操作的图像,形态学处理类型,核矩阵)
形态学处理类型有以下几种:
MORPH_ERODE:腐蚀,当调用morphologyEx使用MORPH_ERODE类型时,与调用腐蚀函数erode效果相同
MORPH_DILATE:膨胀,当调用morphologyEx使用MORPH_DILATE类型时,与调用膨胀函数dilate效果相同
MORPH_OPEN:开运算,对图像先进行腐蚀再膨胀,等同于dilate(erode(src,kernal)),开运算对图像的边界进行平滑、去掉凸起等
MORPH_CLOSE:闭运算,对图像先进行膨胀在腐蚀,等同于erode(dilate(src,kernal)),闭运算用于填充图像内部的小空洞、填充图像的凹陷等
MORPH_GRADIENT:梯度图,用膨胀图减腐蚀图,等同于dilate(src,kernal)−erode(src,kernal),可以用于获得图像中物体的轮廓
MORPH_TOPHAT:顶帽,又称礼帽,用原图像减去开运算后的图像,等同于src−open(src,kernal),可以用于获得原图像中比周围亮的区域
MORPH_BLACKHAT:黑帽,闭运算图像减去原图像,等同于close(src,kernal)−src,可以用于获取原图像中比周围暗的区域
MORPH_HITMISS:击中击不中变换,用于匹配处理图像中是否存在核对应的图像,匹配时,需要确保核矩阵非0部分和为0部分都能匹配,注意该变换只能处理灰度图像。
核矩阵:
可以理解成:和“卷积”在图像处理中的应用一样,一个“内核”遍历图像之后进行处理,这个内核(核矩阵)的不同使得处理得到的图像效果也是不同的。
我们在示例代码中直接用np.ones创建一个3*3的,全为1的矩阵。
【如果你对numpy不熟悉,也可以前往AI Gallery学习:https://marketplace.huaweicloud.com/markets/ai/gallery_course.html】
2)cv.minAreaRect 生成最小外接矩形
因为opencv在实现轮廓发现的时候,cv.findContours是返回一个list。用for循环遍历这些内容,可以得到最小外接矩形的(中心(x,y), (宽,高), 旋转角度)。并且在代码中,我们获取出这些变量,进行外接矩阵绘制
for c in range(len(contours)):
rect = cv.minAreaRect(contours[c])
cx, cy = rect[0] #获取中心点坐标
box = cv.boxPoints(rect)
box = np.int64(box) #将值从float转成整数类型
cv.drawContours(src,[box],0,(0,0,255),2)
cv.circle(src, (np.int32(cx), np.int32(cy)), 2, (255, 0, 0), 2, 8, 0)
我知道上面内容很多,翻回去看代码也不方便。所以我把整个for循环单独贴在这里
我们知道cv.minAreaRect返回值为(中心(x,y), (宽,高), 旋转角度),所以,将 rect[0] 里的值取出用于绘制外接矩形
3):cv.boxPoints
输入的数据形式为: ((x_center, y_center),(w,h), theta)
其中,theta表示的是旋转角度。然后该函数会返回矩形的四个角端点的坐标
之后用cycle绘制上中心点
附上前文说明过的圆形绘制函数:https://bbs.huaweicloud.com/blogs/285489
效果如下:(由于是以前的照片,水印就没有去除,可以看到水印字母的轮廓也标记出来)
- 点赞
- 收藏
- 关注作者
评论(0)