You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python3的OpenCV检测图像轮廓?聚类算法优化咨询

基于聚类算法的矩形检测自动化方案

一、图像数据向量化:适配聚类算法的样本转换

不管用K-means还是DBSCAN,核心是把图像中的像素或候选轮廓转换成带特征的样本点,两种适配方案如下:

  • 像素级颜色聚类:针对不同灰度区域的区分需求,将灰度图像的所有像素展开为(总像素数, 1)的数组,每个像素的特征就是其0-255的灰度值。
  • 候选轮廓特征聚类:先通过低阈值Canny提取所有轮廓(含干扰条纹),再为每个轮廓提取组合特征:比如轮廓包围区域的平均灰度值、轮廓面积、外接矩形宽高比,将这些特征拼接成向量作为单个样本。

二、K-means实现自动化区域分割+矩形检测

适合已知目标颜色类别数(这里是白、灰、黑三类)的场景:

步骤1:像素级聚类分割

import cv2
import numpy as np
from sklearn.cluster import KMeans

# 读取灰度图像
img = cv2.imread('your_image.jpg', cv2.IMREAD_GRAYSCALE)
h, w = img.shape

# 转换像素为聚类样本数组
pixels = img.reshape(-1, 1)

# K-means聚类为3类(对应白、灰、黑区域)
kmeans = KMeans(n_clusters=3, random_state=42)
kmeans.fit(pixels)

# 生成聚类掩码图像
labels = kmeans.labels_.reshape(h, w)

步骤2:从聚类区域提取矩形轮廓

# 遍历每个聚类类别
for cluster_idx in range(3):
    # 生成当前类别的二值掩码
    mask = np.where(labels == cluster_idx, 255, 0).astype(np.uint8)
    
    # 提取轮廓
    contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    # 筛选矩形轮廓
    for cnt in contours:
        # 轮廓多边形逼近
        epsilon = 0.02 * cv2.arcLength(cnt, True)
        approx = cv2.approxPolyDP(cnt, epsilon, True)
        
        # 判断是否为矩形(4个顶点+面积阈值过滤小区域)
        if len(approx) == 4 and cv2.contourArea(cnt) > 1000:
            cv2.drawContours(img, [approx], 0, (0, 255, 0), 2)

cv2.imshow('Detected Rectangles', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

三、DBSCAN筛选目标轮廓(针对小干扰条纹)

适合干扰条纹面积小、特征与目标差异明显的场景,无需提前指定聚类数:

步骤1:提取候选轮廓及特征

import cv2
import numpy as np
from sklearn.cluster import DBSCAN
from sklearn.preprocessing import StandardScaler

img = cv2.imread('your_image.jpg', cv2.IMREAD_GRAYSCALE)
# 低阈值Canny提取所有轮廓(含干扰)
edges = cv2.Canny(img, 50, 150)
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 提取每个轮廓的特征向量
features = []
for cnt in contours:
    area = cv2.contourArea(cnt)
    # 计算轮廓区域的平均灰度
    x, y, w_cnt, h_cnt = cv2.boundingRect(cnt)
    roi = img[y:y+h_cnt, x:x+w_cnt]
    avg_gray = np.mean(roi)
    # 计算外接矩形宽高比
    aspect_ratio = w_cnt / h_cnt if h_cnt != 0 else 0
    features.append([avg_gray, area, aspect_ratio])

# 标准化特征(DBSCAN对特征尺度敏感)
scaler = StandardScaler()
scaled_features = scaler.fit_transform(features)

步骤2:DBSCAN聚类筛选目标矩形

# 初始化DBSCAN,eps和min_samples需根据图像实际调整
dbscan = DBSCAN(eps=0.5, min_samples=1)
labels = dbscan.fit_predict(scaled_features)

# 定位目标聚类:通常目标矩形的平均面积远大于干扰条纹
unique_labels = np.unique(labels)
target_label = None
max_avg_area = 0
for label in unique_labels:
    if label == -1:  # 跳过噪声点
        continue
    # 计算当前聚类的平均轮廓面积
    class_areas = [features[i][1] for i in range(len(features)) if labels[i] == label]
    avg_area = np.mean(class_areas)
    if avg_area > max_avg_area:
        max_avg_area = avg_area
        target_label = label

# 绘制筛选后的目标矩形
for i in range(len(contours)):
    if labels[i] == target_label:
        cnt = contours[i]
        epsilon = 0.02 * cv2.arcLength(cnt, True)
        approx = cv2.approxPolyDP(cnt, epsilon, True)
        if len(approx) == 4:
            cv2.drawContours(img, [approx], 0, (0, 255, 0), 2)

cv2.imshow('Filtered Rectangles', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

关键注意事项

  • K-means适合颜色类别固定的场景,需提前指定聚类数;DBSCAN无需指定聚类数,但需根据图像调整eps(样本邻域半径)和min_samples(聚类最小样本数)。
  • 特征选择要贴合干扰类型:若干扰是小面积条纹,优先用面积+灰度特征;若干扰是灰度接近但形状不同的区域,优先用像素级灰度聚类。
  • 聚类后必须通过approxPolyDP做轮廓逼近,过滤非矩形的无效区域。

内容的提问来源于stack exchange,提问作者lksj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 17:05:52