使用Python和OpenCV从图像中提取和保存字符

通常情况下,当我们想要从图像中提取文本时,大家可能会想到 Google Translate,它可以上传图片或用手机摄像头拍照,然后就能得到翻译结果或想要的文本。然而,今天我们将带您了解其背后的工作原理,但在这篇文章中仍然只是一个小的切入点,距离 Google Translate 的工作机制还有一定的距离。

好的,那我们就开始吧。在这篇文章中,我们将讨论图像处理(Image Processing)和 OpenCV 的技术,这些大家可能已经有些耳熟能详。我们将利用这些技术将图像中的字符分离成单个字符的小图像,然后将每个字符保存为单独的图像文件,这是进行光学字符识别(OCR,Optical Character Recognition)工作的重要基础。

那么我来补充一下 OCR 的相关说明:光学字符识别(Optical Character Recognition,简称 OCR)是一个机械或电子过程,用于将手写或打印文本的图像转换为计算机可编辑的文本。图像捕捉可以通过扫描仪、数码相机等设备完成。OCR 是识别模式、人工智能和计算机视觉领域的一个研究方向。

首先,我们需要安装库

pip install imutils

这是一个用于OpenCV的Python扩展库,提供了一些便利功能,例如:
轮廓排序、图像缩放(resize)、自动旋转图像、角度/坐标转换。这将是我们此次工作的主要库。

 

步骤 1 下载图像并转换为灰度图

import cv2
from imutils import contours

image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

图像描述

我们将从加载包含文字的图像开始,并将其从彩色图像转换为黑白图像,以便于后续处理。

步骤 2 使用 Otsu 的阈值分离背景与文字

thresh = cv2.threshold(
    gray, 0, 255,
    cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV
)[1]

图片描述

接下来,我们将使用 Otsu 的阈值方法来自动确定中间值,以便将背景与字符分开。我们将其设置为反转 (THRESH_BINARY_INV),以使字符为白色,背景为黑色。

步骤 3 寻找字符的边界并从左到右排列

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

我们将使用 cv2.findContours() 来找到每个字符的边界,然后使用 imutils 库中的 sort_contours() 函数将它们从左到右进行排序,这适合从左到右阅读的英语。

 

步骤4:逐个字符裁剪ROI并保存图像

ROI_number = 0
for c in cnts:
    area = cv2.contourArea(c)
    if area > 10:
        x,y,w,h = cv2.boundingRect(c)
        ROI = image[y:y+h, x:x+w]
        cv2.imwrite('ROI_{}.png'.format(ROI_number), ROI)
        cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
        ROI_number += 1

 

图片描述

图片描述
在每个轮廓中循环检查区域是否大于10,以过滤噪声
裁剪出包围字符的边界框
将每个图像保存为文件 ROI_0.png, ROI_1.png, …
同时使用 cv2.rectangle() 绘制绿色框,以显示结果,查看程序是否正确检测

 

步骤5:显示结果

cv2.imshow('thresh', thresh)
cv2.imshow('image', image)
cv2.waitKey()
显示阈值图像和带有文本框的实际图像

然后等待用户按下按钮以关闭窗口

 

更多示例

 

我们将尝试使用其他图像来测试这篇关于使用Python和OpenCV进行图像中的文本分离和保存的文章是否可以在实际中使用

步骤 1 加载图像并转换为灰度图

import cv2
from imutils import contours

image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

图片描述
我们将从加载包含文字的图像开始,并将其从彩色图像转换为黑白图像,以便后续处理更加简便。

步骤 2 使用 Otsu 的阈值来分离背景与字符

thresh = cv2.threshold(
    gray, 0, 255,
    cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV
)[1]

图片描述

接下来,我们将使用 Otsu 的阈值方法来自动确定中间值,以便将背景与字符分离。我们将执行反转操作 (THRESH_BINARY_INV),使字符呈现为白色,背景呈现为黑色。

步骤 3 寻找字符的边界并从左到右排列

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

我们将使用 cv2.findContours() 来找到每个字符的轮廓,然后使用 imutils 库中的 sort_contours() 函数将其从左到右排序,这适合从左到右阅读的英语。

步骤 4 按字母逐个裁剪 ROI 并保存图像

ROI_number = 0
for c in cnts:
    area = cv2.contourArea(c)
    if area > 10:
        x,y,w,h = cv2.boundingRect(c)
        ROI = image[y:y+h, x:x+w]
        cv2.imwrite('ROI_{}.png'.format(ROI_number), ROI)
        cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
        ROI_number += 1

 

图片描述

图片描述

在每个轮廓中循环检查面积是否大于10,以过滤噪声
裁剪出包围字符的边界框
将每个图像保存为文件 ROI_0.png, ROI_1.png, …
同时使用 cv2.rectangle() 绘制绿色框以显示结果,以查看程序是否正确检测到

 

骤 5 显示结果

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

图片描述

显示阈值图像和带有文本框的实际图像
然后等待用户按下按钮以关闭窗口

 

所有代码

import cv2
from imutils import contours

# 加载图像,转换为灰度图,使用大津法阈值
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV)[1]

# 查找轮廓,从左到右排序,然后裁剪
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts, _ = contours.sort_contours(cnts, method="left-to-right")

# 使用轮廓面积进行过滤并提取感兴趣区域(ROI)
ROI_number = 0
for c in cnts:
    area = cv2.contourArea(c)
    if area > 10:
        x,y,w,h = cv2.boundingRect(c)
        ROI = image[y:y+h, x:x+w]
        cv2.imwrite('ROI_{}.png'.format(ROI_number), ROI)
        cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
        ROI_number += 1

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

总结

在本文中,我们展示了如何使用图像处理(Image Processing)和OpenCV从图像中分离并保存字符。通过附加的示例,我们将学习如何使用OpenCV将图像转换为可用格式。
通过使用阈值和轮廓从图像中分离字符,并将字符图像裁剪并保存为子文件。该技术可以作为准备OCR系统数据的初步步骤,或者作为独立工具从图像中提取文本,也可以在后续工作中进一步扩展。

参考文献

https://stackoverflow.com/questions/60515216/extracting-and-saving-characters-from-an-image

更多