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

建筑项目图纸附加文件:云状图形及内嵌数字三角形检测

建筑图纸附加文件检测:云状图形/带数字三角形的鲁棒性实现

问题背景

需要判断图像是否为建筑项目图纸的附加文件,核心是检测图像里的云状对象,如果这个实现难度太高,退而求其次检测内部带数字的三角形也可以。目前用OpenCV写的Python代码只能处理只有两个云状图形的简单图,碰到有大量线条、文字的复杂图像就直接失效,甚至还会误识别。

现有问题根源

简单场景里用的基础检测逻辑(比如靠轮廓面积、简单多边形匹配)扛不住复杂背景的干扰:

  • 密密麻麻的线条、文字会生成一堆噪声轮廓,直接把目标轮廓给盖过去了
  • 云状图形本身边缘不规则,在复杂背景下根本没法准确提取
  • 基础形状匹配对轮廓的完整性、纯净度要求太高,一有干扰就匹配失败

改进方案

方案一:让云状图形检测更抗造

针对复杂背景里的云状图形,可以按这几步优化:

  1. 先做降噪预处理
    • 先用cv2.GaussianBlur()做高斯模糊,把细线条和文字的干扰弱化
    • 换成自适应阈值二值化cv2.adaptiveThreshold(),比全局阈值更能应对光照不均和复杂背景
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (5,5), 0)
    thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
    
  2. 精准筛选轮廓特征
    • 提取轮廓后先过滤掉面积太小或太大的,把文字和大背景区域排除
    • 计算轮廓的形状复杂度:云状图形的近似多边形顶点数远多于普通几何图形,用cv2.approxPolyDP()控制近似精度后统计顶点数;同时算圆度(4*math.pi*area / (perimeter**2)),云状图形的圆度一般在规则圆形和尖锐多边形之间
    import math
    contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for cnt in contours:
        area = cv2.contourArea(cnt)
        # 根据实际场景调整面积阈值
        if area < 100 or area > 10000:
            continue
        perimeter = cv2.arcLength(cnt, True)
        approx = cv2.approxPolyDP(cnt, 0.02*perimeter, True)
        circularity = 4*math.pi*area / (perimeter**2)
        # 云状图形的典型特征:顶点数多(比如>15),圆度适中(0.3-0.8)
        if len(approx) > 15 and 0.3 < circularity < 0.8:
            cv2.drawContours(img, [cnt], -1, (0,255,0), 2)
    
  3. 用形态学操作强化轮廓
    • 先开运算(腐蚀+膨胀)去掉小噪声轮廓,再闭运算填补云状图形内部的小空洞,把目标轮廓变清晰
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
    thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
    thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
    

方案二:检测内部带数字的三角形

如果云状检测实在搞不定,就转去检测带数字的三角形,步骤如下:

  1. 先揪出三角形轮廓
    • 预处理后提取轮廓,通过近似多边形筛选出顶点数为3的轮廓
    contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for cnt in contours:
        approx = cv2.approxPolyDP(cnt, 0.04*cv2.arcLength(cnt, True), True)
        if len(approx) == 3:
            x,y,w,h = cv2.boundingRect(approx)
            roi = gray[y:y+h, x:x+w]
    
  2. 检查三角形内部的数字
    • 对提取的ROI区域做二值化,要么用cv2.matchTemplate()匹配提前做的0-9数字模板,要么用pytesseract这类OCR工具识别区域里有没有数字
    import pytesseract
    roi_thresh = cv2.threshold(roi, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
    # 只识别数字,避免文字干扰
    text = pytesseract.image_to_string(roi_thresh, config='--psm 10 --oem 3 -c tessedit_char_whitelist=0123456789')
    if text.strip().isdigit():
        cv2.drawContours(img, [approx], -1, (0,0,255), 2)
    
  3. 验证三角形的真实性
    • 计算三角形的边长比例,排除那些长得像三角但实际不是的干扰轮廓

测试建议

  • 多找些不同复杂程度的样本图来测,根据实际情况调整面积、顶点数、圆度这些阈值
  • 碰到误识别的情况,分析下干扰轮廓的特征,针对性优化筛选条件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 11:55:22