当前位置: 首页 > news >正文

PIL与OpenCV双线性插值实现差异导致模型精度不够踩坑

起因

训练分类模型使用的是PIL库的resize,指定biliner算法采样,部署使用的是c++ opencv,发现opencv resize后的和PIL resize的不一样,cv的resize图片噪点多,而PIL的很平滑反而和cv的INTER_AREA插值效果差不多,PIL的库很可能做了均值采样。

在图像处理中,双线性插值(Bilinear Interpolation)是最常用的图像缩放算法之一。然而,不同图像处理库的具体实现可能存在差异。本文通过实验对比Python中PIL(Pillow)库和OpenCV库的双线性插值实现差异。

双线性插值原理回顾

双线性插值是一种在二维空间进行线性插值的方法,它通过四个最近的像素点计算新像素值。基本步骤包括:

  1. 计算目标像素在原图像中的对应位置(通常是非整数坐标)
  2. 确定该位置周围的四个最近邻像素
  3. 分别在水平和垂直方向进行线性插值
  4. 组合两次插值结果得到最终像素值

实验设计与实现

我设计了一个对比实验来验证PIL和OpenCV在双线性插值实现上的差异:

import cv2
import numpy as np
from skimage.metrics import structural_similarity as ssim
from PIL import Image
from PIL.Image import Resamplingdef compare_images(img1, img2):"""比较两幅图像的相似度"""gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)# 计算结构相似性指数ssim_score, _ = ssim(gray1, gray2, full=True)# 计算平均像素差异diff = cv2.absdiff(img1, img2)diff_pixels = np.sum(diff) / (img1.shape[0] * img1.shape[1] * 3)# 计算欧氏距离vec_dist = np.linalg.norm(img1.astype(float) - img2.astype(float))return ssim_score, diff_pixels, vec_dist

实验方法

对比两种缩放路径:

  1. 直接缩放:从原图直接缩放到目标尺寸(50×50)
  2. 二次缩放:先放大到中间尺寸(57×57),再缩小到目标尺寸(50×50)

PIL库实现

img = Image.open('input.jpg')
resized_direct_pil = img.resize((50, 50), Resampling.BILINEAR)
resized_up_down_pil = img.resize((100, 100), Resampling.BILINEAR).resize((50, 50), Resampling.BILINEAR)

OpenCV实现

original_img = cv2.imread('input.jpg')
resized_direct = cv2.resize(original_img, (50, 50), interpolation=cv2.INTER_LINEAR)
resized_up_down = cv2.resize(original_img, (57, 57), interpolation=cv2.INTER_LINEAR)
resized_up_down = cv2.resize(resized_up_down, (50, 50), interpolation=cv2.INTER_LINEAR)

实验结果对比

PIL库结果

结构相似性指数(SSIM): 0.9986
平均像素差异: 0.70
向量欧氏距离: 101.26

OpenCV结果

结构相似性指数(SSIM): 0.9051
平均像素差异: 4.65
向量欧氏距离: 558.88

差异分析与讨论

  1. PIL的实现特性

    • 不同缩放路径下结果高度一致(SSIM 0.9986)
    • 对缩放路径不敏感,表现出更好的稳定性
    • 可能采用了更精确的坐标映射和权重计算
  2. OpenCV的实现特性

    • 不同缩放路径下差异较明显(SSIM 0.9051)
    • 对中间缩放尺寸敏感
    • 可能在边界处理和插值计算上有不同策略
  3. 可能的原因

    • 坐标映射方式不同(PIL可能使用中心对齐,OpenCV可能使用角点对齐)
    • 边界像素处理策略不同
    • 浮点数计算精度差异
    • 颜色通道处理顺序差异(PIL使用RGB,OpenCV使用BGR)

实际应用建议

  1. 一致性要求高的场景

    • 建议在整个流程中使用同一图像处理库
    • 避免混合使用PIL和OpenCV的缩放操作
  2. 性能考虑

    • OpenCV通常在大图像处理上性能更优
    • PIL在小图像处理上可能更精确
  3. 版本控制

    • 不同版本的库可能有不同的实现细节
    • 建议记录使用的库版本号
  4. 预处理建议

    • 对于关键应用,建议进行充分的预处理测试
    • 可以考虑添加对齐处理或后处理来减小差异

完整代码

