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

如何用Python统计含噪网格图中的阴影与非阴影矩形?技术咨询

解决含噪网格图中阴影/非阴影矩形统计的实用思路

我太懂这种困境了——带噪声的网格图总能把常规的CV方法搞崩,轮廓检测被小噪点干扰得一团糟,霍夫线检测出一堆冗余线条后又不知道怎么落地。结合我处理类似任务的经验,给你一套更针对性的推进方案:

第一步:先把噪声干掉,预处理是关键

所有后续操作的基础都是干净的图像,之前的方法失效大概率是预处理没做足:

  • 自适应阈值化:别用普通的cv2.threshold,网格图往往存在光照不均,cv2.adaptiveThreshold能根据局部区域的灰度值调整阈值,完美区分网格线和背景。代码示例:
    import cv2
    import numpy as np
    
    img = cv2.imread("your_grid_image.jpg", 0)  # 转灰度图
    # 自适应高斯阈值,INV是让网格线变成白色,背景黑色
    thresh = cv2.adaptiveThreshold(
        img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2
    )
    
  • 形态学清理:用开运算(先腐蚀再膨胀)去掉小噪点,闭运算填补网格线的细微缺口。选矩形核适配网格的形状:
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
    cleaned_img = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=1)
    cleaned_img = cv2.morphologyEx(cleaned_img, cv2.MORPH_CLOSE, kernel, iterations=1)
    

第二步:二选一提取网格结构

根据你的网格规则程度,选下面两种方案:

方案A:霍夫线聚类(适合规则网格)

如果你已经用霍夫线检测出线条,接下来的核心是去重聚类,得到真正的网格线:

  1. 分类线条:把检测到的线分成水平和垂直两类(通过斜率判断,水平线条y坐标变化极小,垂直线条x坐标变化极小)
  2. 聚类去重:把同一位置的重复线条合并,比如对水平线条的y坐标排序后,用阈值合并接近的值(阈值根据你的网格间距调整):
    # 假设霍夫线检测结果是lines = cv2.HoughLinesP(cleaned_img, ...)
    horizontal_ys = []
    vertical_xs = []
    for line in lines:
        x1, y1, x2, y2 = line[0]
        if abs(y2 - y1) < 5:  # 水平线条
            horizontal_ys.append((y1 + y2) // 2)
        elif abs(x2 - x1) < 5:  # 垂直线条
            vertical_xs.append((x1 + x2) // 2)
    
    # 去重水平线条
    horizontal_ys = sorted(list(set(horizontal_ys)))
    filtered_h = []
    prev_y = None
    for y in horizontal_ys:
        if prev_y is None or y - prev_y > 4:  # 间距阈值,按需调整
            filtered_h.append(y)
            prev_y = y
    # 垂直线条同理处理得到filtered_v
    
  3. 生成矩形:有了干净的水平和垂直坐标列表,两两组合就能得到所有矩形的四个顶点(比如(filtered_v[i], filtered_h[j])作为左上角,(filtered_v[i+1], filtered_h[j+1])作为右下角)

方案B:优化轮廓检测(适合不规则网格)

如果之前用轮廓检测失败,试试加筛选条件:

  1. 找轮廓后,用cv2.approxPolyDP把轮廓近似成多边形,只保留4个顶点的轮廓(矩形特征)
  2. 额外筛选:排除面积太小的噪点轮廓,检查轮廓的宽高比是否符合网格的大致比例,甚至可以验证四个角是否为直角
    contours, _ = cv2.findContours(cleaned_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    rect_contours = []
    for cnt in contours:
        area = cv2.contourArea(cnt)
        if area < 50 or area > 5000:  # 过滤过小/过大的轮廓
            continue
        # 近似多边形
        epsilon = 0.02 * cv2.arcLength(cnt, True)
        approx = cv2.approxPolyDP(cnt, epsilon, True)
        if len(approx) == 4:  # 矩形是4个顶点
            rect_contours.append(approx)
    

第三步:区分阴影与非阴影矩形

不管用哪种方法得到矩形,判断阴影的核心是区域灰度统计:

  1. 对每个矩形区域,提取灰度均值(如果是彩色图可以转成HSV取亮度通道)
  2. 提前统计非阴影区域的平均灰度值,设定一个阈值(比如阴影区域的均值是非阴影的70%-80%),低于阈值的就是阴影矩形
    # 假设非阴影区域的均值已经通过采样得到non_shadow_mean
    for rect in rect_contours:
        # 获取矩形的边界框
        x, y, w, h = cv2.boundingRect(rect)
        roi = img[y:y+h, x:x+w]
        mean_gray = np.mean(roi)
        if mean_gray < non_shadow_mean * 0.8:
            print("这是阴影矩形")
        else:
            print("这是非阴影矩形")
    

最后补充几个小技巧

  • 如果网格线很细,可以先做一次膨胀操作加粗线条,方便后续检测
  • 对于噪声特别大的图,可以试试高斯模糊(cv2.GaussianBlur)配合自适应阈值,效果会更好
  • 统计矩形数量时,注意排除那些不完整的矩形(比如只有三条边的),可以通过检查矩形的四条边是否都在网格线中,或者区域内的像素覆盖率

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:28:16