OpenCV OCR实现提取图片文本的完整代码

 更新时间:2026年05月20日 08:28:32   作者:weixin_30777913  
本文主要介绍了使用OpenCV和EasyOCR处理图片并提取文字的流程,首先预处理图片,包括灰度化、去噪、对比度增强等锐化等步骤,此方法适用于处理低质量图片并提取其中的文字,希望对大家有所帮助

完整代码

遍历当前目录及所有子目录下的常见图片,使用 OpenCV 进行多种图像增强,然后调用 EasyOCR 提取文字,并按段落合并同一段中的行,最后把所有结果写入一个带时间戳的文本文件。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import datetime
import cv2
import numpy as np
import easyocr
# ---------- 图像预处理 ----------
def preprocess_image(image_path):
    """
    使用 OpenCV 对图片进行一系列增强,以提高 OCR 识别率。
    返回处理后的灰度图(numpy 数组),可直接送入 EasyOCR。
    """
    # 读取图片(支持中文路径)
    with open(image_path, 'rb') as f:
        data = np.frombuffer(f.read(), dtype=np.uint8)
    img = cv2.imdecode(data, cv2.IMREAD_COLOR)
    if img is None:
        raise ValueError(f"无法读取图片:{image_path}")
    # 1. 转灰度
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 2. 去噪(非局部均值去噪,保留边缘)
    denoised = cv2.fastNlMeansDenoising(gray, None, h=10, templateWindowSize=7, searchWindowSize=21)
    # 3. 对比度增强(CLAHE)
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
    enhanced = clahe.apply(denoised)
    # 4. 轻微锐化(可选,改善边缘)
    kernel_sharpen = np.array([[0, -1, 0],
                               [-1, 5, -1],
                               [0, -1, 0]])
    sharpened = cv2.filter2D(enhanced, -1, kernel_sharpen)
    # 5. 尺寸调整:如果图片过小,放大到至少 800 像素宽(保持比例)
    height, width = sharpened.shape[:2]
    if width < 800:
        scale = 800.0 / width
        new_w = int(width * scale)
        new_h = int(height * scale)
        sharpened = cv2.resize(sharpened, (new_w, new_h), interpolation=cv2.INTER_CUBIC)
    return sharpened
# ---------- 段落合并 ----------
def group_into_paragraphs(results, y_gap_ratio=1.5):
    """
    将 EasyOCR 的检测结果(bbox, text, confidence)按垂直距离合并为段落。
    - 首先按 top 坐标排序所有文本行。
    - 如果当前行的 top 与上一段落最后一行的 bottom 的距离小于
      该段落平均行高的 y_gap_ratio 倍,则认为属于同一段落。
    - 每个段落内的行按照从上到下的顺序用空格连接。
    """
    if not results:
        return []
    # 给每个框计算 top, bottom, center_y, center_x
    processed = []
    for (bbox, text, conf) in results:
        # bbox 是四个点 [[x1,y1],[x2,y2],[x3,y3],[x4,y4]]
        pts = np.array(bbox)
        top = np.min(pts[:, 1])
        bottom = np.max(pts[:, 1])
        center_y = (top + bottom) / 2.0
        center_x = (np.min(pts[:, 0]) + np.max(pts[:, 0])) / 2.0
        height = bottom - top
        processed.append({
            'bbox': bbox,
            'text': text,
            'conf': conf,
            'top': top,
            'bottom': bottom,
            'center_y': center_y,
            'center_x': center_x,
            'height': height
        })
    # 按 top 排序(从上到下)
    processed.sort(key=lambda x: x['top'])
    paragraphs = []
    current_para = []
    para_avg_height = 0.0
    for item in processed:
        if not current_para:
            current_para.append(item)
            para_avg_height = item['height']
        else:
            # 上一行的 bottom 与当前行的 top 之间的间隙
            last_bottom = current_para[-1]['bottom']
            gap = item['top'] - last_bottom
            # 使用当前段落平均行高计算阈值
            threshold = para_avg_height * y_gap_ratio if para_avg_height > 0 else 20
            if gap < threshold:
                current_para.append(item)
                # 更新平均行高
                heights = [x['height'] for x in current_para]
                para_avg_height = sum(heights) / len(heights)
            else:
                # 保存当前段落,开始新段落
                paragraphs.append(current_para)
                current_para = [item]
                para_avg_height = item['height']
    if current_para:
        paragraphs.append(current_para)
    # 将每个段落内的文本按顺序(已经是 top 顺序)用空格合并
    merged_paragraphs = []
    for para in para_inner:
        # 同一段落内可能同一行有多个框(按 x 排序)
        # 这里简单按 top 归为一组视为一行,然后行间用空格连接
        # 实际上 EasyOCR 一般返回的是行级框,这里保留后续扩展能力
        lines = []
        while para:
            # 取第一行(最小 top)
            first = para[0]
            line_top = first['top']
            line_bottom = first['bottom']
            # 把所有 top 相近的框归为同一行
            same_line = [x for x in para if abs(x['top'] - line_top) < first['height'] * 0.5]
            # 同一行内按 center_x 排序
            same_line.sort(key=lambda x: x['center_x'])
            line_text = ' '.join([x['text'] for x in same_line])
            lines.append(line_text)
            # 移除已处理的行
            para = [x for x in para if x not in same_line]
        # 段落文本:行之间用空格连接(可改为换行符,看你需要)
        merged_paragraphs.append(' '.join(lines))
    return merged_paragraphs
