使用 C++/OpenCV 構建中文 OCR 系統:實現賬單、發票及 PDF 讀取

使用 C++/OpenCV 構建中文 OCR 系統:實現賬單、發票及 PDF 讀取

在當今數字化浪潮中,自動從文檔中提取信息至關重要,尤其是在處理大量賬單、發票和 PDF 文件時。光學字符識別(OCR)技術是實現這一目標的核心。本文將詳細介紹如何利用 C++ 和強大的計算機視覺庫 OpenCV,構建一個專門用于讀取中文賬單、發票和 PDF 的 OCR 系統。

核心技術棧

我們的系統將主要圍繞以下核心技術構建:

  • C++: 作為主要的編程語言,C++ 以其高性能和對系統底層資源的強大控制力而著稱,非常適合構建計算密集型的計算機視覺應用。
  • OpenCV: 一個開源的計算機視覺和機器學習軟件庫。它提供了豐富的圖像處理和計算機視覺算法,是本項目的基石。
  • OCR 引擎: 我們將重點探討兩種主流的、支持中文識別的 OCR 引擎:Tesseract 和 PaddleOCR。它們都可以與 C++ 和 OpenCV 良好集成。
  • PDF 處理庫 (Poppler): 由于 OCR 引擎通常處理的是圖像文件,我們需要一個庫來將 PDF 文件頁面轉換為可供 OpenCV 處理的圖像。Poppler 是一個優秀的選擇。

系統構建流程

構建一個完整的文檔 OCR 系統,大致可以分為以下幾個步驟:

  1. 環境搭建: 配置 C++ 編譯環境,安裝 OpenCV、Tesseract 或 PaddleOCR,以及 Poppler 庫。
  2. 輸入處理: 讀取圖像文件或將 PDF 頁面轉換為 OpenCV 的 Mat 圖像格式。
  3. 圖像預處理: 對圖像進行一系列優化操作,以提高 OCR 的準確率。
  4. 文本檢測與定位: 在圖像中找到包含文本的區域。
  5. 文本識別: 對檢測到的文本區域進行 OCR 識別。
  6. 版面分析與結構化輸出 (關鍵步驟): 對于賬單和發票等結構化文檔,識別出關鍵字段(如發票號碼、日期、金額等)并以結構化數據(如 JSON)格式輸出。

第一步:環境搭建

在開始編碼之前,您需要確保開發環境中已經安裝了所有必要的庫。

對于 Tesseract:

您需要安裝 Tesseract OCR 引擎及其開發庫,同時下載中文語言包 (chi_sim.traineddata)。

  • 在 Ubuntu/Debian 系統中:
    sudo apt-get update
    sudo apt-get install -y tesseract-ocr libtesseract-dev
    sudo apt-get install -y tesseract-ocr-chi-sim
    
  • 在 Windows 系統中:
    可以從 Tesseract 的官方 GitHub 倉庫下載預編譯的二進制文件,并確保將 Tesseract 的安裝路徑添加到系統環境變量中。同時,需要獲取中文語言包。

對于 PaddleOCR:

您需要下載 PaddleOCR 的 C++ 預測庫。PaddleOCR 的 GitHub 倉庫中提供了詳細的編譯和部署文檔,包括如何在 Windows (Visual Studio) 和 Linux 環境下進行編譯。

安裝 OpenCV:

可以從 OpenCV 官網下載源碼進行編譯,也可以使用包管理器進行安裝。

安裝 Poppler:

  • 在 Ubuntu/Debian 系統中:
    sudo apt-get install -y libpoppler-cpp-dev
    
  • 在 Windows 系統中:
    可以下載預編譯的二進制文件,并配置好頭文件和庫文件的路徑。

第二-三步:輸入處理與圖像預處理

處理 PDF 文件

OCR 引擎直接處理的是圖像。因此,第一步是將 PDF 文件轉換為圖像。借助 Poppler 庫,我們可以輕松實現這一點。

