如何在Python中应用轮廓后从图像中提取文本?

3

我已经在一张大图片上应用了轮廓线,并得到了以下裁剪过的部分图片:

enter image description here

enter image description here

但是现在,不使用任何机器学习模型,我该如何将这幅图像转换为文本变量?我了解到模板匹配,但我不知道从哪里开始。我有字母和数字的图像(根据它们的值命名)存储在一个目录中,但怎样才能匹配它们并将获取到的文本作为字符串呢?我不想使用pyTesseract等机器学习模型或库。

非常感谢任何帮助。

编辑:

我尝试过的模板匹配代码。

def templateMatch(image):
    path = "location"

    for image_path in os.listdir(path + "/characters-images"):
        template = cv2.imread(os.path.join(path, "characters-images", image_path))
        template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)

        template = template.astype(np.uint8)
        image = image.astype(np.uint8)

        res = cv2.matchTemplate(template, image, cv2.TM_SQDIFF_NORMED)
        mn, _, mnLoc, _ = cv2.minMaxLoc(res)

        if res is not None:
            return image_path.replace(".bmp", "")


def match(image):
    plate = ""
    # mask = np.zeros(image.shape, dtype=np.uint8)
    # print(image.shape)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # print(image.shape)
    # print(image)
    thresh = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

    cnts = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    (cnts, _) = contours.sort_contours(cnts, method="left-to-right")

    for con in cnts:
        area = cv2.contourArea(con)

        if 800 > area > 200:
            x, y, w, h = cv2.boundingRect(con)
            # cv2.drawContours(mask, [c], 1, (255, 0, 0), 2)
            temp = thresh[y:y+h, x:x+w]

            character = templateMatching(temp)

            if character is not None:
                plate += character

    return plate

你在模板匹配方面尝试了什么?你需要匹配每个字母,并使用找到的位置将这些字母按顺序设置。 - T A
@TA 我已经添加了我尝试过的代码,但它在一次后会出现异常,并且仅检测上面图像中的333333而不是其他字符。 - Panda
2个回答

3
我该如何将图像实际转换为文本变量?我了解到模板匹配,但我不知道如何继续下一步。
模板匹配用于在给定模板的情况下定位图像中的对象,而不是从图像中提取文本。将模板与图像中对象的位置进行匹配将无法帮助将文本作为字符串获取。有关如何应用动态比例可变模板匹配的示例,请查看如何隔离轮廓内部的所有内容、缩放并测试与图像的相似性?Python OpenCV线检测以检测X符号中的图像。我不明白为什么你不想使用OCR库。如果您想将图像中的文本提取为字符串变量,则应使用某种类型的深度/机器学习。 PyTesseract可能是最简单的。这里是使用PyTesseract的解决方案。
所需的思路是使用Otsu阈值获得二进制图像,然后执行轮廓面积和纵横比过滤以提取字母/数字ROI。从这里开始,我们使用Numpy切片将每个ROI裁剪到空白蒙版上,然后使用Pytesseract应用OCR。以下是每个步骤的可视化:
二进制图像

以绿色突出显示的检测到的ROI

在准备进行OCR的空白蒙版上隔离ROI

我们使用--psm 6配置选项来告诉Pytesseract假设文本块是统一的。请查看此处获取更多配置选项。 Pytesseract的结果:

XS NB 23

代码

import cv2
import numpy as np
import pytesseract

pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"

# Load image, create mask, grayscale, Otsu's threshold
image = cv2.imread('1.png')
mask = np.zeros(image.shape, dtype=np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# Filter for ROI using contour area and aspect ratio
cnts = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    area = cv2.contourArea(c)
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.05 * peri, True)
    x,y,w,h = cv2.boundingRect(approx)
    aspect_ratio = w / float(h)
    if area > 2000 and aspect_ratio > .5:
        mask[y:y+h, x:x+w] = image[y:y+h, x:x+w]

# Perfrom OCR with Pytesseract
data = pytesseract.image_to_string(mask, lang='eng', config='--psm 6')
print(data)

cv2.imshow('thresh', thresh)
cv2.imshow('mask', mask)
cv2.waitKey()

谢谢您的见解,但我并不想使用pytesseract.image_to_string,而是想匹配两个图像,如果找到匹配,则获取图像的名称(该名称将与图像字符相同)。例如,当将轮廓与所有图像进行比较时,图像N命名为N.jpg应该与第一个轮廓匹配,然后我就可以知道N是车牌号码中的第一个字符。 - Panda
我正在尝试不使用pytesseract来更好地理解算法和底层原理,如果能得到一些帮助,我将不胜感激。 - Panda
1
那是一种非常低效的方法,因为它只适用于模板是大型“气泡”字母的情况,如果您使用这种方法来处理普通文本,则无法正常工作。如果您真的想以这种方式做,请查看两个模板匹配链接。另外一个需要考虑的问题是多个字母。如果您为字母'a'进行模板匹配,将会有许多匹配项,因此您需要确定您要查找哪一个。 - nathancy

0
一种选择是考虑字符周围的边界框,并计算手头字符与训练集中的字符之间的相关性分数。您将保留最大的相关性分数。(如果您在二进制图像上工作,则为SAD、SSD、归一化灰度相关或仅汉明距离)。
您需要开发一个合适的策略,以确保测试字符和学习字符具有兼容的大小并正确重叠。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接