高阶:基于Python paddleocr库 提取pdf 文档高亮显示的内容

预览


第1步:理解基本结构和导入必要的库

python 复制代码
# 1. 首先导入需要的库
import os  # 用于处理文件和路径
import cv2  # 用于图像处理
import numpy as np  # 用于数值计算
from paddleocr import PaddleOCR  # 用于文字识别
from pdf2image import convert_from_path  # 用于PDF转图像
import time  # 用于计时

第2步:创建基本类结构

python 复制代码
class PDFTextExtractor:
    def __init__(self):
        # 初始化OCR工具
        self.ocr = PaddleOCR(
            use_angle_cls=True,
            lang='ch',  # 中文识别
            use_gpu=False,  # 不使用GPU
            show_log=False  # 不显示日志
        )
        
        # 定义要识别的颜色范围(黄色和红色)
        self.color_ranges = {
            'yellow': {
                'lower': np.array([15, 70, 70]),
                'upper': np.array([35, 255, 255])
            },
            'red': {
                'lower': np.array([0, 70, 70]),
                'upper': np.array([15, 255, 255])
            }
        }

第3步:创建主要处理函数

python 复制代码
def process_pdf(self, pdf_path, output_path='extracted_text.txt'):
    try:
        # 检查PDF文件是否存在
        if not os.path.exists(pdf_path):
            raise FileNotFoundError(f"PDF文件不存在: {pdf_path}")

        print(f"开始处理PDF: {pdf_path}")
        start_time = time.time()

        # 设置poppler路径(需要先安装poppler)
        poppler_path = r"E:\Proper\poppler-24.08.0\Library\bin"
        if not os.path.exists(poppler_path):
            raise Exception(f"Poppler 路径不存在: {poppler_path}")

        # 获取PDF总页数
        total_pages = self.get_pdf_page_count(pdf_path, poppler_path)
        print(f"PDF总页数: {total_pages}")

        # 处理每一页
        with open(output_path, 'w', encoding='utf-8') as f:
            # 处理代码...

第4步:创建图像预处理函数

python 复制代码
def preprocess_image(self, pil_image):
    """图像预处理函数"""
    # 1. 调整图像大小
    pil_image = self.resize_image(pil_image)

    # 2. 转换为OpenCV格式并预处理
    img = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)  # 转换颜色空间
    img = cv2.GaussianBlur(img, (3, 3), 0)  # 使用高斯模糊降噪
    img = cv2.convertScaleAbs(img, alpha=1.2, beta=10)  # 调整对比度和亮度

    return img

def resize_image(self, image):
    """调整图像大小的函数"""
    width, height = image.size
    max_dimension = 2000  # 设置最大尺寸
    
    # 如果图像太大,就等比例缩小
    if width > max_dimension or height > max_dimension:
        scale = max_dimension / max(width, height)
        new_width = int(width * scale)
        new_height = int(height * scale)
        return image.resize((new_width, new_height))
    return image

第5步:创建文本提取函数

python 复制代码
def extract_colored_text(self, img, color_lower, color_upper):
    """提取特定颜色区域的文本"""
    try:
        # 1. 转换为HSV颜色空间(更容易处理颜色)
        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
        
        # 2. 创建颜色掩码
        mask = cv2.inRange(hsv, color_lower, color_upper)
        
        # 3. 图像处理优化
        kernel = np.ones((3, 3), np.uint8)
        mask = cv2.dilate(mask, kernel, iterations=2)  # 膨胀
        mask = cv2.erode(mask, kernel, iterations=1)   # 腐蚀
        mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)  # 开运算
        
        # 4. 提取颜色区域
        result = cv2.bitwise_and(img, img, mask=mask)
        
        # 5. 转换为灰度图
        gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)
        gray = cv2.convertScaleAbs(gray, alpha=1.5, beta=10)
        
        # 6. OCR文字识别
        ocr_result = self.ocr.ocr(gray, cls=True)
        
        # 7. 处理识别结果
        texts = []
        if ocr_result is not None:
            for line in ocr_result:
                if line is not None:
                    for word_info in line:
                        if isinstance(word_info, list) and len(word_info) >= 2:
                            text = word_info[1][0].strip()
                            confidence = word_info[1][1]
                            if confidence > 0.6 and text:  # 置信度大于0.6的结果
                                texts.append(text)
        
        return texts
        
    except Exception as e:
        print(f"文本提取错误: {str(e)}")
        return []