#include <iostream>
#include <opencv2/opencv.hpp>
#include <poppler-cpp.h>cv::Mat convert_pdf_page_to_image(const std::string& pdf_file, int page_number, int dpi = 300) {poppler::document* doc = poppler::document::load_from_file(pdf_file);if (!doc || doc->is_locked()) {std::cerr << "Error: Cannot open PDF file." << std::endl;return cv::Mat();}if (page_number < 0 || page_number >= doc->num_pages()) {std::cerr << "Error: Invalid page number." << std::endl;delete doc;return cv::Mat();}poppler::page* page = doc->create_page(page_number);if (!page) {std::cerr << "Error: Cannot create page." << std::endl;delete doc;return cv::Mat();}poppler::page_renderer renderer;renderer.set_render_hint(poppler::page_renderer::antialiasing, true);renderer.set_render_hint(poppler::page_renderer::text_antialiasing, true);poppler::image image = renderer.render_page(page, dpi, dpi);if (!image.is_valid()) {std::cerr << "Error: Cannot render page." << std::endl;delete page;delete doc;return cv::Mat();}cv::Mat cv_image;if (image.format() == poppler::image::format_rgb24) {cv_image = cv::Mat(image.height(), image.width(), CV_8UC3, image.data());cv::cvtColor(cv_image, cv_image, cv::COLOR_RGB2BGR); // Poppler a RGB, OpenCV a BGR} else if (image.format() == poppler::image::format_argb32) {cv_image = cv::Mat(image.height(), image.width(), CV_8UC4, image.data());cv::cvtColor(cv_image, cv_image, cv::COLOR_BGRA2BGR);} else {std::cerr << "Error: Unsupported image format from PDF." << std::endl;}delete page;delete doc;return cv_image.clone();
}
圖像預處理

高質量的圖像是 OCR 成功的關鍵。對于掃描的賬單和發票,通常需要進行以下預處理步驟:

  • 灰度化: 將彩色圖像轉換為灰度圖像,以減少計算復雜性。
  • 二值化: 將灰度圖像轉換為黑白圖像。自適應閾值二值化(cv::adaptiveThreshold)對于處理光照不均的文檔尤為有效。
  • 噪聲消除: 使用高斯模糊 (cv::GaussianBlur) 或中值濾波 (cv::medianBlur) 去除圖像中的隨機噪聲。
  • 傾斜校正: 檢測文檔的傾斜角度并進行旋轉校正。可以通過霍夫變換 (cv::HoughLinesP) 檢測直線或使用最小面積外接矩形 (cv::minAreaRect) 來實現。
cv::Mat preprocess_image(const cv::Mat& input_image) {cv::Mat gray, blurred, thresholded;// 1. 灰度化cv::cvtColor(input_image, gray, cv::COLOR_BGR2GRAY);// 2. 高斯模糊去噪cv::GaussianBlur(gray, blurred, cv::Size(5, 5), 0);// 3. 自適應閾值二值化cv::adaptiveThreshold(blurred, thresholded, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C,cv::THRESH_BINARY, 11, 2);// 可選:進行傾斜校正等更復雜的操作return thresholded;
}

第四-五步:文本檢測與識別

在進行 OCR 之前,先檢測出文本所在的位置可以顯著提高效率和準確性,避免對非文本區域進行識別。

文本檢測

OpenCV 的 DNN 模塊提供了多種預訓練的文本檢測模型,其中 EAST (Efficient and Accurate Scene Text Detector) 模型是一個不錯的選擇。

使用 PaddleOCR 進行識別

PaddleOCR 提供了集成的文本檢測和識別功能,其 C++ 部署方案性能優越,對中文場景有很好的優化。使用 PaddleOCR,您可以直接輸入預處理后的圖像,它會返回包含位置和文本內容的結構化結果。

使用 Tesseract 進行識別

如果您選擇使用 Tesseract,可以先用 EAST 模型檢測出文本框,然后將每個文本框的區域 cv::Rect 傳入 Tesseract 進行識別。