import cv2
import numpy as np
from skimage.metrics import structural_similarity as ssim
from PIL import Image
from PIL.Image import Resampling  # 新版本推荐方式
def compare_images(img1, img2):# 转换为灰度图像以计算SSIMgray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)# 计算结构相似性指数(SSIM)ssim_score, _ = ssim(gray1, gray2, full=True)# 计算像素差异diff = cv2.absdiff(img1, img2)diff_pixels = np.sum(diff) / (img1.shape[0] * img1.shape[1] * 3)  # 平均每个通道的像素差异# 计算欧氏距离(向量相似度)vec_dist = np.linalg.norm(img1.astype(float) - img2.astype(float))return ssim_score, diff_pixels, vec_distdef compare_images_pil(pil_img1, pil_img2):# 将PIL图像转换为numpy数组img1_np = np.array(pil_img1)img2_np = np.array(pil_img2)# 检查图像维度if len(img1_np.shape) == 2:  # 灰度图像# 直接使用灰度图像gray1 = img1_np# 不需要颜色空间转换img1_np_bgr = cv2.cvtColor(img1_np, cv2.COLOR_GRAY2BGR) if len(img1_np.shape) == 2 else img1_npelse:  # 彩色图像# PIL图像是RGB格式,OpenCV需要BGR格式if img1_np.shape[2] == 4:  # RGBA图像img1_np = cv2.cvtColor(img1_np, cv2.COLOR_RGBA2BGR)else:  # RGB图像img1_np = cv2.cvtColor(img1_np, cv2.COLOR_RGB2BGR)gray1 = cv2.cvtColor(img1_np, cv2.COLOR_BGR2GRAY)if len(img2_np.shape) == 2:  # 灰度图像gray2 = img2_npimg2_np_bgr = cv2.cvtColor(img2_np, cv2.COLOR_GRAY2BGR) if len(img2_np.shape) == 2 else img2_npelse:  # 彩色图像if img2_np.shape[2] == 4:  # RGBA图像img2_np = cv2.cvtColor(img2_np, cv2.COLOR_RGBA2BGR)else:  # RGB图像img2_np = cv2.cvtColor(img2_np, cv2.COLOR_RGB2BGR)gray2 = cv2.cvtColor(img2_np, cv2.COLOR_BGR2GRAY)# 计算结构相似性指数(SSIM)ssim_score, _ = ssim(gray1, gray2, full=True)# 确保两个图像都是3通道(BGR)用于后续计算if len(img1_np.shape) == 2:img1_np = cv2.cvtColor(img1_np, cv2.COLOR_GRAY2BGR)if len(img2_np.shape) == 2:img2_np = cv2.cvtColor(img2_np, cv2.COLOR_GRAY2BGR)# 计算像素差异diff = cv2.absdiff(img1_np, img2_np)diff_pixels = np.sum(diff) / (img1_np.shape[0] * img1_np.shape[1] * 3)  # 平均每个通道的像素差异# 计算欧氏距离(向量相似度)vec_dist = np.linalg.norm(img1_np.astype(float) - img2_np.astype(float))return ssim_score, diff_pixels, vec_dist
# 加载原始图像
original_img = cv2.imread(r'F:\sms\traindata\trainwx\empty\825_r90_1.jpg')  # 替换为你的图片路径
if original_img is None:print("无法加载图像,请检查路径")exit()# 1. 调整图片到500x500(如果原图不是500x500)# 2. 方法1
resized_direct = cv2.resize(original_img, (50, 50), interpolation=cv2.INTER_LINEAR)# 3. 方法2
resized_up_down = cv2.resize(original_img, (57, 57), interpolation=cv2.INTER_LINEAR)
resized_up_down = cv2.resize(resized_up_down, (50, 50), interpolation=cv2.INTER_LINEAR)#使用python的库再验证
img = Image.open(r'F:\sms\traindata\trainwx\empty\825_r90_1.jpg')
resized_direct_pil = img.resize((50, 50), Resampling.BILINEAR)
resized_up_down_pil = img.resize((100, 100), Resampling.BILINEAR).resize((50, 50), Resampling.BILINEAR)#对比py的结果
ssim_score, diff_pixels, vec_dist = compare_images_pil(resized_direct_pil, resized_up_down_pil)print(f"py结构相似性指数(SSIM): {ssim_score:.4f}")
print(f"py平均像素差异: {diff_pixels:.2f}")
print(f"py向量欧氏距离: {vec_dist:.2f}")# 保存图片
resized_direct_pil.save('resized_direct_pil_250x250.jpg')
resized_up_down_pil.save('resized_up_down_pil_250x250.jpg')# 4. 比较两种方法的结果(理论上应该完全相同)
ssim_score, diff_pixels, vec_dist = compare_images(resized_direct, resized_up_down)# 5. 显示结果
print(f"结构相似性指数(SSIM): {ssim_score:.4f}")
print(f"平均像素差异: {diff_pixels:.2f}")
print(f"向量欧氏距离: {vec_dist:.2f}")# 保存结果图像
cv2.imwrite('resized_direct_250x250.jpg', resized_direct)
cv2.imwrite('resized_up_down_250x250.jpg', resized_up_down)
http://www.dtcms.com/a/486322.html

相关文章:

  • 逆合成孔径雷达成像的MATLAB算法实现
  • 网站定制建设公司启信宝企业查询官网
  • html案例:制作一个图片水印生成器,防止复印件被滥用
  • 最新版谷歌浏览器集成知笺云阅读器控件介绍
  • 嘉定装饰装修网站企业网络营销青岛
  • break,continue练习题
  • 【Ubuntu 24.04.3 LTS(Noble Numbat)】移动硬盘数据提取操作手册
  • 网站开发需求分析与功能设计互联网线上推广是什么工作
  • 做网站前应该怎么处理微信推广文案范文
  • 35.渗透-.Kali Linux-工具-反弹shell生成器
  • 便携式水质监测仪——快速锁定水质污染
  • Redis String原理
  • 旅游网站功能流程图php wordpress教程
  • adminPage-vue3依赖LoadingWrap说明文档,表单页快速开发,使用思路及范例-汇总
  • 八股已死、场景当立(场景篇-JVM)
  • 【MySQL】主从复制
  • C4D域的常规修改层:功能详解与实用技巧
  • 网站后台管理系统模板仿西部数码网站
  • 外贸网站电子建设网站免费推广平台有哪些
  • 【汽车篇】AI深度学习在汽车轮胎X-ray缺陷检测应用方案
  • Jmeter循环控制器,IF控制器,正则表达式
  • 【qt学习】day1登录界面模仿
  • 一款优秀的桌面辅助软件
  • 2025-陇剑杯决赛-ezTraffic
  • 【Qt】1.安装QT
  • Spring AI 番外篇01:MCP Streamable HTTP 模式
  • 【GUI自动化测试】Python 自动化测试框架 pytest 全面指南:基础语法、核心特性(参数化 / Fixture)及项目实操
  • Vue3中组件间的数据传递【6】
  • nginx-1.16.1-2.p01.ky10.sw_64.rpm 安装教程(详细步骤,适用于Kylin V10/SW64架构)
  • 教育培训机构如何开发搭建自己的微信小程序?