基于PyMuPDF和Azure Form Recognizer提取PDF图片遇多边形坐标问题
解决Azure Form Recognizer英寸坐标与PyMuPDF的映射问题
一、确认英寸坐标解析是否正确
Azure Form Recognizer返回的边界多边形以页面左上角为原点,单位为英寸,PyMuPDF(Fitz)的默认坐标单位是点(1点 = 1/72英寸),正确的转换公式应为:
# 单个坐标点转换:英寸转点 pdf_x = az_inch_x * 72 pdf_y = az_inch_y * 72
如果代码中用了96(屏幕DPI)而非72进行转换,必然会导致坐标超出页面范围——因为PDF的标准分辨率是72DPI,96的缩放比例会让坐标放大1.33倍,直接超出页面尺寸。
二、确保坐标正确映射到页面尺寸
- 获取页面实际尺寸:先用PyMuPDF获取当前页面的点单位尺寸:
page = doc.load_page(page_num) page_rect = page.rect # 返回fitz.Rect对象,包含x0,y0(左上角)和x1,y1(右下角) page_width = page_rect.width page_height = page_rect.height - 校验转换后的坐标范围:转换后的所有多边形坐标必须满足
0 ≤ x ≤ page_width且0 ≤ y ≤ page_height。如果超出,要么是Azure返回的坐标有误(比如相对于整个文档而非单页),要么是转换逻辑错误。 - 构建有效裁剪矩形:不要直接用多边形的所有点来裁剪,而是取多边形的极值构建矩形(PyMuPDF的裁剪只需要左上角和右下角坐标):
# 假设polygon是Azure返回的[[x1,y1], [x2,y2], ...]英寸坐标列表 x_coords = [p[0] for p in polygon] y_coords = [p[1] for p in polygon] x0 = min(x_coords) * 72 y0 = min(y_coords) * 72 x1 = max(x_coords) * 72 y1 = max(y_coords) * 72 # 确保矩形有效(避免x0 >=x1或y0 >=y1) if x0 >= x1 or y0 >= y1: raise ValueError("Invalid polygon coordinates after conversion") clip_rect = fitz.Rect(x0, y0, x1, y1)
三、缩放因子对裁剪精度的影响
如果提取图片时使用了缩放矩阵(比如放大图片清晰度),需要注意:
- 若先缩放页面再裁剪:裁剪坐标必须同步乘以缩放因子,比如缩放2倍时,
clip_rect的四个值都要乘以2; - 更稳妥的方式:先按原始页面尺寸裁剪出区域,再对裁剪后的pixmap进行缩放:
# 先按原始尺寸裁剪 pix = page.get_pixmap(clip=clip_rect) # 再缩放(比如2倍) pix = pix.scaled(2, 2) pix.save("extracted_image.png")
这种方式避免了坐标和缩放不同步导致的区域偏移问题。
四、其他可行方案
- 直接使用Azure的图片提取结果:Azure Form Recognizer的分析结果中,
images字段已经包含了识别出的图片的位置、尺寸和内容,可以直接调用接口获取图片,无需手动裁剪; - 验证多边形坐标方向:确认Azure返回的多边形是顺时针/逆时针闭合图形,若存在坐标点顺序混乱,取极值构建矩形的方式依然有效,无需纠结顺序;
- 检查页面旋转:如果PDF页面存在旋转(
page.rotation不为0),需要先将页面旋转回0度再处理坐标,否则会导致裁剪区域错位:if page.rotation != 0: page.set_rotation(0) page_rect = page.rect # 重新获取旋转后的页面尺寸
内容的提问来源于stack exchange,提问作者Mali
相关产品推荐
相关产品推荐

