目錄
?1、介紹
1.1、痛點
1.2、程序介紹
2、安裝方式
2.1、??必要環(huán)節(jié)
2.2、腳本安裝
2.2.1、不太推薦的方式
2.2.2、節(jié)約內(nèi)存的方式
2.3、?完整版安裝
3、使用
3.1、最終文件目錄
3.2、主程序
3.2.1、絕對路徑
3.2.2、是否為書籍
3.2.3、?截取區(qū)域
3.2.4、?進程數(shù)
3.3、運行完成
3.4、保存路徑
4、代碼詳解
4.1、思路
4.2、交互
4.3、提取圖片
4.4、裁剪圖片
4.5、刪除不必要的內(nèi)容
4.5、?OCR處理
4.5.1、處理裁剪后的圖片
4.5.2、寫入文件
5、?完整源代碼
??作者介紹:雙非本科大三網(wǎng)絡(luò)工程專業(yè)在讀,阿里云專家博主,專注于Java領(lǐng)域?qū)W習,擅長web應(yīng)用開發(fā)、數(shù)據(jù)結(jié)構(gòu)和算法,初步涉獵Python人工智能開發(fā)和前端開發(fā)。
??主頁:@逐夢蒼穹??所屬專欄:項目
??您的一鍵三連,是我創(chuàng)作的最大動力??
?1、介紹
程序下載:
鏈接:https://pan.baidu.com/s/1kK1cBRwPMgnWBP2L43rs9Q?pwd=1234
提取碼:1234
1.1、痛點
這是一個處理圖片式PDF文件轉(zhuǎn)換為可搜索的文字式word文檔的程序,該程序是為了解決如下痛點:
①各軟件的識別付費
②網(wǎng)頁在線轉(zhuǎn)換有大小限制
③開源的程序識別準確率略有不足(這個是比較有名的開源軟件umi-ocr,準確率能達到百分之95)
1.2、程序介紹
這個程序最終是打包成了exe可執(zhí)行程序(后面會詳細講解),沒有做GUI圖形化界面,用戶和程序的交互在命令行窗口執(zhí)行。
這個項目涉及的技術(shù)點包括:
- 文件操作:使用Python的os和shutil模塊進行文件夾和文件的創(chuàng)建、刪除和操作。這些模塊提供了對文件系統(tǒng)的訪問和操作,允許您在項目中進行文件和文件夾的管理。
- 圖像處理:使用OpenCV和PIL庫進行圖像的裁剪、保存和處理。OpenCV是一個廣泛用于計算機視覺任務(wù)的開源計算機視覺庫,而PIL(Python Imaging Library)則提供了處理圖像的基本功能,例如打開、保存、裁剪和調(diào)整圖像大小。
- PDF處理:使用PyMuPDF(fitz)庫進行PDF文檔的處理和圖像提取。PyMuPDF是一個用于處理PDF文件的Python庫,可以用于提取PDF中的文本、圖像等內(nèi)容,并對PDF文檔進行各種操作。
- 并發(fā)編程:使用Python的線程和線程池進行并發(fā)處理,加快圖像處理和OCR識別速度。線程和線程池允許程序在同一時間執(zhí)行多個任務(wù),提高了程序的效率,尤其在需要處理大量圖像或進行OCR識別時尤為重要。
- OCR識別:使用cnocr庫進行中文OCR識別,并將識別結(jié)果寫入Word文檔。cnocr是一個用于中文OCR識別的Python庫,能夠?qū)χ形奈谋具M行識別,這對于處理包含中文的文檔或圖像非常有用。
- 用戶輸入處理:使用Python的input函數(shù)接收用戶輸入,根據(jù)用戶輸入執(zhí)行不同的處理邏輯。這樣可以使程序更加靈活,能夠根據(jù)用戶需求進行不同的操作。
- 異常處理:使用try-except結(jié)構(gòu)進行異常處理,確保程序在出現(xiàn)異常時能夠正常處理并給出相應(yīng)提示。這有助于提高程序的穩(wěn)定性和可靠性,尤其在處理文件和網(wǎng)絡(luò)請求時非常重要。
這個項目主要用于將PDF文檔中的圖片提取出來,并對提取的圖片進行裁剪、OCR識別,最后將識別結(jié)果寫入Word文檔。通過結(jié)合多種技術(shù),實現(xiàn)了從PDF文檔到圖像處理再到文本識別的全流程自動化。
2、安裝方式
這個程序一共有兩種安裝方式。
無論哪種安裝方式,都是即裝即用,也就是說,當年不需要的時候,把這個程序所在的文件夾整個刪除即可,不會有殘留。
需要的內(nèi)容都存入百度網(wǎng)盤了。下載對應(yīng)的zip壓縮包解壓即可。
OCR-program-transition-all.zip是完整版,直接就可以用!
OCR-program-transition-empty-bat.zip是腳本安裝版,需要用戶按照指引來操作,才可使用。
推薦使用完整版
2.1、??必要環(huán)節(jié)
這個程序有兩個依賴項,需要手動安裝!(也在網(wǎng)盤內(nèi))。即:
安裝過程一路默認即可。
安裝后:
2.2、腳本安裝
目錄結(jié)構(gòu)如下:
2.2.1、不太推薦的方式
這個項目需要依賴到C++的一些庫,根據(jù)報錯信息,是建議直接安裝C++編譯器Visual Studio:
雖然能做到完全解決這個報錯,但是很大的缺點是:這玩意太大了……
2.2.2、節(jié)約內(nèi)存的方式
這種方式,能不能成功,看點運氣…
第一步:先安裝上文提到的兩個exe文件
第二步:運行“初始化腳本-1”文件
第三步:運行“初始化腳本-2”文件,此文件運行過程會非常久,因為這是在該文件夾下面安裝項目所需依賴環(huán)境。不出意外的話,第三步安裝到最后一個的時候,會報錯,提示缺少C++ 14.0。
第四步:此時需要點開上文提到的兩個裝好的程序,右鍵,選擇修改:
點擊修復:
然后重啟。
第五步:重啟后,重復第三步到第五步的操作(此時第三步的運行速度會很快了),連續(xù)操作超過三次,就…建議直接下載完整版吧…(這地方有點玄學,不是百分百能解決…程序作者本人整了三天了!程序就像捉摸不透的人一樣,有時成功有時失?。?/p>
2.3、?完整版安裝
完整版的目錄,即是下文的最終文件目錄。完整版則非常簡單,下載-解壓-運行主程序一氣呵成。
請看下文分解。
3、使用
3.1、最終文件目錄
3.2、主程序
找到主程序:
雙擊運行,按照交互窗口填寫對應(yīng)的內(nèi)容(如果長時間沒有響應(yīng),請按一下空格鍵即可):
3.2.1、絕對路徑
目標文檔,鼠標右鍵,點擊安全,即可看見絕對路徑:
3.2.2、是否為書籍
作者認為,如果是書籍的話,最好把文檔前面的"封面+目錄"以及末尾倒數(shù)幾頁的"致謝"內(nèi)容去除,以提高正確率和可閱讀性。該程序不識別格式,所以這樣能最大化得到文字信息。
3.2.3、?截取區(qū)域
如果這是一個電子書的PDF文檔,為了識別文字的結(jié)果更加準確,方便讀者搜索查閱內(nèi)容,作者認為可以把每一頁書的頂部區(qū)域的標注去掉,例如這種區(qū)域:
這種區(qū)域與正文內(nèi)容無關(guān),可以去掉。
那么如何確定好去掉區(qū)域的所占比例呢?下面細說:
使用微信截圖功能,確定這個圖片的“最大高度”,再確定截取區(qū)域的“高度”,二者相除,即可得到比例,圖解如下:
3.2.4、?進程數(shù)
進程數(shù)決定了這個多線程程序的執(zhí)行速度,但也不是數(shù)字填的越高越好。
下面給出幾個數(shù)值參考:
游戲本->20線程
全能本->10-18線程
輕薄本->建議12線程以下
3.3、運行完成
運行完成的結(jié)果顯示:轉(zhuǎn)換后的文字列表內(nèi)容+提示信息:
3.4、保存路徑
程序運行完成后,默認的保存路徑為PDF文件的同目錄下。
4、代碼詳解
4.1、思路
需求是圖片式PDF識別轉(zhuǎn)換為文字式可搜索word:
第一步:告訴用戶這個產(chǎn)品->介紹
第二步:用戶輸入圖片式PDF的路徑(需要的是絕對路徑)
第三步:該PDF文檔是否是書籍,是:刪除非正文的頁面(封面、目錄、結(jié)尾)->在后續(xù)步驟執(zhí)行刪除;否,不執(zhí)行刪除操作
第四步:詢問是否需要截取圖片區(qū)域(是,輸入截取的比例;否,截取比例制為0)->立即執(zhí)行->提取到新的文件夾
第五步:用戶輸入本次運行過程中用到的進程數(shù)(游戲本可以輸入20,全能本10-15,其他建議10甚至是8以下)
第六步:刪除不要的圖片區(qū)域
第七步:開始處理,把結(jié)果寫入到PDF同路徑下刪除過程性文件
第八步:刪除過程性文件,把處理結(jié)果和處理后的文件路徑告訴用戶
4.2、交互
4.3、提取圖片
提取圖片式PDF文件的每一頁,保存到一個臨時圖片文件夾下面:
4.4、裁剪圖片
4.5、刪除不必要的內(nèi)容
4.5、?OCR處理
4.5.1、處理裁剪后的圖片
4.5.2、寫入文件
文章來源:http://www.zghlxwxcb.cn/news/detail-803807.html
5、?完整源代碼
代碼即注釋:文章來源地址http://www.zghlxwxcb.cn/news/detail-803807.html
# -*- coding: utf-8 -*-
# @Author:逐夢蒼穹
# @Time: 2024/1/18 1:23
import os
import cv2
import fitz
import shutil
import threading
from concurrent.futures import ThreadPoolExecutor, as_completed
from cnocr import CnOcr
from tqdm import tqdm
from PIL import Image
from docx import Document
def mkdir(folder_path):
os.makedirs(folder_path, exist_ok=True)
def get_max_folder_number(folder_path):
image_files = [f for f in os.listdir(folder_path) if f.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp'))]
return len(image_files)
def crop_top_and_save(args):
i, image_path, output_path, crop_percentage = args
image = cv2.imread(image_path)
height = image.shape[0]
crop_pixels = int(height * crop_percentage)
cropped_image = image[crop_pixels:, :]
cv2.imwrite(output_path, cropped_image)
print(f"Image {i + 1} cropped and saved: {output_path}")
def startCutImage(input_folder, output_folder, crop_percentage, max_workers_input):
mkdir(output_folder)
max_folder_number = get_max_folder_number(input_folder)
with ThreadPoolExecutor(max_workers=max_workers_input) as executor:
args_list = [
(i, os.path.join(input_folder, f'{i + 1}.jpg'), os.path.join(output_folder, f'{i + 1}.jpg'), crop_percentage)
for i in range(max_folder_number)
]
executor.map(crop_top_and_save, args_list)
def get_max_folder_number(folder_path):
image_files = [f for f in os.listdir(folder_path) if f.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp'))]
return len(image_files)
def delete_images(folder_path, start_index, end_index):
for i in range(start_index, end_index + 1):
imageStr = str(i) + ".jpg"
file_path = os.path.join(folder_path, imageStr)
os.remove(file_path)
print(f"Deleted: {file_path}")
def startDeleteImage(folder_path, end_index, back_start_index_input):
max_folder_number = get_max_folder_number(folder_path)
if max_folder_number > 0:
start_index = 1
back_start_index = max_folder_number - back_start_index_input + 1
back_end_index = max_folder_number
delete_images(folder_path, start_index, end_index)
delete_images(folder_path, back_start_index, back_end_index)
else:
print("No valid image files found.")
def convert_page_to_image(pdf_path, output_folder, page_number):
pdf_document = fitz.open(pdf_path)
page = pdf_document[page_number]
image_list = page.get_images(full=True)
for img_index, img_info in enumerate(image_list):
image_index = img_info[0]
base_image = pdf_document.extract_image(image_index)
image_bytes = base_image["image"]
image_filename = os.path.join(output_folder, f"{page_number + 1}.jpg")
with open(image_filename, "wb") as image_file:
image_file.write(image_bytes)
pdf_document.close()
def pdf_to_images(pdf_path, output_folder, num_workers):
if not os.path.exists(output_folder):
os.makedirs(output_folder)
pdf_document = fitz.open(pdf_path)
total_pages = pdf_document.page_count
with ThreadPoolExecutor(max_workers=num_workers) as executor:
futures = [executor.submit(convert_page_to_image, pdf_path, output_folder, page_number)
for page_number in range(total_pages)]
for future in tqdm(futures, desc="Converting pages", total=total_pages):
future.result()
def get_max_folder_number(folder_path):
image_files = [f for f in os.listdir(folder_path) if f.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp'))]
return len(image_files)
def ocr_and_append(image_str, startList, event, lock):
pagelist = []
image_number = int(os.path.basename(image_str).split('.')[0])
image = Image.open(image_str)
ocr = CnOcr(debug=False)
res = ocr.ocr(image)
for j in range(len(res)):
pagelist.append(res[j]['text'])
with lock:
startList[image_number - 11] = pagelist
print(f"Image {image_number} OCR completed.")
event.set()
def process_images_with_ocr(start, end, startList, event, max_workers_input, lock):
with ThreadPoolExecutor(max_workers=max_workers_input) as executor:
futures = [executor.submit(ocr_and_append, f'output-image-cut/{i}.jpg', startList, event, lock) for i in
tqdm(range(start, end + 1), desc="OCR Processing")]
for future in as_completed(futures):
future.result()
def startOCR(file_folder, test_end_index, word_file_output_path, max_workers_input):
max_folder_number = get_max_folder_number(file_folder)
start = 1 + test_end_index
end = test_end_index + max_folder_number
startList = [''] * max_folder_number
lock = threading.Lock()
event = threading.Event()
process_images_with_ocr(start, end, startList, event, max_workers_input, lock)
event.wait()
print(len(startList))
for i in startList:
print(len(i))
print(startList)
startWriteWordFile(word_file_output_path, startList)
def startWriteWordFile(word_file_path, listPages):
doc = Document()
for i in listPages:
write_list_to_word(word_file_path, i, doc)
doc.add_page_break()
doc.save(word_file_path)
def write_list_to_word(word_file, my_list, doc):
endList = []
for item in my_list:
item = item.strip()
if len(item) < 10:
if endList != None and len(endList) > 0:
doc.add_paragraph("".join(endList))
endList = []
doc.add_paragraph(item)
else:
endList.append(item)
if item == my_list[-1]:
doc.add_paragraph("".join(endList))
endList = []
def main():
try:
crop_percentage = 0.0
end_index = 0
back_start_index_input = 0
print("==========================")
print("這是一個OCR識別程序,作者CSDN@逐夢蒼穹,該程序不做商用請切記!")
print("==========================")
pdf_file_path = str(input("請輸入PDF文件的絕對路徑:"))
print("該PDF文檔是否是書籍?")
isBookPdf = int(input("(是,請輸入1;否,請輸入0):"))
if isBookPdf == 1:
print("輸入要刪除非正文的頁面(封面、目錄、結(jié)尾)")
end_index = int(input("需要刪除該文檔的前幾頁: "))
back_start_index_input = int(input("需要刪除該文檔的倒數(shù)前幾頁: "))
print("詢問是否需要截取圖片區(qū)域?")
isCutImage = int(input("(是,請輸入1;否,請輸入0):"))
if isCutImage == 1:
crop_percentage = float(input("請輸入截取圖片區(qū)域的縱向比例:"))
max_workers = int(input("請輸入本次運行過程中想要使用的進程數(shù):"))
if max_workers <= 0:
max_workers = 1
except Exception as e:
print("參數(shù)有誤,報錯信息如下:", e)
try:
pdf_to_images(pdf_file_path, 'output-image', max_workers)
if isCutImage == 1:
startCutImage('output-image', 'output-image-cut', crop_percentage, max_workers)
if isBookPdf == 1:
startDeleteImage('output-image-cut', end_index, back_start_index_input)
file_name = os.path.splitext(os.path.basename(pdf_file_path))[0]
directory_path = os.path.dirname(pdf_file_path)
word_file_path = directory_path + '\\' + file_name + '(OCR_XZL).docx'
startOCR(r'output-image-cut', end_index, word_file_path, max_workers)
except Exception as e:
print("處理過程出錯,報錯信息如下:", e)
try:
delete_path_1 = r"output-image"
delete_path_2 = r"output-image-cut"
shutil.rmtree(delete_path_1)
shutil.rmtree(delete_path_2)
print(f"Folder '{delete_path_1}' successfully removed.")
print(f"Folder '{delete_path_2}' successfully removed.")
print("OCR處理完成!")
except Exception as e:
print("刪除過程性文件出錯,原因如下:", e)
if __name__ == '__main__':
main()
到了這里,關(guān)于python實現(xiàn)圖片式PDF轉(zhuǎn)可搜索word文檔[OCR](已打包exe文件)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!