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

如何检测图像中近似共线线段以修复重叠样本计数与长度测量问题

重叠样本计数修复:共线线段合并方案

针对重叠样本被误计数的问题,核心是把近似共线且距离接近的线段合并为单个样本,以下是具体实现方案:

核心思路

判断两条线段属于同一样本需要满足两个条件:

  1. 线段方向近似一致(共线)
  2. 线段之间的距离足够近(属于同一“直线簇”)

具体实现步骤

1. 计算每条线段的几何参数

先为每个线段提取关键参数:斜率、直线归一化一般式(用于距离计算)、中点坐标、线段长度。

2. 分组近似共线的线段

通过斜率阈值筛选方向一致的线段,垂直线单独处理避免除零错误。

3. 验证组内线段的距离

对同方向的线段,计算线段中点到基准直线的距离,只有距离小于阈值的才归为同一样本。

4. 合并线段并统计结果

将同组线段的所有端点整合,用最小外接矩形的长轴长度作为合并后样本的长度,最终统计样本数量。

代码示例

假设你的extremes_dict结构为{label: [(x1,y1), (x2,y2)]},对应每个线段的两个端点:

import numpy as np
import cv2

def get_line_params(p1, p2):
    """计算线段的关键几何参数"""
    x1, y1 = p1
    x2, y2 = p2
    dx = x2 - x1
    dy = y2 - y1
    
    # 处理斜率,垂直线标记为无穷大
    slope = np.inf if dx == 0 else dy / dx
    
    # 直线归一化一般式 Ax + By + C = 0
    A, B, C = dy, -dx, dx*y1 - dy*x1
    norm = np.sqrt(A**2 + B**2)
    if norm != 0:
        A, B, C = A/norm, B/norm, C/norm
    
    # 中点坐标和线段长度
    mid = ((x1+x2)/2, (y1+y2)/2)
    length = np.sqrt(dx**2 + dy**2)
    
    return slope, (A,B,C), mid, length

# 配置阈值(根据图像分辨率和样本粗细调整)
SLOPE_TOLERANCE = 0.05    # 斜率容忍度
DISTANCE_TOLERANCE = 3    # 像素距离容忍度

# 预处理所有线段参数
line_params = {}
for label, endpoints in extremes_dict.items():
    slope, abc, mid, length = get_line_params(*endpoints)
    line_params[label] = {
        "slope": slope,
        "abc": abc,
        "mid": mid,
        "length": length,
        "endpoints": endpoints
    }

# 分组共线且近距离的线段
groups = []
used_labels = set()

for label1, params1 in line_params.items():
    if label1 in used_labels:
        continue
    current_group = [label1]
    used_labels.add(label1)
    slope1, abc1 = params1["slope"], params1["abc"]
    
    for label2, params2 in line_params.items():
        if label2 in used_labels:
            continue
        slope2 = params2["slope"]
        
        # 判断斜率是否近似一致
        same_dir = False
        if np.isinf(slope1) and np.isinf(slope2):
            same_dir = True
        elif not np.isinf(slope1) and not np.isinf(slope2):
            same_dir = abs(slope1 - slope2) < SLOPE_TOLERANCE
        
        if not same_dir:
            continue
        
        # 判断中点到基准直线的距离是否符合要求
        A, B, C = abc1
        mx, my = params2["mid"]
        dist = abs(A*mx + B*my + C)
        if dist < DISTANCE_TOLERANCE:
            current_group.append(label2)
            used_labels.add(label2)
    
    groups.append(current_group)

# 统计最终结果
final_count = len(groups)
final_lengths = []

for group in groups:
    # 收集组内所有端点,计算最小外接矩形的长轴长度
    all_points = []
    for label in group:
        all_points.extend(line_params[label]["endpoints"])
    all_points = np.array(all_points, dtype=np.float32)
    
    rect = cv2.minAreaRect(all_points)
    sample_length = max(rect[1])
    final_lengths.append(round(sample_length, 2))

print(f"修正后样本数量: {final_count}")
print(f"各样本长度(像素): {final_lengths}")

注意事项

  • 阈值调整:SLOPE_TOLERANCE和DISTANCE_TOLERANCE需要根据你的图像实际情况微调,比如样本越粗,距离阈值可以适当放大。
  • 方向判断优化:如果样本有轻微弯曲,可以用方向向量的夹角替代斜率判断(计算两个线段方向向量的点积,夹角小于5°即视为同方向)。
  • 端点衔接验证:可以额外加入端点距离判断,若组内线段的端点间距小于阈值,进一步确认属于同一样本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.10 16:04:51