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

如何在OpenCV中不受倾斜影响按棋盘格顺序排列Blob中心?

解决LED点阵Blob中心的稳定排序问题(不受倾斜影响)

针对大幅倾斜的LED点阵,直接按坐标x/y排序会失效,这里提供基于**主成分分析(PCA)**的稳定排序方案,能自动识别点阵的行/列方向,实现类似cv2.findChessboardCorners的棋盘格顺序排列。

核心思路

  1. 用PCA计算点阵的两个主方向:第一个主方向对应点阵的"行"延伸方向,第二个对应"列"延伸方向(可根据实际情况调整顺序)。
  2. 将每个Blob中心坐标投影到这两个主方向轴上,得到每个点在行、列方向的投影值。
  3. 先按行投影值分组(同一行的点投影值接近),再在每组内按列投影值排序,最终得到规则的棋盘格顺序。

完整代码实现

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

def sort_led_points(points, grid_shape=None):
    """
    对LED点阵的Blob中心进行稳定排序,不受倾斜影响
    :param points: 输入的Blob中心坐标数组,形状为(N, 2)
    :param grid_shape: 可选,点阵的网格形状(行数, 列数),已知则传入提升准确性
    :return: 排序后的坐标数组,形状为(N, 2),顺序为从左到右、从上到下的棋盘格顺序
    """
    # 标准化坐标,消除平移影响
    points_centered = points - np.mean(points, axis=0)
    
    # 执行PCA,获取点阵的主方向
    pca = PCA(n_components=2)
    pca.fit(points_centered)
    principal_axes = pca.components_
    
    # 将点投影到两个主方向轴上
    proj_row = np.dot(points_centered, principal_axes[0])
    proj_col = np.dot(points_centered, principal_axes[1])
    
    # 分组逻辑:已知网格形状则直接拆分,未知则用KMeans聚类
    if grid_shape is not None:
        num_rows, num_cols = grid_shape
        sorted_indices = np.argsort(proj_row)
        row_groups = np.array_split(sorted_indices, num_rows)
    else:
        # 假设点阵近似正方形,自动估算行数
        num_rows = int(np.round(np.sqrt(len(points))))
        kmeans = KMeans(n_clusters=num_rows, random_state=0)
        row_labels = kmeans.fit_predict(proj_row.reshape(-1, 1))
        row_groups = [np.where(row_labels == i)[0] for i in range(num_rows)]
    
    # 对每个行组内的点按列投影值排序
    sorted_points = []
    for group in row_groups:
        group_proj_col = proj_col[group]
        group_sorted_indices = group[np.argsort(group_proj_col)]
        sorted_points.extend(points[group_sorted_indices])
    
    return np.array(sorted_points, dtype=np.float32)

# ---------------------- 调用示例 ----------------------
if __name__ == "__main__":
    # 原有Blob检测代码
    img = cv2.imread('./image.png', cv2.IMREAD_GRAYSCALE)
    params = cv2.SimpleBlobDetector_Params()
    params.minThreshold = 50
    params.maxThreshold = 255
    params.filterByArea = True
    params.minArea = 0
    params.maxArea = 80
    params.filterByColor = True
    params.blobColor = 255
    params.filterByCircularity = False
    params.filterByConvexity = False
    params.filterByInertia = False

    detector = cv2.SimpleBlobDetector_create(params)
    keypoints = detector.detect(img)
    
    # 提取Blob中心坐标
    ips = np.array([(kp.pt[0], kp.pt[1]) for kp in keypoints], dtype=np.float32)
    
    # 排序:替换为你的点阵实际形状,比如(7,7),未知则省略grid_shape参数
    sorted_ips = sort_led_points(ips, grid_shape=(7,7))
    
    # 可选:绘制排序结果验证
    img_color = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
    for i, (x, y) in enumerate(sorted_ips):
        cv2.circle(img_color, (int(x), int(y)), 3, (0, 255, 0), -1)
        cv2.putText(img_color, str(i), (int(x)+5, int(y)), cv2.FONT_HERSHEY_SIMPLEX, 0.3, (0,0,255), 1)
    cv2.imwrite('sorted_leds.png', img_color)

关键说明

  • PCA主方向识别:自动适配点阵的倾斜、旋转状态,无需手动调整方向参数。
  • 分组灵活性:已知点阵行列数时传入grid_shape可确保分组精准;未知时通过聚类自动估算行数,适配多数规则点阵场景。
  • 无依赖手动参数:完全基于点阵的几何特征排序,避免了原方案中shrinker这类需要手动调试的参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 03:40:43