最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

OpenCV OCR實現(xiàn)提取圖片文本的完整代碼

 更新時間:2026年05月20日 08:28:32   作者:weixin_30777913  
本文主要介紹了使用OpenCV和EasyOCR處理圖片并提取文字的流程,首先預(yù)處理圖片,包括灰度化、去噪、對比度增強(qiáng)等銳化等步驟,此方法適用于處理低質(zhì)量圖片并提取其中的文字,希望對大家有所幫助

完整代碼

遍歷當(dāng)前目錄及所有子目錄下的常見圖片,使用 OpenCV 進(jìn)行多種圖像增強(qiáng),然后調(diào)用 EasyOCR 提取文字,并按段落合并同一段中的行,最后把所有結(jié)果寫入一個帶時間戳的文本文件。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import datetime
import cv2
import numpy as np
import easyocr
# ---------- 圖像預(yù)處理 ----------
def preprocess_image(image_path):
    """
    使用 OpenCV 對圖片進(jìn)行一系列增強(qiáng),以提高 OCR 識別率。
    返回處理后的灰度圖(numpy 數(shù)組),可直接送入 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. 轉(zhuǎn)灰度
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 2. 去噪(非局部均值去噪,保留邊緣)
    denoised = cv2.fastNlMeansDenoising(gray, None, h=10, templateWindowSize=7, searchWindowSize=21)
    # 3. 對比度增強(qiáng)(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. 尺寸調(diào)整:如果圖片過小,放大到至少 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 的檢測結(jié)果(bbox, text, confidence)按垂直距離合并為段落。
    - 首先按 top 坐標(biāo)排序所有文本行。
    - 如果當(dāng)前行的 top 與上一段落最后一行的 bottom 的距離小于
      該段落平均行高的 y_gap_ratio 倍,則認(rèn)為屬于同一段落。
    - 每個段落內(nèi)的行按照從上到下的順序用空格連接。
    """
    if not results:
        return []
    # 給每個框計算 top, bottom, center_y, center_x
    processed = []
    for (bbox, text, conf) in results:
        # bbox 是四個點(diǎn) [[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 與當(dāng)前行的 top 之間的間隙
            last_bottom = current_para[-1]['bottom']
            gap = item['top'] - last_bottom
            # 使用當(dāng)前段落平均行高計算閾值
            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:
                # 保存當(dāng)前段落,開始新段落
                paragraphs.append(current_para)
                current_para = [item]
                para_avg_height = item['height']
    if current_para:
        paragraphs.append(current_para)
    # 將每個段落內(nèi)的文本按順序(已經(jīng)是 top 順序)用空格合并
    merged_paragraphs = []
    for para in para_inner:
        # 同一段落內(nèi)可能同一行有多個框(按 x 排序)
        # 這里簡單按 top 歸為一組視為一行,然后行間用空格連接
        # 實際上 EasyOCR 一般返回的是行級框,這里保留后續(xù)擴(kuò)展能力
        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]
            # 同一行內(nèi)按 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():
    # 圖片擴(kuò)展名(常見格式,可自行添加)
    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)
    # 獲取當(dāng)前工作目錄
    root_dir = os.getcwd()
    print(f"開始遍歷目錄:{root_dir}")
    # 存儲結(jié)果:{文件路徑: [段落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. 圖像增強(qiáng)
                processed_img = preprocess_image(full_path)
                # 2. OCR 識別(返回行級結(jié)果,方便后續(xù)段落合并)
                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] = []
    # ---------- 寫入結(jié)果文件 ----------
    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所有處理完成!結(jié)果已保存至:{output_filename}")
if __name__ == "__main__":
    main()

代碼說明

1.圖像預(yù)處理

  • 使用 cv2.imdecode + 二進(jìn)制讀取,支持中文文件路徑。
  • 依次進(jìn)行:灰度化 → 非局部均值去噪 → CLAHE 對比度增強(qiáng) → 輕度銳化 → 若寬度小于 800 像素則放大。
    這些操作能有效抑制噪聲、改善對比度,提升 EasyOCR 對低質(zhì)量圖片的識別率。

2.段落合并

  • group_into_paragraphs 函數(shù)先將所有文本行按 top 坐標(biāo)排序,然后通過比較相鄰行的垂直間距(以當(dāng)前段落平均行高的 1.5 倍為閾值)判斷是否屬于同一段落。
  • 同一段落中,若存在同一行被拆分成多個框(水平分布),會按 center_x 排序后用空格拼接,最終將各行文本也用空格連接成一個段落。
  • 你可以根據(jù)需要將段落內(nèi)行連接符改為 '\n',使保存的文本更接近原始排版。

3.EasyOCR 調(diào)用

  • 語言設(shè)為 ['ch_sim', 'en'],同時識別簡體中文和英文。
  • 優(yōu)先嘗試 GPU 加速,失敗則自動降級為 CPU。
  • 使用 paragraph=False 獲取精細(xì)的行級結(jié)果,方便自行控制段落合并邏輯。