第6步:创建PDF页数获取函数

python 复制代码
def get_pdf_page_count(self, pdf_path, poppler_path):
    """获取PDF总页数"""
    try:
        # 使用pdf2image的方法获取PDF信息
        from pdf2image.pdf2image import pdfinfo_from_path
        info = pdfinfo_from_path(pdf_path, poppler_path=poppler_path)
        return info['Pages']
    except Exception as e:
        print(f"获取PDF页数失败: {str(e)}")
        return 0

第7步:创建主函数

python 复制代码
def main():
    try:
        # 1. 创建PDF文本提取器实例
        extractor = PDFTextExtractor()
        
        # 2. 设置PDF文件路径
        pdf_path = r"你的PDF文件路径"
        
        # 3. 处理PDF
        extractor.process_pdf(pdf_path)
        
    except Exception as e:
        print(f"程序执行失败: {str(e)}")

# 程序入口
if __name__ == "__main__":
    main()

使用步骤:

  1. 安装必要的库:
bash 复制代码
pip install opencv-python numpy paddleocr pdf2image pillow
  1. 安装Poppler:

    • 下载Poppler并解压
    • 将bin目录添加到环境变量
  2. 修改代码中的路径:

    • PDF文件路径
    • Poppler路径
  3. 运行程序

    好的,让我详细解释如何一步步实现这个程序:

第8步:环境准备

  1. 创建项目文件夹
bash 复制代码
mkdir pdf_extractor
cd pdf_extractor
  1. 创建虚拟环境(推荐)
bash 复制代码
python -m venv venv
# Windows激活虚拟环境
venv\Scripts\activate
# Linux/Mac激活虚拟环境
source venv/bin/activate
  1. 安装所需库
bash 复制代码
pip install opencv-python
pip install numpy
pip install paddleocr
pip install pdf2image
pip install pillow

第9步:创建项目结构

pdf_extractor/
    ├── main.py          # 主程序文件
    ├── requirements.txt  # 依赖库列表
    └── output/          # 输出文件夹

第10步:编写完整代码

main.py 中:

python 复制代码
import os
import cv2
import numpy as np
from paddleocr import PaddleOCR
from pdf2image import convert_from_path
import time

class PDFTextExtractor:
    def __init__(self):
        # 初始化OCR
        print("初始化OCR系统...")
        self.ocr = PaddleOCR(
            use_angle_cls=True,
            lang='ch',
            use_gpu=False,
            show_log=False
        )
        
        # 定义颜色范围
        self.color_ranges = {
            'yellow': {
                'lower': np.array([15, 70, 70]),
                'upper': np.array([35, 255, 255])
            },
            'red': {
                'lower': np.array([0, 70, 70]),
                'upper': np.array([15, 255, 255])
            }
        }
        print("初始化完成!")

    def process_pdf(self, pdf_path, output_path='output/extracted_text.txt'):
        """处理PDF文件的主函数"""
        try:
            # 创建输出目录
            os.makedirs(os.path.dirname(output_path), exist_ok=True)
            
            # 检查文件是否存在
            if not os.path.exists(pdf_path):
                raise FileNotFoundError(f"PDF文件不存在: {pdf_path}")

            print(f"开始处理PDF: {pdf_path}")
            start_time = time.time()

            # 处理每一页
            self._process_pages(pdf_path, output_path)

            # 完成处理
            end_time = time.time()
            print(f"\n处理完成!用时: {end_time - start_time:.2f}秒")
            print(f"结果已保存到: {output_path}")

        except Exception as e:
            print(f"处理过程中出错: {str(e)}")
            raise

    def _process_pages(self, pdf_path, output_path):
        """处理PDF的所有页面"""
        # 获取PDF总页数
        total_pages = self.get_pdf_page_count(pdf_path)
        print(f"PDF总页数: {total_pages}")

        # 打开输出文件
        with open(output_path, 'w', encoding='utf-8') as f:
            # 处理每一页
            for page_num in range(1, total_pages + 1):
                self._process_single_page(pdf_path, page_num, total_pages, f)

