可以单个处理图片,也可以选择文件夹批量处理,完全本地cpu处理
需要用到的python库
- pip install PyQt5
- pip install opencv-python
- pip install paddleocr
- pip install numpy
- pip install pillow
- pip install pyperclip
python版本 3.8或者3.9
python下载地址:https://www.python.org/downloads/windows/
python代码
- import sys
- import os
- from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QHBoxLayout, QWidget, QFileDialog, QTextEdit, QLabel, QMessageBox, QProgressBar
- from PyQt5.QtGui import QPixmap, QImage
- from PyQt5.QtCore import Qt, QThread, pyqtSignal
- import cv2
- from paddleocr import PaddleOCR
- import numpy as np
- from PIL import Image
- import pyperclip
-
- class OCRThread(QThread):
- progress_update = pyqtSignal(int)
- result_ready = pyqtSignal(list)
-
- def __init__(self, ocr, file_list):
- super().__init__()
- self.ocr = ocr
- self.file_list = file_list
-
- def run(self):
- results = []
- for i, file in enumerate(self.file_list):
- try:
- result = self.ocr.ocr(file, cls=True)
- results.append((os.path.basename(file), result))
- except Exception as e:
- results.append((os.path.basename(file), None))
- print(f"处理文件 {file} 时出错: {str(e)}")
- self.progress_update.emit(int((i + 1) / len(self.file_list) * 100))
- self.result_ready.emit(results)
-
- class OCRApp(QMainWindow):
- def __init__(self):
- super().__init__()
- self.initUI()
- self.ocr = PaddleOCR(use_angle_cls=True, lang="ch")
- self.current_image = None
-
- def initUI(self):
- self.setWindowTitle('OCR应用')
-
- fixed_width = 400
- fixed_height = 500
- self.setFixedSize(fixed_width, fixed_height)
-
- central_widget = QWidget()
- self.setCentralWidget(central_widget)
- main_layout = QVBoxLayout()
- central_widget.setLayout(main_layout)
-
- self.image_label = QLabel(self)
- self.image_label.setAlignment(Qt.AlignCenter)
- self.image_label.setFixedSize(fixed_width - 20, 200)
- main_layout.addWidget(self.image_label)
-
- button_layout = QHBoxLayout()
- self.open_file_button = QPushButton('选择图片', self)
- self.open_file_button.clicked.connect(self.open_file)
- button_layout.addWidget(self.open_file_button)
-
- self.open_folder_button = QPushButton('选择文件夹', self)
- self.open_folder_button.clicked.connect(self.open_folder)
- button_layout.addWidget(self.open_folder_button)
-
- self.copy_button = QPushButton('复制内容', self)
- self.copy_button.clicked.connect(self.copy_content)
- button_layout.addWidget(self.copy_button)
-
- main_layout.addLayout(button_layout)
-
- self.progress_bar = QProgressBar(self)
- self.progress_bar.setVisible(False)
- main_layout.addWidget(self.progress_bar)
-
- self.result_text = QTextEdit(self)
- self.result_text.setReadOnly(True)
- main_layout.addWidget(self.result_text)
-
- def open_file(self):
- file_name, _ = QFileDialog.getOpenFileName(self, "选择图片", "", "图片文件 (*.png *.jpg *.bmp)")
- if file_name:
- self.process_image(file_name)
-
- def open_folder(self):
- directory = QFileDialog.getExistingDirectory(self, "选择文件夹")
- if directory:
- files = [os.path.join(directory, f) for f in os.listdir(directory) if f.lower().endswith(('.png', '.jpg', '.bmp'))]
- if files:
- self.process_multiple_images(files)
- else:
- QMessageBox.warning(self, "提示", "文件夹中没有符合条件的图片文件。")
-
- def process_image(self, file_name):
- self.current_image = cv2.imread(file_name)
- if self.current_image is None:
- QMessageBox.warning(self, "错误", "无法加载图片,文件可能已损坏或格式不支持。")
- return
-
- self.display_image(self.current_image)
- try:
- result = self.ocr.ocr(file_name, cls=True)
- self.display_result([(os.path.basename(file_name), result)])
- except Exception as e:
- QMessageBox.warning(self, "错误", f"OCR处理失败: {str(e)}")
-
- def process_multiple_images(self, files):
- self.progress_bar.setVisible(True)
- self.progress_bar.setValue(0)
-
- self.ocr_thread = OCRThread(self.ocr, files)
- self.ocr_thread.progress_update.connect(self.update_progress)
- self.ocr_thread.result_ready.connect(self.display_result)
- self.ocr_thread.start()
-
- def update_progress(self, value):
- self.progress_bar.setValue(value)
-
- def display_image(self, img):
- height, width, channel = img.shape
- bytes_per_line = 3 * width
- q_img = QImage(img.data, width, height, bytes_per_line, QImage.Format_RGB888).rgbSwapped()
- pixmap = QPixmap.fromImage(q_img)
-
- label_width = self.image_label.width()
- label_height = self.image_label.height()
- scale = min(label_width / width, label_height / height)
-
- new_width = int(width * scale)
- new_height = int(height * scale)
-
- scaled_pixmap = pixmap.scaled(new_width, new_height, Qt.KeepAspectRatio, Qt.SmoothTransformation)
- self.image_label.setPixmap(scaled_pixmap)
-
- def display_result(self, results):
- self.result_text.clear()
- for file_name, result in results:
- self.result_text.append(f"文件: {file_name}")
- if result and len(result) > 0 and result[0]:
- try:
- sorted_result = sorted(result[0], key=lambda x: (x[0][0][1], x[0][0][0]))
- for line in sorted_result:
- text = line[1][0]
- self.result_text.append(text)
- except Exception as e:
- self.result_text.append(f"解析结果时出错: {str(e)}")
- else:
- self.result_text.append("未识别到文本")
- self.result_text.append("\n")
-
- self.progress_bar.setVisible(False)
- if len(results) > 1:
- QMessageBox.information(self, "完成", f"已完成 {len(results)} 个文件的识别")
-
- def copy_content(self):
- content = self.result_text.toPlainText()
- pyperclip.copy(content)
- QMessageBox.information(self, "提示", "内容已复制到剪贴板")
-
- if __name__ == '__main__':
- app = QApplication(sys.argv)
- ex = OCRApp()
- ex.show()
- sys.exit(app.exec_())