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

基于Python的7段数码管(FND)数字识别问题求助(适配树莓派)

问题描述

正在Google Colaboratory中使用Python编写7段数码管(FND)数字识别代码,该代码是树莓派4驱动电机流程的一部分,需实时识别摄像头拍摄的秤的7段数码管数字并向电机发送信号。当前核心代码如下:

image=cv2.imread("/content/cas.jpg")
image=imutils.resize(image, height=500)

gray=cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5,5),0)
edged = cv2.Canny(blurred,50,200,255)

contours=cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
contours = grab_contours(contours)
contours = sorted(contours, key=cv2.contourArea, reverse=True)
displayCnt = None

for c in contours :
  peri = cv2.arcLength(c,True)
  approx = cv2.approxPolyDP(c, 0.02*peri, True)
  if len(approx)==4 :
    displayCnt = approx
    break

[x, y,w, h] = cv2.boundingRect(displayCnt)
cv2.rectangle(image, (x,y), (x+w,y+h), (0,0,255), 2)
plt.imshow(image)
plt.show()

warped = four_point_transform(gray, displayCnt.reshape(4,2))
output=four_point_transform(image,displayCnt.reshape(4,2))
plt.imshow(warped)
plt.show()

thresh = cv2.threshold(warped, 0, 255,
                       cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (1,5))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
plt.imshow(thresh)
plt.show()

cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
digitCnts = []

for c in cnts :
   (x, y, w, h) = cv2.boundingRect(c)
   if w >= 30 and h>=3:
      digitCnts.append(c)

for digit in digitCnts:
   [x, y, w, h] = cv2.boundingRect(digit)
   cv2.rectangle(output,(x,y),(x+w,y+h),(0,255,0),2)
plt.title('digit')
plt.imshow(output)
plt.show()

当前问题:单个数字无法被完整框选,疑似因7段数码管的连接处断裂导致。尝试调整W、H阈值但丢失了校准参数,且不想使用深度学习或机器学习技术,求修改现有代码的方法或其他可行方案。

解决方案
  • 调整形态学操作,修复断裂笔画
    原代码使用的开运算(先腐蚀后膨胀)更适合去除噪声,改用闭运算(先膨胀后腐蚀)可以闭合数码管笔画的小断裂,或者单独执行膨胀操作连接断裂部分:

    # 替换原形态学操作代码
    # 使用矩形核覆盖横向、纵向的断裂缺口
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 4))
    # 闭运算闭合笔画断裂
    thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
    
    # 或者先膨胀连接断裂,再腐蚀降噪
    # kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
    # thresh = cv2.dilate(thresh, kernel, iterations=1)
    # thresh = cv2.erode(thresh, kernel, iterations=1)
    

    调整核的尺寸(如(2,4)、(3,3))可以适配不同程度的断裂情况,确保同一数字的笔画连接成整体轮廓。

  • 按数字区域合并断裂轮廓
    数码管数字按从左到右排列,可先按轮廓的x坐标排序,再根据相邻轮廓的位置关系判断是否属于同一数字,合并后生成整体框:

    cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)
    # 按轮廓的x坐标从左到右排序
    cnts = sorted(cnts, key=lambda c: cv2.boundingRect(c)[0])
    digitCnts = []
    current_group = []
    
    for c in cnts:
        x, y, w, h = cv2.boundingRect(c)
        # 过滤过小的噪声轮廓
        if w < 8 or h < 20:
            continue
        if not current_group:
            current_group.append(c)
        else:
            # 获取当前组第一个轮廓的位置信息
            prev_x, prev_y, prev_w, prev_h = cv2.boundingRect(current_group[0])
            # 同一数字的轮廓间距小、y轴范围重叠
            if (x - (prev_x + prev_w)) < 12 and abs(y - prev_y) < prev_h // 2:
                current_group.append(c)
            else:
                # 计算当前组的整体边界框
                x_min = min([cv2.boundingRect(contour)[0] for contour in current_group])
                y_min = min([cv2.boundingRect(contour)[1] for contour in current_group])
                x_max = max([cv2.boundingRect(contour)[0] + cv2.boundingRect(contour)[2] for contour in current_group])
                y_max = max([cv2.boundingRect(contour)[1] + cv2.boundingRect(contour)[3] for contour in current_group])
                # 创建虚拟轮廓表示整体数字框
                dummy_contour = np.array([[[x_min, y_min]], [[x_max, y_min]], [[x_max, y_max]], [[x_min, y_max]]], dtype=np.int32)
                digitCnts.append(dummy_contour)
                current_group = [c]
    # 处理最后一组数字
    if current_group:
        x_min = min([cv2.boundingRect(contour)[0] for contour in current_group])
        y_min = min([cv2.boundingRect(contour)[1] for contour in current_group])
        x_max = max([cv2.boundingRect(contour)[0] + cv2.boundingRect(contour)[2] for contour in current_group])
        y_max = max([cv2.boundingRect(contour)[1] + cv2.boundingRect(contour)[3] for contour in current_group])
        dummy_contour = np.array([[[x_min, y_min]], [[x_max, y_min]], [[x_max, y_max]], [[x_min, y_max]]], dtype=np.int32)
        digitCnts.append(dummy_contour)
    

    此方法无需调整宽高阈值,直接通过位置关系合并同一数字的断裂部分,生成完整的数字框。

  • 改用自适应阈值优化笔画完整性
    原Otsu全局阈值易受光照不均影响,改用自适应阈值可根据局部区域亮度调整,减少笔画断裂:

    # 替换原阈值处理代码
    thresh = cv2.adaptiveThreshold(warped, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
    

    参数11是局部区域大小,2是阈值调整量,可根据实际画面亮度微调。

  • 基于数码管结构的轮廓过滤
    7段数码管的单个数字宽高比相对固定(通常在0.5-0.8之间),合并轮廓后可通过宽高比过滤异常框:

    # 在生成digitCnts后添加过滤逻辑
    filtered_digitCnts = []
    for contour in digitCnts:
        x, y, w, h = cv2.boundingRect(contour)
        aspect_ratio = w / float(h)
        # 保留符合数码管数字宽高比的框
        if 0.5 <= aspect_ratio <= 0.8:
            filtered_digitCnts.append(contour)
    digitCnts = filtered_digitCnts
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 09:54:51