好的,让我们继续完成代码的其余部分:

python 复制代码
    def _process_single_page(self, pdf_path, page_num, total_pages, output_file):
        """处理单个PDF页面"""
        print(f"\n处理第 {page_num}/{total_pages} 页...")
        try:
            # 1. 转换PDF页面为图像
            pages = convert_from_path(
                pdf_path,
                first_page=page_num,
                last_page=page_num,
                dpi=200,  # 设置分辨率
                poppler_path=r"E:\Proper\poppler-24.08.0\Library\bin",  # 修改为你的poppler路径
                thread_count=1
            )

            if not pages:
                print(f"警告: 第 {page_num} 页转换失败")
                return

            # 2. 获取页面图像
            page = pages[0]
            
            # 3. 预处理图像
            img = self.preprocess_image(page)

            # 4. 处理每种颜色
            page_results = []
            for color_name, color_range in self.color_ranges.items():
                print(f"处理{color_name}色文本...")
                highlighted_text = self.extract_colored_text(
                    img.copy(),
                    color_range['lower'],
                    color_range['upper']
                )
                if highlighted_text:
                    page_results.extend(highlighted_text)

            # 5. 保存结果
            if page_results:
                output_file.write(f"\n第{page_num}页标注文本:\n")
                output_file.write('\n'.join(page_results) + '\n')
                output_file.flush()
                print(f"第 {page_num} 页找到 {len(page_results)} 条文本")
            else:
                print(f"第 {page_num} 页未找到高亮文本")

            # 6. 清理内存
            del pages
            del page
            del img

        except Exception as e:
            print(f"处理第 {page_num} 页时出错: {str(e)}")

    def preprocess_image(self, pil_image):
        """图像预处理"""
        try:
            # 1. 调整图像大小
            resized_image = self.resize_image(pil_image)
            
            # 2. 转换为OpenCV格式
            img = cv2.cvtColor(np.array(resized_image), cv2.COLOR_RGB2BGR)
            
            # 3. 图像增强
            img = cv2.GaussianBlur(img, (3, 3), 0)  # 降噪
            img = cv2.convertScaleAbs(img, alpha=1.2, beta=10)  # 增加对比度和亮度
            
            return img
            
        except Exception as e:
            print(f"图像预处理错误: {str(e)}")
            raise

    def resize_image(self, image):
        """调整图像大小"""
        try:
            width, height = image.size
            max_dimension = 2000
            
            # 如果图像太大,进行缩放
            if width > max_dimension or height > max_dimension:
                scale = max_dimension / max(width, height)
                new_width = int(width * scale)
                new_height = int(height * scale)
                return image.resize((new_width, new_height))
            return image
            
        except Exception as e:
            print(f"图像缩放错误: {str(e)}")
            raise

使用示例:

python 复制代码
def main():
    try:
        # 1. 创建输出目录
        os.makedirs('output', exist_ok=True)

        # 2. 创建提取器实例
        print("初始化PDF文本提取器...")
        extractor = PDFTextExtractor()

        # 3. 设置PDF文件路径
        pdf_path = r"你的PDF文件路径"  # 修改为你的PDF文件路径
        output_path = "output/extracted_text.txt"

        # 4. 处理PDF
        print(f"开始处理PDF文件: {pdf_path}")
        extractor.process_pdf(pdf_path, output_path)

    except Exception as e:
        print(f"程序执行失败: {str(e)}")
        raise

if __name__ == "__main__":
    main()

