如何使用PyMuPDF将PDF内图像读取转换为OpenCV图像
PyMuPDF 提取PDF图像转OpenCV格式实现方案
核心对齐标准
首先明确cv2.imread()默认读取结果的固定属性,所有转换逻辑严格对齐:
- 数据类型为
uint8型numpy数组 - 彩色图像通道顺序为BGR(非PyMuPDF默认的RGB顺序)
- 默认丢弃透明Alpha通道
- 灰度图输出单通道数组
- 无重压缩、重采样导致的精度损失
实现逻辑说明
pix_to_opencv_image函数不需要经过内存编解码(比如转PNG字节流再用OpenCV解码,会引入不必要的性能损耗和格式偏差),直接基于Pixmap原始像素数据处理,步骤如下:
- 统一色彩空间:如果原始Pixmap是CMYK格式、或带Alpha通道,先调用PyMuPDF原生接口转成标准RGB格式的Pixmap,这一步由PyMuPDF内部完成色彩转换,精度最高,无额外损失
- 原始字节转numpy数组:直接读取Pixmap的像素字节流,指定dtype为
uint8,避免类型隐式转换 - 通道顺序转换:彩色图将RGB顺序转为OpenCV要求的BGR顺序,灰度图直接保留单通道结构
- 资源释放:临时生成的Pixmap副本及时回收,避免内存泄漏
完整可运行代码
首先修正原有基础代码的语法笔误(多余冒号、变量名错误),再补全转换函数:
import os import cv2 import fitz import numpy as np filename = "myfile.pdf" def pix_to_opencv_image(pix): # 处理带透明通道、CMYK色彩空间的情况,统一转成无Alpha的RGB格式 if pix.n >= 4 or pix.colorspace not in (fitz.csGRAY, fitz.csRGB): pix = fitz.Pixmap(fitz.csRGB, pix) # 读取原始像素数据转uint8数组 img_arr = np.frombuffer(pix.samples, dtype=np.uint8) # 按图像尺寸、通道数调整数组形状 if pix.n == 3: # 彩色图:reshape后将RGB转为BGR img_arr = img_arr.reshape(pix.height, pix.width, 3) cv2.cvtColor(img_arr, cv2.COLOR_RGB2BGR, dst=img_arr) elif pix.n == 1: # 灰度图直接reshape为单通道 img_arr = img_arr.reshape(pix.height, pix.width) # 回收临时Pixmap资源 pix = None return img_arr def read_images(filename): images = [] _, extension = os.path.splitext(filename) if extension.lower() == ".pdf": pdf = fitz.open(filename) for index in range(len(pdf)): page = pdf[index] for im in page.get_image_list(): xref = im[0] pix = fitz.Pixmap(pdf, xref) images.append(pix_to_opencv_image(pix)) pdf.close() else: img = cv2.imread(filename) if img is not None: images.append(img) return images
注意事项
- 不要用
pix.getPNGData()+cv2.imdecode()的方案,该方案会先对像素做PNG编码再解码,虽然是无损但多了冗余计算,且默认会保留Alpha通道,和cv2.imread()默认行为不一致 - 不要手动用切片
[:,:,::-1]做通道翻转,在Pixmap存在行对齐填充的场景下会出现像素错位,上述实现通过PyMuPDF原生接口统一Pixmap格式后再reshape,完全规避该问题 - 转换后的图像和
cv2.imread()读取同源图像的输出在dtype、通道顺序、像素值上完全一致,无精度损失
内容的提问来源于stack exchange,提问作者Vincent
相关产品推荐
相关产品推荐