# ---------- 主程序 ----------
def main():
    # 图片扩展名(常见格式,可自行添加)
    IMAGE_EXTENSIONS = ('.png', '.jpg', '.jpeg', '.bmp', '.tiff', '.tif', '.webp')
    # 初始化 EasyOCR(中英文混合,开启 GPU 加速)
    print("正在初始化 EasyOCR,请稍候...")
    try:
        reader = easyocr.Reader(['ch_sim', 'en'], gpu=True)
    except Exception:
        print("GPU 初始化失败,切换为 CPU 模式。")
        reader = easyocr.Reader(['ch_sim', 'en'], gpu=False)
    # 获取当前工作目录
    root_dir = os.getcwd()
    print(f"开始遍历目录:{root_dir}")
    # 存储结果:{文件路径: [段落1, 段落2, ...]}
    ocr_results = {}
    for dirpath, _, filenames in os.walk(root_dir):
        for fname in filenames:
            if not fname.lower().endswith(IMAGE_EXTENSIONS):
                continue
            full_path = os.path.join(dirpath, fname)
            rel_path = os.path.relpath(full_path, root_dir)  # 相对路径便于阅读
            print(f"正在处理:{rel_path}")
            try:
                # 1. 图像增强
                processed_img = preprocess_image(full_path)
                # 2. OCR 识别(返回行级结果,方便后续段落合并)
                results = reader.readtext(processed_img, paragraph=False)
                if not results:
                    print(f"  -> 未检测到文本")
                    ocr_results[rel_path] = []
                    continue
                # 3. 段落合并
                paragraphs = group_into_paragraphs(results, y_gap_ratio=1.5)
                ocr_results[rel_path] = paragraphs
                print(f"  -> 检测到 {len(results)} 个文本行,合并为 {len(paragraphs)} 个段落")
            except Exception as e:
                print(f"  -> 处理出错:{e}")
                ocr_results[rel_path] = []
    # ---------- 写入结果文件 ----------
    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    output_filename = f"ocr_results_{timestamp}.txt"
    with open(output_filename, 'w', encoding='utf-8') as f:
        for img_path, paragraphs in ocr_results.items():
            f.write(f"===== {img_path} =====\n")
            if paragraphs:
                for i, para in enumerate(paragraphs, 1):
                    f.write(f"[段落 {i}]\n{para}\n\n")
            else:
                f.write("(未识别到文本)\n\n")
            f.write("\n")  # 不同图片之间再空一行
    print(f"\n所有处理完成!结果已保存至:{output_filename}")
if __name__ == "__main__":
    main()

代码说明

1.图像预处理

  • 使用 cv2.imdecode + 二进制读取,支持中文文件路径。
  • 依次进行:灰度化 → 非局部均值去噪 → CLAHE 对比度增强 → 轻度锐化 → 若宽度小于 800 像素则放大。
    这些操作能有效抑制噪声、改善对比度,提升 EasyOCR 对低质量图片的识别率。