使用说明:

  1. 准备工作

    • 安装所需库
    • 安装Poppler并设置路径
    • 准备要处理的PDF文件
  2. 修改配置

    • 修改PDF文件路径
    • 修改Poppler路径
    • 根据需要调整颜色范围
  3. 运行程序

bash 复制代码
python main.py
  1. 查看结果
    • 输出文件将保存在output目录下
    • 程序会显示处理进度和结果

完整项目代码

python 复制代码
import os
import cv2
import numpy as np
from paddleocr import PaddleOCR
from pdf2image import convert_from_path
import time


class PDFTextExtractor:
    def __init__(self):
        self.ocr = PaddleOCR(
            use_angle_cls=True,
            lang='ch',
            use_gpu=False,
            show_log=False
        )

        self.color_ranges = {
            'yellow': {
                'lower': np.array([15, 70, 70]),
                'upper': np.array([35, 255, 255])
            },
            'red': {
                'lower': np.array([0, 70, 70]),
                'upper': np.array([15, 255, 255])
            }
        }

    def process_pdf(self, pdf_path, output_path='extracted_text.txt'):
        try:
            if not os.path.exists(pdf_path):
                raise FileNotFoundError(f"PDF文件不存在: {pdf_path}")

            print(f"开始处理PDF: {pdf_path}")
            start_time = time.time()

            poppler_path = r"E:\Proper\poppler-24.08.0\Library\bin"
            if not os.path.exists(poppler_path):
                raise Exception(f"Poppler 路径不存在: {poppler_path}")

            # 获取PDF总页数
            total_pages = self.get_pdf_page_count(pdf_path, poppler_path)
            print(f"PDF总页数: {total_pages}")

            with open(output_path, 'w', encoding='utf-8') as f:
                for page_num in range(1, total_pages + 1):
                    print(f"\n处理第 {page_num}/{total_pages} 页...")

                    try:
                        pages = convert_from_path(
                            pdf_path,
                            first_page=page_num,
                            last_page=page_num,
                            dpi=200,
                            poppler_path=poppler_path,
                            thread_count=1
                        )

                        if not pages:
                            print(f"警告: 第 {page_num} 页转换失败")
                            continue

                        page = pages[0]
                        # 转换和预处理图像
                        img = self.preprocess_image(page)

                        # 处理每种颜色
                        page_results = []
                        for color_name, color_range in self.color_ranges.items():
                            print(f"处理{color_name}色文本...")
                            highlighted_text = self.extract_colored_text(
                                img.copy(),  # 使用图像副本
                                color_range['lower'],
                                color_range['upper']
                            )
                            if highlighted_text:
                                page_results.extend(highlighted_text)

                        # 保存结果
                        if page_results:
                            f.write(f"\n第{page_num}页标注文本:\n")
                            f.write('\n'.join(page_results) + '\n')
                            f.flush()
                            print(f"第 {page_num} 页找到 {len(page_results)} 条文本")
                        else:
                            print(f"第 {page_num} 页未找到高亮文本")

                        # 清理内存
                        del pages
                        del page
                        del img

                    except Exception as e:
                        print(f"处理第 {page_num} 页时出错: {str(e)}")
                        continue

            end_time = time.time()
            print(f"\n处理完成!用时: {end_time - start_time:.2f}秒")
            print(f"结果已保存到: {output_path}")

        except Exception as e:
            print(f"处理过程中出错: {str(e)}")
            raise

    def preprocess_image(self, pil_image):
        """图像预处理"""
        # 调整大小
        pil_image = self.resize_image(pil_image)

        # 转换为OpenCV格式并预处理
        img = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)
        img = cv2.GaussianBlur(img, (3, 3), 0)  # 降噪
        img = cv2.convertScaleAbs(img, alpha=1.2, beta=10)  # 增加对比度和亮度

        return img

    def get_pdf_page_count(self, pdf_path, poppler_path):
        """获取PDF页数"""
        try:
            pages = convert_from_path(
                pdf_path,
                dpi=72,
                poppler_path=poppler_path,
                first_page=1,
                last_page=1
            )
            # 使用 pdf2image 的方法获取总页数
            from pdf2image.pdf2image import pdfinfo_from_path
            info = pdfinfo_from_path(pdf_path, poppler_path=poppler_path)
            return info['Pages']
        except Exception as e:
            print(f"获取PDF页数失败: {str(e)}")
            return 0

    def resize_image(self, image):
        """调整图像大小"""
        width, height = image.size
        max_dimension = 2000  # 增加最大尺寸以提高识别率
        if width > max_dimension or height > max_dimension:
            scale = max_dimension / max(width, height)
            new_width = int(width * scale)
            new_height = int(height * scale)
            return image.resize((new_width, new_height))
        return image

    def extract_colored_text(self, img, color_lower, color_upper):
        """提取特定颜色区域的文本"""
        try:
            # 转换颜色空间
            hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

            # 创建掩码
            mask = cv2.inRange(hsv, color_lower, color_upper)

            # 形态学操作
            kernel = np.ones((3, 3), np.uint8)
            mask = cv2.dilate(mask, kernel, iterations=2)
            mask = cv2.erode(mask, kernel, iterations=1)
            mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)

            # 应用掩码
            result = cv2.bitwise_and(img, img, mask=mask)

            # 转换为灰度图
            gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)

            # 增强对比度
            gray = cv2.convertScaleAbs(gray, alpha=1.5, beta=10)

            # 保存处理后的图像用于调试
            # cv2.imwrite(f'debug_page_{time.time()}.png', gray)

            # OCR识别
            ocr_result = self.ocr.ocr(gray, cls=True)

            # 处理OCR结果
            texts = []
            if ocr_result is not None:  # 添加空值检查
                for line in ocr_result:
                    if line is not None:  # 添加行级空值检查
                        for word_info in line:
                            if isinstance(word_info, list) and len(word_info) >= 2:
                                text = word_info[1][0].strip()
                                confidence = word_info[1][1]
                                if confidence > 0.6 and text:
                                    texts.append(text)

            return texts

        except Exception as e:
            print(f"文本提取错误: {str(e)}")
            return []


