OpenCV轮廓图的一些操作

1.按短边筛选

原始轮廓图:

python 复制代码
import cv2
import numpy as np

# 读取轮廓图
contour_image = cv2.imread('..\\IMGS\\pp_edge.png', cv2.IMREAD_GRAYSCALE)

# 使用cv2.findContours()函数获取所有轮廓
contours, _ = cv2.findContours(contour_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 设定的直径阈值
threshold_diameter = 25.0

# 遍历每个轮廓
new_image = np.zeros_like(contour_image)
for contour in contours:
    rect = cv2.minAreaRect(contour)  # 获取最小外接矩形
    diameter = rect[1][0] if rect[1][0] <= rect[1][1] else rect[1][1]    # 计算轮廓的最短尺寸,并获取直径

    # 如果轮廓的直径小于设定的阈值,则忽略该轮廓
    if diameter >= threshold_diameter:
        cv2.drawContours(new_image, [contour], -1, (255, 255, 255))
        print(diameter, end=', ')


cv2.imshow('Filtered Contours', new_image)   # 绘制保留的轮廓
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果以及与原图对比:

2.按长边筛选

python 复制代码
import cv2
import numpy as np

# 读取轮廓图
contour_image = cv2.imread('..\\IMGS\\pp_edge2.png', cv2.IMREAD_GRAYSCALE)

# 使用cv2.findContours()函数获取所有轮廓
contours, _ = cv2.findContours(contour_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 设定的直径阈值
threshold_diameter = 25.0

# 遍历每个轮廓
new_image = np.zeros_like(contour_image)
for contour in contours:
    diameter = cv2.minEnclosingCircle(contour)[1] * 2   # cv2.minEnclosingCircle():计算一个轮廓的最小包围圆,返回值是圆心坐标和半径

    # 如果轮廓的直径小于设定的阈值,则忽略该轮廓
    if diameter >= threshold_diameter:
        cv2.drawContours(new_image, [contour], -1, (255, 255, 255))
        print(diameter, end=', ')


cv2.imshow('Filtered Contours', new_image)   # 绘制保留的轮廓
cv2.waitKey(0)
cv2.destroyAllWindows()

结果图:

3.将粘连的轮廓分开

有经过灰度、二值化处理后的图如下,需要将图中的所有轮廓读出,用以进行尺寸测量和数量统计等后续操作。

看得出,图中有两个轮廓 粘连到了一起,如果直接进行查找和统计就会出错。

例如用下面代码将轮廓找出并画出:

python 复制代码
import cv2
import numpy as np

input_img = cv2.imread('..\\IMGS\\pp_binary.png', cv2.IMREAD_GRAYSCALE)     # 读取已转换过的轮廓图像
contours = cv2.findContours(input_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0]   # 查找轮廓
tmp_img = np.zeros_like(input_img)  # 创建空白临时图像
cv2.drawContours(tmp_img, contours, -1, 255)  # 将轮廓绘制在临时图像上
cv2.imshow('OutPut', tmp_img)   # 显示轮廓图
cv2.waitKey(0)
cv2.destroyAllWindows()

输出图如下:

看得出,轮廓是粘到一起的。为了将轮廓分开,初步的设想是,先用腐蚀的方法,如果存在轮廓粘连,那么腐蚀操作以后,图像就会被分成多个独立的部分,然后将每个独立的部分再进行膨胀操作恢复尺寸,并分别读取每个独立部分的轮廓,这样就实现了粘连轮廓的分离。

代码:

python 复制代码
import cv2
import numpy as np

input_img = cv2.imread('..\\IMGS\\pp_binary.png', cv2.IMREAD_GRAYSCALE)     # 读取已转换过的轮廓图像
contours = cv2.findContours(input_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0]   # 查找轮廓

out_contours = []    # 创建用以输出的轮廓线列表

for contour in contours:      # 针对每一个轮廓进行操作
    rect = cv2.minAreaRect(contour)   # 获取最小外接矩形
    diameter = rect[1][0] if rect[1][0] <= rect[1][1] else rect[1][1]   # 计算轮廓的最短尺寸,并获取直径

    num_kernel = int(diameter / 2.5)   # 定义核的大小
    if num_kernel % 2 == 0:
        num_kernel += 1
    kernel = np.ones((num_kernel, num_kernel), np.uint8)  # 定义核

    tmp_img = np.zeros_like(input_img)   # 创建空白临时图像
    cv2.drawContours(tmp_img, [contour], -1, (255, 255, 255), thickness=cv2.FILLED)    # 将当前的轮廓绘制在临时图像上

    erode_img = cv2.erode(tmp_img, kernel, iterations=1)   # 腐蚀操作,打破连接
    tmp_contours = cv2.findContours(erode_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0]      # 读取腐蚀操作后的临时图像的轮廓
    if len(tmp_contours) > 1:    # 如果存在轮廓粘连,那么腐蚀操作以后,图像就会被分成多个独立的部分
        for tmp in tmp_contours:
            tmp_img = np.zeros_like(input_img)  # 创建空白临时图像
            cv2.drawContours(tmp_img, [tmp], -1, (255, 255, 255), thickness=cv2.FILLED)  # 将轮廓绘制在临时图像上
            dilate_img = cv2.dilate(tmp_img, kernel, iterations=1)  # 膨胀操作,恢复轮廓尺寸
            _ = cv2.findContours(dilate_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0]  # 读取膨胀操作后的临时图像的轮廓
            out_contours.extend(_)     # 将膨胀操作后的轮廓加入输出用的轮廓列表
    else:
        out_contours.extend([contour])      # 不存在轮廓粘连,直接将当前轮廓加入输出用的轮廓列表

# 在原图上绘制轮廓
tmp_img = np.zeros_like(input_img)   # 创建空白临时图像,用以输出
cv2.drawContours(tmp_img, out_contours, -1, 255)   # 在临时图像上画出所有轮廓

# 显示结果
mask_img = cv2.cvtColor(tmp_img, cv2.COLOR_GRAY2BGR)    # 掩模图,用以将轮廓叠加在原图上
mask_img[tmp_img == 255] = [0, 255, 0]  # 按照临时图中的白色位置,将掩模图中的对应位置变为绿色
gray_img_3ch = cv2.cvtColor(input_img, cv2.COLOR_GRAY2BGR)   # 转换创建RGB图,用以显示
show_img = cv2.addWeighted(gray_img_3ch, 0.5, mask_img, 1, 0)  # 将掩模图与灰色3通道图叠加输出
cv2.imshow('OutPut', show_img)

cv2.waitKey(0)
cv2.destroyAllWindows()
复制代码
输出结果:

粘连的轮廓已经被分开,成为两个相邻的独立轮廓。当然了,由于使用了先腐蚀再膨胀的操作,轮廓尺寸会有一些精度上的损失,但是比起将两个轮廓误统计为一个,误差还是小多了。

题外话,先腐蚀再膨胀看上去很熟悉是吧,不就是开操作吗?直接使用开操作行不行?我的实验结果是不行,会得到类似下面这样的结果:

相关推荐
Cindy辛蒂几秒前
python办公自动化之分析日志文件
开发语言·python
Alice_JC6 分钟前
《昇思25天学习打卡营第11天|计算机视觉-ResNet50迁移学习》
深度学习·学习·计算机视觉·迁移学习
镜花照无眠1 小时前
python破解字母已知但大小写未知密码
开发语言·python
程序无涯海1 小时前
Python爬虫教程第1篇-基础知识
开发语言·爬虫·python·网络爬虫
家有狸花1 小时前
PYTHON自学笔记(一)vscode配置
笔记·vscode·python
鸽芷咕1 小时前
【python学习】快速了解python基本数据类型
开发语言·python·学习
深蓝海拓1 小时前
使用OpenCV与PySide(PyQt)的视觉检测小项目练习
人工智能·opencv·numpy·pyqt
秋刀鱼_(:з」∠)_别急2 小时前
如何获取歌曲id---cloudmusic
后端·爬虫·python·计算机网络·ajax·okhttp·xhr
杰哥在此2 小时前
Python面试题:如何在 Python 中读取和写入 JSON 文件?
开发语言·python·面试·json·编程
LabVIEW开发2 小时前
LabVIEW透视变换
算法·计算机视觉·labview·labview开发