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()
复制代码
输出结果:

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

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

相关推荐
三体世界42 分钟前
测试用例全解析:从入门到精通(1)
linux·c语言·c++·python·功能测试·测试用例·测试覆盖率
Python私教44 分钟前
Django全栈班v1.04 Python基础语法 20250912 下午
后端·python·django
xchenhao1 小时前
Scikit-Learn 对糖尿病数据集(回归任务)进行全面分析
python·机器学习·回归·数据集·scikit-learn·特征·svm
xchenhao1 小时前
Scikit-learn 对加州房价数据集(回归任务)进行全面分析
python·决策树·机器学习·回归·数据集·scikit-learn·knn
这里有鱼汤1 小时前
发现一个高性能回测框架,Python + Rust,比 backtrader 快 250 倍?小团队必备!
后端·python
☼←安于亥时→❦1 小时前
数据分析之Pandas入门小结
python·pandas
带娃的IT创业者1 小时前
《Python Web部署应知应会》No3:Flask网站的性能优化和实时监测深度实战
前端·python·flask
赴3351 小时前
图像拼接案例,抠图案例
人工智能·python·计算机视觉
Monkey的自我迭代1 小时前
SIFT特征匹配实战:KNN算法实现指纹认证
人工智能·opencv·计算机视觉
TwoAI2 小时前
Scikit-learn 机器学习:构建、训练与评估预测模型
python·机器学习·scikit-learn