def main():
    try:
        extractor = PDFTextExtractor()
        pdf_path = r"E:\z_library_books\平时作业\中国旅游文化_11608595(1).pdf"
        extractor.process_pdf(pdf_path)

    except Exception as e:
        print(f"程序执行失败: {str(e)}")


if __name__ == "__main__":
    main()

补充说明:便于理解程序的运行流程

好的,让我更详细地解释每个步骤:

1. 程序启动和初始化

python 复制代码
def main():
    try:
        # 1. 创建PDF文本提取器
        extractor = PDFTextExtractor()
        
        # 这一步会:
        # - 启动PaddleOCR引擎(文字识别工具)
        # - 设置识别中文
        # - 设置不使用GPU
        # - 设置要识别的颜色范围(黄色和红色)

2. 设置文件路径和开始处理

python 复制代码
        # 2. 设置PDF文件路径
        pdf_path = r"E:\z_library_books\平时作业\中国旅游文化_11608595(1).pdf"
        
        # 3. 开始处理PDF
        extractor.process_pdf(pdf_path)

3. PDF处理流程(process_pdf函数)

python 复制代码
def process_pdf(self, pdf_path, output_path='extracted_text.txt'):
    try:
        # 1. 检查PDF文件是否存在
        if not os.path.exists(pdf_path):
            raise FileNotFoundError("PDF文件不存在")

        # 2. 记录开始时间
        start_time = time.time()

        # 3. 设置poppler工具路径(用于转换PDF为图片)
        poppler_path = r"E:\Proper\poppler-24.08.0\Library\bin"

        # 4. 获取PDF总页数
        total_pages = self.get_pdf_page_count(pdf_path, poppler_path)
        print(f"PDF总页数: {total_pages}")

        # 5. 创建输出文件
        with open(output_path, 'w', encoding='utf-8') as f:
            # 6. 逐页处理
            for page_num in range(1, total_pages + 1):
                # 处理每一页...