2.段落合并

  • group_into_paragraphs 函数先将所有文本行按 top 坐标排序,然后通过比较相邻行的垂直间距(以当前段落平均行高的 1.5 倍为阈值)判断是否属于同一段落。
  • 同一段落中,若存在同一行被拆分成多个框(水平分布),会按 center_x 排序后用空格拼接,最终将各行文本也用空格连接成一个段落。
  • 你可以根据需要将段落内行连接符改为 '\n',使保存的文本更接近原始排版。

3.EasyOCR 调用

  • 语言设为 ['ch_sim', 'en'],同时识别简体中文和英文。
  • 优先尝试 GPU 加速,失败则自动降级为 CPU。
  • 使用 paragraph=False 获取精细的行级结果,方便自行控制段落合并逻辑。

4.输出文件

  • 带时间戳的 ocr_results_YYYYMMDD_HHMMSS.txt,每个图片的相对路径作为标题,下方依次列出每个段落的文本。
  • 无文本的图片也会记录,方便排查。

运行环境准备

pip install easyocr opencv-python numpy

将脚本放在需要处理的目录下,直接运行即可。

到此这篇关于OpenCV OCR实现提取图片文本的完整代码的文章就介绍到这了,更多相关OpenCV OCR图片文本提取内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python实现Word文档中提取表格数据并转换为CSV和JSON格式

    Python实现Word文档中提取表格数据并转换为CSV和JSON格式

    在日常工作中,我们经常需要处理大量的Word文档,其中包含各种表格数据,手动整理这些表格不仅耗时且容易出错,Python提供了多个库来帮助我们实现这一目标,所以本文给大家介绍了Python实现Word文档中提取表格数据并转换为CSV和JSON格式,需要的朋友可以参考下
    2025-12-12
  • Python模块与包管理使用pip与virtualenv

    Python模块与包管理使用pip与virtualenv

    本文深入介绍了使用pipenv管理Python项目的依赖关系和环境,我们首先从pip和virtualenv开始,介绍了它们的基本功能和用法,然后深入探讨了pipenv作为更高级工具的功能和特性,
    2024-03-03
  • Python批量查询关键词微信指数实例方法

    Python批量查询关键词微信指数实例方法

    在本篇文章中小编给大家整理的是关于Python批量查询关键词微信指数实例方法以及相关代码,需要的朋友们可以跟着学习下。
    2019-06-06
  • python中if嵌套命令实例讲解

    python中if嵌套命令实例讲解

    在本篇文章里小编给大家整理的是一篇关于python中if嵌套命令实例讲解内容,有兴趣的朋友们可以学习下。
    2021-02-02
  • Python实现将json格式数据存储到Mysql数据库

    Python实现将json格式数据存储到Mysql数据库

    这篇文章主要为大家详细介绍了如何使用Python实现将json格式数据存储到Mysql数据库,文中的示例代码简洁易懂,有需要的小伙伴可以参考下
    2025-03-03
  • Python将Word文档转为PDF的两种方法

    Python将Word文档转为PDF的两种方法

    这篇文章主要介绍了两种将docx和doc文件转换为PDF的方法,方法一使用了docx2pdf模块,方法二使用了win32com模块,文中通过代码及图文介绍的非常详细,需要的朋友可以参考下
    2024-12-12
  • Python数据分析之彩票的历史数据

    Python数据分析之彩票的历史数据

    这篇文章主要介绍了Python数据分析之彩票的历史数据,文中有非常详细的代码示例,对正在学习python的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04
  • PyTorch Lightning Callback使用指南

    PyTorch Lightning Callback使用指南

    文章主要介绍了Callback在深度学习训练过程中的重要性,包括其核心价值、核心概念与架构、内置Callback的详细解释以及自定义Callback的开发方法
    2025-12-12
  • 使用gunicorn部署django项目的问题

    使用gunicorn部署django项目的问题

    这篇文章主要介绍了使用gunicorn部署django项目,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • Python 虚拟环境完全指南:venv、virtualenv 与 Conda详解

    Python 虚拟环境完全指南:venv、virtualenv 与 Conda详解

    文章详细介绍了Python的虚拟环境及其管理工具,文章还提供了创建、激活、导出、删除环境等操作指导,以及最佳实践和参考命令,感兴趣的朋友跟随小编一起看看吧
    2026-05-05

最新评论