如何用OpenCV调整图片DPI?含当前检测及300DPI转换需求
解决OpenCV调整图片至300DPI的问题
我之前也碰到过类似的困惑,其实核心要先搞清楚:DPI是图片的元数据(描述每英寸显示的像素数),和像素尺寸是完全独立的两个属性。OpenCV的cv2.resize只负责修改像素数量,根本不会触碰DPI元数据,这就是为什么你用Photoshop验证后发现DPI没变化的原因。
要实现「仅当当前DPI低于300时调整至300DPI」的需求,我们需要结合OpenCV处理像素,再用Pillow库读取/写入DPI元数据,具体步骤如下:
步骤1:读取图片的DPI信息
OpenCV的cv2.imread不会读取图片的EXIF元数据,所以我们用Pillow来获取DPI。先确保你已经安装了Pillow:
pip install pillow
读取DPI的工具函数:
from PIL import Image def get_image_dpi(image_path): with Image.open(image_path) as img: dpi = img.info.get('dpi') # 部分图片可能没有DPI元数据,默认按行业通用的72DPI处理 if dpi is None: return (72, 72) return dpi
调用这个函数就能拿到当前图片的DPI:
dpi_x, dpi_y = get_image_dpi("source.png") current_dpi = min(dpi_x, dpi_y) # 取最小的DPI值作为判断标准
步骤2:计算缩放比例并调整像素尺寸
如果当前DPI低于300,我们需要计算缩放比例(scale = 300 / current_dpi),然后用cv2.resize调整像素尺寸。放大图片时推荐用cv2.INTER_CUBIC插值,能让画质更平滑,更适合OCR识别场景。
完整的处理函数:
import cv2 import numpy as np def resize_image_to_300dpi(image_path, output_path): # 获取当前DPI dpi_x, dpi_y = get_image_dpi(image_path) current_dpi = min(dpi_x, dpi_y) if current_dpi >= 300: print("当前图片DPI已达标,直接保留原画质并写入300DPI元数据") with Image.open(image_path) as img: img.save(output_path, dpi=(300, 300)) return # 用OpenCV读取图片(处理像素) image = cv2.imread(image_path) if image is None: raise ValueError("无法读取图片,请检查文件路径是否正确") # 计算缩放后的像素尺寸 scale = 300 / current_dpi new_width = int(image.shape[1] * scale) new_height = int(image.shape[0] * scale) # 调整像素尺寸 resized_image = cv2.resize(image, (new_width, new_height), interpolation=cv2.INTER_CUBIC) # 用Pillow保存并写入300DPI元数据(OpenCV不支持写入DPI) # 先把OpenCV的BGR格式转换成PIL的RGB格式 pil_image = Image.fromarray(cv2.cvtColor(resized_image, cv2.COLOR_BGR2RGB)) pil_image.save(output_path, dpi=(300, 300)) print(f"已将图片调整至300DPI,保存至{output_path}")
调用示例
resize_image_to_300dpi("source.png", "output_300dpi.png")
关键细节说明
- 为什么必须用Pillow保存?因为OpenCV的
imwrite函数只会写入像素数据,完全忽略DPI元信息,只有通过Pillow才能把300DPI的标记写入图片文件。 - 插值方法选择:放大图片时,
cv2.INTER_CUBIC比默认的INTER_LINEAR画质更清晰,能提升OCR的识别准确率。 - 无DPI元数据的处理:如果图片没有标注DPI,我们默认按72DPI处理,这是多数图片的出厂默认值。
内容的提问来源于stack exchange,提问作者yozawiratama