4. 单页处理流程

python 复制代码
# 对于每一页:
try:
    # 1. 将PDF页面转换为图片
    pages = convert_from_path(
        pdf_path,
        first_page=page_num,
        last_page=page_num,
        dpi=200,  # 设置图片清晰度
        poppler_path=poppler_path
    )

    # 2. 获取页面图片
    page = pages[0]

    # 3. 预处理图片
    img = self.preprocess_image(page)
    # - 调整图片大小
    # - 增加清晰度
    # - 调整亮度和对比度

    # 4. 处理每种颜色
    page_results = []
    for color_name, color_range in self.color_ranges.items():
        print(f"处理{color_name}色文本...")
        # 提取特定颜色的文本
        highlighted_text = self.extract_colored_text(
            img.copy(),
            color_range['lower'],
            color_range['upper']
        )
        if highlighted_text:
            page_results.extend(highlighted_text)

    # 5. 保存这一页的结果
    if page_results:
        f.write(f"\n第{page_num}页标注文本:\n")
        f.write('\n'.join(page_results) + '\n')

5. 文本提取流程(extract_colored_text函数)

python 复制代码
def extract_colored_text(self, img, color_lower, color_upper):
    try:
        # 1. 转换颜色空间,便于找到高亮部分
        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
        
        # 2. 创建掩码(找出高亮部分)
        mask = cv2.inRange(hsv, color_lower, color_upper)
        
        # 3. 优化掩码
        kernel = np.ones((3, 3), np.uint8)
        mask = cv2.dilate(mask, kernel, iterations=2)
        mask = cv2.erode(mask, kernel, iterations=1)
        
        # 4. 提取高亮区域
        result = cv2.bitwise_and(img, img, mask=mask)
        
        # 5. 转为灰度图
        gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)
        
        # 6. OCR识别文字
        ocr_result = self.ocr.ocr(gray, cls=True)
        
        # 7. 处理识别结果
        texts = []
        if ocr_result is not None:
            for line in ocr_result:
                if line is not None:
                    for word_info in line:
                        text = word_info[1][0].strip()
                        confidence = word_info[1][1]
                        if confidence > 0.6 and text:
                            texts.append(text)
        
        return texts

这个程序就像一个阅读助手:

  1. 先准备好工具(OCR引擎)
  2. 打开PDF文件
  3. 一页一页地:
    • 把PDF页面转成图片
    • 找出高亮的部分
    • 识别高亮部分的文字
    • 记录下识别到的文字
  4. 最后把所有记录的文字保存到文件中
相关推荐
jingling5558 分钟前
如何使用免费资源--知网篇
开发语言·经验分享·搜索引擎·pdf·开源
Eric.Lee202113 分钟前
数据集-目标检测系列 车牌检测&识别 数据集 CCPD2019
人工智能·python·目标检测·计算机视觉·车牌识别·车牌检测·yolo检测
乌恩大侠14 分钟前
画图,matlab,
开发语言·matlab
kris000915 分钟前
Python知识分享第二十九天-PyMySQL
开发语言·数据库·python
盼兮*36 分钟前
Python调用星火认知大模型API(流式传输)
开发语言·python·flask·request
阿松のblog39 分钟前
pyQt5实现页面切换操作
开发语言·qt
小馒头学python40 分钟前
【期末大作业】使用Python熟练掌握面向对象
开发语言·python·课程设计
Rossy Yan41 分钟前
【C++面向对象——类的多态性与虚函数】计算图像面积(头歌实践教学平台习题)【合集】
开发语言·c++·多态·面向对象·虚函数·头歌实践教学平台
MavenTalk1 小时前
如何使用Python进行音频片断合成
开发语言·python·音视频·pico2wave·gtts·synthesizer
hnmpf1 小时前
wtforms+flask_sqlalchemy在flask-admin视图下实现日期的修改与更新
后端·python·flask