4.輸出文件

  • 帶時間戳的 ocr_results_YYYYMMDD_HHMMSS.txt,每個圖片的相對路徑作為標(biāo)題,下方依次列出每個段落的文本。
  • 無文本的圖片也會記錄,方便排查。

運(yùn)行環(huán)境準(zhǔn)備

pip install easyocr opencv-python numpy

將腳本放在需要處理的目錄下,直接運(yùn)行即可。

到此這篇關(guān)于OpenCV OCR實現(xiàn)提取圖片文本的完整代碼的文章就介紹到這了,更多相關(guān)OpenCV OCR圖片文本提取內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python全局變量引用與修改過程解析

    python全局變量引用與修改過程解析

    這篇文章主要介紹了python全局變量引用與修改過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-01-01
  • python?教程之blinker?信號庫

    python?教程之blinker?信號庫

    這篇文章主要介紹了python?教程之blinker?信號庫,文章基于python的相關(guān)資料展開詳細(xì)的內(nèi)容說明。具有一定的參考價價值,需要的小伙伴可以參考一下
    2022-05-05
  • 利用python爬取軟考試題之ip自動

    利用python爬取軟考試題之ip自動

    最近為了考試打算抓取網(wǎng)上的軟考試題,在抓取中遇到一些問題,下面這篇文章主要介紹的是利用python爬取軟考試題之ip自動的相關(guān)資料,文中介紹的非常詳細(xì),需要的朋友們下面來一起看看吧。
    2017-03-03
  • 解決matplotlib庫show()方法不顯示圖片的問題

    解決matplotlib庫show()方法不顯示圖片的問題

    今天小編就為大家分享一篇解決matplotlib庫show()方法不顯示圖片的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • 使用venv重建python虛擬環(huán)境的步驟實現(xiàn)

    使用venv重建python虛擬環(huán)境的步驟實現(xiàn)

    venv可以創(chuàng)建彼此隔絕的Python環(huán)境,我們能夠把同一個軟件包的不同版本分別安裝到不同的環(huán)境里面,,這樣就不會產(chǎn)生沖突了,下面就來介紹一下venv重建python虛擬環(huán)境的步驟實現(xiàn)
    2025-08-08
  • Windows系統(tǒng)下實現(xiàn)pycharm運(yùn)行.sh文件(本地運(yùn)行和打開服務(wù)器終端)

    Windows系統(tǒng)下實現(xiàn)pycharm運(yùn)行.sh文件(本地運(yùn)行和打開服務(wù)器終端)

    PyCharm是Python開發(fā)的高效率IDE,但是很多時候需要同時開發(fā)Bash(shell)腳本,下面這篇文章主要給大家介紹了關(guān)于Windows系統(tǒng)下實現(xiàn)pycharm運(yùn)行.sh文件(本地運(yùn)行和打開服務(wù)器終端)的相關(guān)資料,需要的朋友可以參考下
    2022-09-09
  • Python教程之Python多態(tài)的深層次理解

    Python教程之Python多態(tài)的深層次理解

    相信很多在學(xué)Python的朋友都有了解過多態(tài),本篇文章來帶大家更進(jìn)一步的深入了解Python多態(tài),有需要的朋可以借鑒參考下,希望可以有所幫助
    2021-09-09
  • Python基礎(chǔ)之類的定義和使用詳解

    Python基礎(chǔ)之類的定義和使用詳解

    在Python中,類表示具有相同屬性和方法的對象的集合。在使用類時,需要先定義類,然后再創(chuàng)建類的實例,通過類的實例就可以訪問類中的屬性和方法了。本文就來和大家一起聊聊Python中類的定義和使用,需要的可以參考一下
    2022-08-08
  • 基于Python實現(xiàn)文件處理程序

    基于Python實現(xiàn)文件處理程序

    這篇文章主要為大家詳細(xì)介紹了如何基于Python實現(xiàn)一個簡單的文件處理程序,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • Python 的第三方調(diào)試庫 ???pysnooper?? 使用示例

    Python 的第三方調(diào)試庫 ???pysnooper?? 使用示例

    這篇文章主要介紹了Python 的第三方調(diào)試庫 ???pysnooper?? 使用示例的相關(guān)資料,需要的朋友可以參考下
    2023-02-02

最新評論

广平县| 汉源县| 鲁甸县| 大连市| 灌南县| 鲁甸县| 瑞安市| 京山县| 通渭县| 辉南县| 南平市| 始兴县| 运城市| 射阳县| 长沙市| 扶沟县| 延川县| 海口市| 大竹县| 翁源县| 寿宁县| 静乐县| 新和县| 道孚县| 招远市| 大洼县| 从江县| 竹山县| 红桥区| 临江市| 平武县| 孟州市| 壶关县| 江陵县| 中宁县| 息烽县| 集贤县| 谢通门县| 循化| 红原县| 安新县|