### 在图像中拆分数字

我获得了很多手工填写的报告。报告中的一列包含时间戳,我希望尝试在不手动查看每份报告的情况下识别这些时间戳。

我正在考虑将时间(例如00:30)拆分为四个数字,并通过训练过的MNIST分类器来识别实际的时间戳。

当我在Photoshop中手动提取这四个数字并通过MNIST分类器运行时,效果非常好。但到目前为止,我还没有找到如何编程地将数字序列拆分为单个数字的方法。我尝试使用OpenCV中的不同类型的轮廓查找,但效果并不稳定。

有什么建议吗?

我已经添加了一张截图,展示了报告中相关的一些列。


回答:

我会这样做(只要是想法就不提供代码,你可以测试一下是否有效):

  1. 如Rick M.在上面建议的,提取每个数字组的区域。这样你将得到许多Kl [hour]的矩形图像。

  2. 对于每个矩形,使用OpenCV的轮廓功能提取每个ROI。如果不需要Kl,可以删除它(你知道这个ROI的尺寸,可以用img.shape计算,它们大致相同)。

  3. 使用上述相同的脚本提取所有数字。你可以查看我的问题/答案,找到一些执行此操作的代码片段。有些情况下你会遇到下划线的问题。在Stack Overflow上搜索这个问题,有几种完整的解决方案和代码。

  4. 现在,关于拆分。我们知道ROI是以小时格式的,即hh:mm(或4个数字)。一个简单(且非常原始)的解决方案是将包含2个数字的ROI一分为二。这是一个粗糙的解决方案,但在你的情况下应该表现良好,因为附着的数字只有2个。

  5. 有些数字输出时会“缺少部分”。这可以通过使用一些侵蚀/膨胀/骨架化来避免。

这里没有字母,只有数字,所以MNIST应该能很好地工作(但请记住,不会完美)。

总之,提取数据不是难事,但识别数字会让你稍微出点汗。

我希望能尽快提供一些代码来展示上述步骤。

编辑 – 代码

这是我编写的一些代码。最终输出是这样的:

output

该代码对这张图片的效果是100%的,所以,如果对你不起作用,请检查文件夹/路径/模块安装

希望这对你有帮助。


import cv2
import numpy as np
# 1 - 移除左侧的垂直线
img = cv2.imread('image.jpg', 0)
# gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(img, 100, 150, apertureSize=5)
lines = cv2.HoughLines(edges, 1, np.pi / 50, 50)
for rho, theta in lines[0]:
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a * rho
    y0 = b * rho
    x1 = int(x0 + 1000 * (-b))
    y1 = int(y0 + 1000 * (a))
    x2 = int(x0 - 1000 * (-b))
    y2 = int(y0 - 1000 * (a))
    cv2.line(img, (x1, y1), (x2, y2), (255, 255, 255), 10)
cv2.imshow('marked', img)
cv2.waitKey(0)
cv2.imwrite('image.png', img)
# 2 - 移除水平线
img = cv2.imread("image.png")
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_orig = cv2.imread("image.png")
img = cv2.bitwise_not(img)
th2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 15, -2)
cv2.imshow("th2", th2)
cv2.waitKey(0)
cv2.destroyAllWindows()
horizontal = th2
rows, cols = horizontal.shape
# 反转图像,使线条变为黑色以便于掩码
horizontal_inv = cv2.bitwise_not(horizontal)
# 使用提供的掩码进行位运算与操作以掩码线条
masked_img = cv2.bitwise_and(img, img, mask=horizontal_inv)
# 恢复图像到正常状态
masked_img_inv = cv2.bitwise_not(masked_img)
cv2.imshow("masked img", masked_img_inv)
cv2.waitKey(0)
cv2.destroyAllWindows()
horizontalsize = int(cols / 30)
horizontalStructure = cv2.getStructuringElement(cv2.MORPH_RECT, (horizontalsize, 1))
horizontal = cv2.erode(horizontal, horizontalStructure, (-1, -1))
horizontal = cv2.dilate(horizontal, horizontalStructure, (-1, -1))
cv2.imshow("horizontal", horizontal)
cv2.waitKey(0)
cv2.destroyAllWindows()
# step1
edges = cv2.adaptiveThreshold(horizontal, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 3, -2)
cv2.imshow("edges", edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
# step2
kernel = np.ones((1, 2), dtype="uint8")
dilated = cv2.dilate(edges, kernel)
cv2.imshow("dilated", dilated)
cv2.waitKey(0)
cv2.destroyAllWindows()
im2, ctrs, hier = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 排序轮廓
sorted_ctrs = sorted(ctrs, key=lambda ctr: cv2.boundingRect(ctr)[0])
for i, ctr in enumerate(sorted_ctrs):
    # 获取边界框
    x, y, w, h = cv2.boundingRect(ctr)
    # 获取ROI
    roi = img[y:y + h, x:x + w]
    # 显示ROI
    rect = cv2.rectangle(img_orig, (x, y), (x + w, y + h), (255, 255, 255), -1)
cv2.imshow('areas', rect)
cv2.waitKey(0)
cv2.imwrite('no_lines.png', rect)
# 3 - 检测和提取ROI
image = cv2.imread('no_lines.png')
cv2.imshow('i', image)
cv2.waitKey(0)
# 灰度化
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow('gray', gray)
cv2.waitKey(0)
# 二值化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)
cv2.imshow('thresh', thresh)
cv2.waitKey(0)
# 膨胀
kernel = np.ones((8, 45), np.uint8)  # 这些值仅为此图像设置 - 需要根据不同图像进行调整
img_dilation = cv2.dilate(thresh, kernel, iterations=1)
cv2.imshow('dilated', img_dilation)
cv2.waitKey(0)
# 查找轮廓
im2, ctrs, hier = cv2.findContours(img_dilation.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 排序轮廓
sorted_ctrs = sorted(ctrs, key=lambda ctr: cv2.boundingRect(ctr)[0])
for i, ctr in enumerate(sorted_ctrs):
    # 获取边界框
    x, y, w, h = cv2.boundingRect(ctr)
    # 获取ROI
    roi = image[y:y + h, x:x + w]
    # 显示ROI
    # cv2.imshow('segment no:'+str(i),roi)
    cv2.rectangle(image, (x, y), (x + w, y + h), (255, 255, 255), 1)
    # cv2.waitKey(0)
    # 仅保存包含有效信息的ROI
    if h > 20 and w > 75:
        cv2.imwrite('roi\\{}.png'.format(i), roi)
cv2.imshow('marked areas', image)
cv2.waitKey(0)

接下来的步骤是:

  1. 理解我写的内容;)。这是最重要的一步。

  2. 使用上面的代码片段(特别是步骤3),你可以删除提取图像中剩余的Kl

  3. 为每张图片创建文件夹并提取数字。

  4. 使用MNIST识别每个数字。

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注