我在Jupyter笔记本上使用Python编写代码,以识别7段显示器(FND)上的数字。
我使用了opencv
并获取了图像的边缘。
import cv2import matplotlib.pyplot as plt def detect_edge(image): ''' 检测边缘的函数 ''' image_with_edges = cv2.Canny(image , 100, 200) images = [image , image_with_edges] location = [121, 122] for loc, img in zip(location, images): plt.subplot(loc) plt.imshow(img, cmap='gray') plt.savefig('edge.png') plt.show()image = cv2.imread('/Users/USER/Desktop/test/test2.png', 0)detect_edge(image)
这是我从上述代码中得到的样本输入和输出的截图:
我不知道接下来该怎么做。我想识别这个例子中的数字51.12。
我应该先裁剪出数字所在的FND部分,然后再进行深度学习吗?
接下来我应该怎么做?
回答:
我觉得对于这样的问题使用CNN是小题大做。特别是考虑到这是7段显示器,我们应该能够在不使用这种复杂方法的情况下解决这个问题。
你已经标记了角点,所以我假设你可以可靠地裁剪并旋转(使其平整)显示器。
我们只想获取数字。在这种情况下,我首先转换为LAB颜色空间,并在b通道上进行阈值处理。
然后我使用opencv的findContours来标记周边:
之后我裁剪出每个单独的数字:
然后我单独查找每个段,并根据哪些段是活跃的来确定数字(对于数字1,我使用了一个特殊情况,检查了宽度和高度的比例)。
这是我使用的代码(两个文件)segments.py
import numpy as npclass Segments: def __init__(self): # 创建一个7段模型 self.flags = []; self.segments = []; h1 = [[0, 1.0],[0, 0.1]]; # 0 h2 = [[0, 1.0],[0.45, 0.55]]; # 1 h3 = [[0, 1.0],[0.9, 1.0]]; # 2 vl1 = [[0, 0.2],[0, 0.5]]; # 3 # 左上 vl2 = [[0, 0.2],[0.5, 1.0]]; # 4 vr1 = [[0.8, 1.0],[0, 0.5]]; # 5 # 右上 vr2 = [[0.8, 1.0], [0.5, 1.0]]; # 6 self.segments.append(h1); self.segments.append(h2); self.segments.append(h3); self.segments.append(vl1); self.segments.append(vl2); self.segments.append(vr1); self.segments.append(vr2); # 处理图像并设置标志 def digest(self, number): # 重置标志 self.flags = []; # 检查是否为1 h, w = number.shape[:2]; if w < 0.5 * h: self.flags.append(5); self.flags.append(6); return; # 检查段 for a in range(len(self.segments)): seg = self.segments[a]; # 获取边界 xl, xh = seg[0]; yl, yh = seg[1]; # 转换为像素坐标 xl = int(xl * w); xh = int(xh * w); yl = int(yl * h); yh = int(yh * h); sw = xh - xl; sh = yh - yl; # 检查 count = np.count_nonzero(number[yl:yh, xl:xh] == 255); if count / (sh * sw) > 0.5: # 0.5是一个灵敏度度量 self.flags.append(a); # 返回存储的数字(存储在self.flags中) def getNum(self): # 硬编码输出 if self.flags == [0,2,3,4,5,6]: return 0; if self.flags == [5,6]: return 1; if self.flags == [0,1,2,4,5]: return 2; if self.flags == [0,1,2,5,6]: return 3; if self.flags == [1,3,5,6]: return 4; if self.flags == [0,1,2,3,6]: return 5; if self.flags == [0,1,2,3,4,6]: return 6; if self.flags == [0,5,6]: return 7; if self.flags == [0,1,2,3,4,5,6]: return 8; if self.flags == [0,1,2,3,5,6]: return 9; # 错误 return -1;
main.py
import cv2import numpy as npfrom segments import Segments# 加载图像img = cv2.imread("seg7.jpg");# 裁剪img = img[300:800,100:800,:];# 转换为LAB颜色空间lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB);l,a,b = cv2.split(lab);# 显示cv2.imshow("orig", img);# 闭运算kernel = np.ones((5,5), np.uint8);# 阈值参数low = 165;high = 200;iters = 3;# 制作副本copy = b.copy();# 阈值处理thresh = cv2.inRange(copy, low, high);# 膨胀for a in range(iters): thresh = cv2.dilate(thresh, kernel);# 腐蚀for a in range(iters): thresh = cv2.erode(thresh, kernel);# 显示图像cv2.imshow("thresh", thresh);cv2.imwrite("threshold.jpg", thresh);# 开始处理_, contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);# 绘制for contour in contours: cv2.drawContours(img, [contour], 0, (0,255,0), 3);# 获取每个数字的边界bounds = [];h, w = img.shape[:2];for contour in contours: left = w; right = 0; top = h; bottom = 0; for point in contour: point = point[0]; x, y = point; if x < left: left = x; if x > right: right = x; if y < top: top = y; if y > bottom: bottom = y; tl = [left, top]; br = [right, bottom]; bounds.append([tl, br]);# 裁剪出每个数字cuts = [];number = 0;for bound in bounds: tl, br = bound; cut_img = thresh[tl[1]:br[1], tl[0]:br[0]]; cuts.append(cut_img); number += 1; cv2.imshow(str(number), cut_img);# 字体 font = cv2.FONT_HERSHEY_SIMPLEX;# 创建一个段模型model = Segments();index = 0;for cut in cuts: # 保存图像 cv2.imwrite(str(index) + "_" + str(number) + ".jpg", cut); # 处理 model.digest(cut); number = model.getNum(); print(number); cv2.imshow(str(index), cut); # 再次绘制并保存 h, w = cut.shape[:2]; drawn = np.zeros((h, w, 3), np.uint8); drawn[:, :, 0] = cut; drawn = cv2.putText(drawn, str(number), (10,30), font, 1, (0,0,255), 2, cv2.LINE_AA); cv2.imwrite("drawn" + str(index) + "_" + str(number) + ".jpg", drawn); index += 1; # cv2.waitKey(0);# 显示cv2.imshow("contours", img);cv2.imwrite("contours.jpg", img);cv2.waitKey(0);
我不能保证这总是有效的,但在进行一些调整后应该可以使用。记得如果图像不是平的,要对其进行旋转。段模型假设数字大多是直立的。