#include <tesseract/baseapi.h>// ... 假設已經通過文本檢測獲得了文本框 a_text_roi (cv::Rect) ...// 初始化 Tesseract
tesseract::TessBaseAPI* ocr = new tesseract::TessBaseAPI();
// "chi_sim" 代表簡體中文
if (ocr->Init(NULL, "chi_sim", tesseract::OEM_LSTM_ONLY)) {std::cerr << "Could not initialize tesseract." << std::endl;// ... 錯誤處理 ...
}
ocr->SetPageSegMode(tesseract::PSM_SINGLE_BLOCK);// 提取 ROI
cv::Mat roi_image = preprocessed_image(a_text_roi);// 設置圖像進行識別
ocr->SetImage(roi_image.data, roi_image.cols, roi_image.rows, roi_image.channels(), roi_image.step);// 獲取識別結果
char* out_text = ocr->GetUTF8Text();
std::string result_text = std::string(out_text);// 銷毀 Tesseract 實例
ocr->End();
delete ocr;
delete[] out_text;

第六步:版面分析與結構化輸出

對于賬單和發票,僅僅獲取所有文字是不夠的,我們還需要理解它們的含義。版面分析是實現這一目標的關鍵。

基于規則和模板的方法

對于格式相對固定的發票,這是一種簡單有效的方法。

  1. 定義關鍵字段: 首先確定您需要提取的關鍵信息,例如“發票代碼”、“發票號碼”、“開票日期”、“金額合計”等。
  2. 定位關鍵字: 在 OCR 結果中搜索這些關鍵字。
  3. 相對位置提取: 根據關鍵字的位置,利用其相對空間關系來定位和提取目標信息。例如,“發票號碼”通常位于“發票號碼:”這個標簽的右側或下方。
機器學習方法

對于格式多變的文檔,可以訓練機器學習模型(如基于圖神經網絡 GNN 的模型)來理解文檔布局和字段間的關系,但這需要大量的標注數據和更復雜的實現。

結構化輸出

將提取到的信息以 JSON 格式輸出,便于后續的系統集成和數據分析。

{"invoice_code": "010002100311","invoice_number": "81804581","issue_date": "2025-06-20","total_amount": "1170.00","items": [{"description": "技術服務費","amount": "1000.00"},{"description": "稅額","amount": "170.00"}]
}

總結與展望

使用 C++ 和 OpenCV 構建一個中文文檔 OCR 系統是一個涉及多個步驟的綜合性項目。通過結合強大的開源工具如 Tesseract、PaddleOCR 和 Poppler,我們可以創建一個高效、準確的解決方案來自動化處理賬單、發票和 PDF 文件。

對于追求更高準確率和更強泛化能力的場景,可以進一步探索:

  • 深度學習驅動的版面分析: 訓練專門用于文檔理解的深度學習模型。
  • 模型微調: 使用您自己收集和標注的數據對預訓練的 OCR 模型進行微調,以適應特定類型的文檔。
  • 自然語言處理 (NLP) 后處理: 利用 NLP 技術對 OCR 結果進行校正和信息提取,進一步提升最終輸出的質量。

希望這篇指南能為您在 C++ 環境下進行中文 OCR 開發提供一個清晰的路線圖。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/88374.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/88374.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/88374.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

windows配置Jenkins自動化定時任務+測試報告發送

一、Jenkins的安裝步驟 JDK安裝 沒有JDK的先安裝JDKhttps://adoptium.net/zh-CN/temurin/releases/?osany&archany&version21 下載Jenkins 由于JDK 1.8僅適配Jenkins 2.357之前的版本&#xff08;如2.346.1及以下&#xff09;&#xff0c;需從舊版本渠道下載&#xf…

預訓練語言模型基礎知識概述

文章目錄 預處理語言模型的發展預訓練語言模型統計語言模型神經網絡語言模型 詞向量onehot編碼詞嵌入word embedding Word2Vec模型RNN和LSTMRNNLSTM ELMo模型預訓練下游任務 Attention自注意力Masked Self AttentionMulti-head Self Attention 位置編碼Transformer概念GPT概念B…

