首页 论坛 置顶 使用Python和OpenCV从图像中提取和保存字符

正在查看 1 个帖子:1-1 (共 1 个帖子)
  • 作者
    帖子
  • #14702

    通常情况下,当我们想要从图像中提取文本时,大家可能会想到 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

正在查看 1 个帖子:1-1 (共 1 个帖子)
  • 哎呀,回复话题必需登录。