基于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
相关产品推荐
相关产品推荐

