OpenCV(python)一键入门--十四篇

举报
拓佑豪 发表于 2021/07/31 00:05:52 2021/07/31
【摘要】 简单介绍了二值图像分析的轮廓发现以及绘制外接矩形的简单操作

本系列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

效果如下:(由于是以前的照片,水印就没有去除,可以看到水印字母的轮廓也标记出来)

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。