瀏覽器工作原理24 [#]分層和合成機制:為什么css動畫比JavaScript高效

引用 《瀏覽器工作原理與實踐》 本文主要講解渲染引擎的分層和合成機制&#xff0c;因為分層和合成機制代表了瀏覽器最為先進的合成技術&#xff0c;Chrome 團隊為了做到這一點&#xff0c;做了大量的優化工作。了解其工作原理&#xff0c;有助于拓寬你的視野&#xff0c;而且也…

【數字后端】-什么是RC corner? 每種Corner下有什么區別?

芯片的寄生參數可以在多個corner下提取&#xff0c;他們對應了不同情況的net delay Typical&#xff1a;R和C都是標準值Cmax(Cworst)&#xff1a;C最大的互連角&#xff0c;R小于TypicalCmin(Cbest)&#xff1a;C最小&#xff0c;R大于TypicalRCmax(RCworst)&#xff1a;互連線…

HarmonyOS開發基礎 --鴻蒙倉頡語言基礎語法入門

倉頡編程語言是華為自主研發的一種面向全場景應用開發的現代編程語言&#xff0c;具有高效編程、安全可靠、輕松并發和卓越性能等特點。本節將簡單介紹倉頡語言的部分語法和使用&#xff0c;幫助開發者快速上手。 1.3.1&#xff1a;數據類型 整數 倉頡把整數分為有符號和無符…

Excel文件比較器v1.3,html和js寫的

Excel文件比較器v1.3 版本說明&#xff1a;v1.3 1添加支持文件格式&#xff1a;CSV。 2&#xff0c;添加60條歷史記錄保存功能 - 用于保存比對結果。歷史記錄保存在瀏覽器的localStorage中&#xff0c;這是一個瀏覽器提供的本地存儲機制&#xff0c;數據會一直保留直到用戶…

Kimi“新PPT助手” ,Kimi全新自研的免費AI生成PPT助手

大家好&#xff0c;這里是K姐。 一個幫你用AI輕松生成精美PPT的女子。 前段時間給大家分享了一期用智能體做PPT的對比測評&#xff0c;很多友友都表示&#xff1a;那 Kimi 呢&#xff1f; 今天偶然發現 Kimi 新增了一個叫“新PPT助手”的功能&#xff0c;立馬上手體驗了一下…

MySQL DATETIME類型存儲空間詳解:從8字節到5字節的演變

在MySQL數據庫設計中&#xff0c;DATETIME類型用于存儲日期和時間信息&#xff0c;但其存儲空間大小并非固定不變&#xff0c;而是隨MySQL版本迭代和精度定義動態變化。本文將詳細說明其存儲規則&#xff0c;并提供清晰的對比表格。 一、核心結論 MySQL 5.6.4 是分水嶺&#…

Gartner發布中國企業應用生成式AI指南:避免12 個 GenAI 陷阱

GenAI 技術&#xff08;例如 AI 代理和 DeepSeek&#xff09;的快速迭代導致企業抱有不切實際的期望。本研究借鑒了我們與中國 AI 領導者就常見的 GenAI 陷阱進行的討論&#xff0c;并提供了最終有助于成功采用的建議。 主要發現 接受調查的首席信息官表示&#xff0c;生成式人…

Vue3中ref和reactive的區別與使用場景詳解

在 Vue 3 中&#xff0c;響應式系統進行了全新設計&#xff0c;ref 和 reactive 是其中的核心概念。 ### 一、ref 的使用 ref 適用于基本數據類型&#xff0c;也可以用于對象&#xff0c;但返回的是一個帶 .value 的包裝對象。 js import { ref } from vue const count ref(…

React性能優化:父組件如何導致子組件重新渲染及避免策略

目錄 React性能優化&#xff1a;父組件如何導致子組件重新渲染及避免策略什么是重新渲染&#xff1f;父組件如何"無辜"地讓子組件重新渲染&#xff1f;示例 1: 基礎父組件狀態變更示例 2: 傳遞未變化的原始類型Prop示例 3: 傳遞引用類型Prop&#xff08;對象&#xf…

圖的拓撲排序管理 Go 服務啟動時的組件初始化順序

在構建復雜的 Go 應用程序時&#xff0c;服務的啟動過程往往涉及多個組件的初始化&#xff0c;例如日志、配置、數據庫連接、緩存、服務管理器、適配器等等。這些組件之間通常存在著復雜的依賴關系&#xff1a;日志可能需要配置信息&#xff0c;數據庫連接可能依賴日志和追蹤&a…

【物理重建】SPLART:基于3D高斯潑濺的鉸鏈估計與部件級重建

標題&#xff1a;《SPLART: Articulation Estimation and Part-Level Reconstruction with 3D Gaussian Splatting》 項目&#xff1a;https://github.com/ripl/splart 文章目錄 摘要一、引言二、相關工作2.1 數據驅動的鉸鏈學習2.2 物體重建的表征方法2.3 鉸鏈物體重建 三、方…

vscode中vue自定義組件的標簽失去特殊顏色高亮

遇到的問題 最近接觸了一個歷史遺留項目時&#xff0c;我遭遇了堪稱"史詩級屎山"的代碼結構——各種命名混亂的自定義組件和原生HTML標簽混雜在一起&#xff0c;視覺上完全無法區分。這讓我突然想起&#xff0c;之前在使用vue或者其他框架開發的時候&#xff0c;只要…

【Dify精講】第19章:開源貢獻指南

今天&#xff0c;讓我們深入 Dify 的開源貢獻體系&#xff0c;看看這個項目是如何在短短時間內聚集起一個活躍的開發者社區的。作為想要參與 Dify 開發的你&#xff0c;這一章將是你的實戰指南。 一、代碼貢獻流程&#xff1a;從想法到合并的完整路徑 1.1 貢獻前的準備工作 …

Web攻防-CSRF跨站請求偽造Referer同源Token校驗復用刪除置空聯動上傳或XSS

知識點&#xff1a; 1、Web攻防-CSRF-原理&檢測&利用&防御 2、Web攻防-CSRF-防御-Referer策略隱患 3、Web攻防-CSRF-防御-Token校驗策略隱患 一、演示案例-WEB攻防-CSRF利用-原理&構造 CSRF 測試功能點 刪除帳戶 更改電子郵件 如果不需要舊密碼&#xff0c;請…

Drag-and-Drop LLMs: Zero-Shot Prompt-to-Weights

“拖拽式大模型定制”&#xff08;Drag-and-Drop LLMs: Zero-Shot Prompt-to-Weights&#xff09;。 核心問題&#xff1a; 現在的大模型&#xff08;比如GPT-4&#xff09;很厲害&#xff0c;但想讓它們專門干好某個特定任務&#xff08;比如解數學題、寫代碼&#xff09;&am…

抖音視頻怎么去掉抖音號水印保存

隨著抖音成為短視頻平臺的領軍者&#xff0c;越來越多的人喜歡在上面拍攝、觀看和分享各種創意內容。對于用戶來說&#xff0c;下載抖音視頻并去除水印保存&#xff0c;以便后續使用或分享成為了一種常見需求。抖音號水印的存在雖然能幫助平臺追溯視頻源頭&#xff0c;但也讓許…

【RAG技術(1)】大模型為什么需要RAG

文章目錄 為什么需要RAG&#xff1f;RAG的工作原理關鍵的Embedding技術 RAG vs 模型微調&#xff1a;選擇的核心邏輯RAG的關鍵挑戰與解決思路1. 檢索質量決定一切2. 上下文長度限制 實際應用場景分析企業知識問答技術文檔助手法律咨詢系統 構建RAG系統的關鍵步驟總結 為什么需要…

JS紅寶書筆記 - 8.1 理解對象

對象就是一組沒有特定順序的值&#xff0c;對象的每個屬性或者方法都可由一個名稱來標識&#xff0c;這個名稱映射到一個值。可以把對象想象成一張散列表&#xff0c;其中的內容就是一組名值對&#xff0c;值可以是數據或者函數 創建自定義對象的通常方式是創建Object的一個新…