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

jpg图片使用pil的resize后_Python Pillow 和 cv2 图片 resize 速度的比较

今天要说的事情很简单,就是比较了一下 PIL 和 cv2 resize 图片的速度。我们都知道,Python 中有关图像处理的库有很多,常见的有 cv2,scikit-image,PIL (严谨点应该叫 Pillow,下文就用 PIL 来代替了) 等等。在用 Python 进行深度学习图像任务的时候,我们常常会使用 PIL 这个库来读取图片(尤其是在用 PyTorch 的时候)。至于为什么 PIL 比较常用,我也不知道... 难道是 TorchVision 带来的风气(https://github.com/pytorch/vision#image-backend)? 但在进行视频流处理的时候,我们往往会用到 cv2,因为都会用到 cv2.VideoCapture() 来读视频(应该没有人第一反应是其他的库吧)。

为什么会想到对比这二者 resize 图片的速度?原因是最近处理视频流的时候用的是 cv2 读取,每一帧读出来的结果是一个3维的 Numpy Array。然后要 resize 一下送到模型嘛,因为惯性我就用了 PIL 来做图片 resize (而没有用 cv2.resize)。PIL 的 resize 只能对 PIL Image 类做处理,所以我先把 Numpy Array 转成 PIL Image, 然后 resize, 然后再转回 Numpy Array。 我后来再看代码的时候心想这 tm 是什么操作?那索性来比一比这二者的速度吧。

因为这不是什么严肃的对比,所以我就不列啥硬件软件配置了。但大体上就是,一台普通的电脑,用着 pip3 安装来的普通的 cv2 和 PIL,做的一次简单的对比。

1. resize 对比

对比中我们使用的是 CV 界的经典图像,512x512 的豪华彩色三通道 Lena 的 png 图片:

9f5e00f9844d8bc70985898102dbbd78.png
// 看看这高清的像素,看看这左上角标的 2014 的独特 logo,看看这被截到只剩头和肩膀的 Lena, 还有知乎你为什么不支持删除线??

首先我们先测试一下 cv2 的速度,我们采用双线性插值,将 512x512 的图片 resize 到 1024x1024:

repeat = 2000
im = cv2.imread('lena512_colour.png')
print(type(im), im.shape)
# <class 'numpy.ndarray'> (512, 512, 3)

start = time.time()
for i in range(repeat):
    im_resized = cv2.resize(im, (1024, 1024), interpolation=cv2.INTER_LINEAR)

print('cv2 resize - total time of %d is %.3f s' % (repeat, time.time()-start))
# cv2 resize - total time of 2000 is 3.789 s

然后试试 PIL 吧,所以条件一致的情况下,我们假定需要的输入和输出都是 Numpy Array

repeat = 2000
im = cv2.imread('lena512_colour.png')

start = time.time()
for i in range(repeat):
    tmp = Image.fromarray(im)
    tmp = tmp.resize((1024, 1024), resample=Image.BILINEAR)
    im_resized = np.array(tmp)

print('PIL resize - total time of %d is %.3f s' % (repeat, time.time()-start))
# PIL resize - total time of 2000 is 40.714 s

这... 被吊打好嘛。当然这对 PIL 有些不公平,毕竟 Numpy ArrayPIL Image 互相转换也要花费时间,所以我们来测一下输入输出都是 PIL Image 时候的速度:

repeat = 2000

im = Image.open('lena512_colour.png')
print(type(im))
# <class 'PIL.PngImagePlugin.PngImageFile'>

start = time.time()
for i in range(repeat):
    im_resized = im.resize((1024, 1024), resample=Image.BILINEAR)

print('PIL resize - total time of %d is %.3f s' % (repeat, time.time()-start))
# PIL resize - total time of 2000 is 27.219 s

好嘛,还是被吊打... 我查了查资料,Kaggle 上有位老哥做了比较全的对比,比我严谨多了,结果也是 PIL 被吊打(https://www.kaggle.com/vfdev5/pil-vs-opencv)。还有老哥建议用优化过的 Pillow-SIMD,但是貌似官方的测试结果(https://python-pillow.org/pillow-perf/)还是差 OpenCV 好多啊... well...

2. 买一送一:cv2 的 BGR

我们都知道,用 cv2 打开彩色三通道图像的时候,通道的顺序是 BGR,所以比如我们用 pyplot 来显示图片的时候,图片是不正常的,效果如下:

2ac7d076a5e7ada87a573ce3632f3ef6.png
冷色调的 Lena

所以我们在预处理的时候,还要把通道给变成 RGB。怎么变呢,我知道有三种方法:

# 方法一:
repeat = 50000
im = cv2.imread('lena512_colour.png')

start = time.time()
for i in range(repeat):
    b, g, r = cv2.split(im)
    im_rgb1 = cv2.merge([r, g, b])

print('method 1 - total time of %d is %.3f s' % (repeat, time.time()-start))
# method 1 - total time of 50000 is 9.279 s


# 方法二:
repeat = 50000
im = cv2.imread('lena512_colour.png')

start = time.time()
for i in range(repeat):
    im_rgb2 = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)

print('method 2 - total time of %d is %.3f s' % (repeat, time.time()-start))
# method 2 - total time of 50000 is 1.602 s


# 方法三:
repeat = 50000
im = cv2.imread('lena512_colour.png')

start = time.time()
for i in range(repeat):
    im_rgb3 = im[: , : , ::-1]

print('method 3 - total time of %d is %.3f s' % (repeat, time.time()-start))
# method 3 - total time of 50000 is 0.027 s

三种方法的结果都是一样的。但是大家需要主要的是,虽然第三种速度最快,但 im_rgb3im 是共享内存的哦,也就是如果在后边 im 的值被(inplace)修改了,im_rgb3 的值也会跟着相应变化,而前两种方法是不会有这种情况的。

3. 总结

经过不严谨的对比显示,cv2 比 PIL 快不少,至少在图像 resize 上。好了,不多说了,周一的时候把改正的代码测试一下,估计模型的实时处理速度会提升一点,没准老板会夸我优化做得不错呢(玩笑,测试用的 demo 而已),CV 从业者的一天,往往就是这么朴实无华且枯燥。

相关文章:

  • 小白学vb还是python_小白学 Python(6):基础运算符(下)
  • qt 表格中插入一行_表格中插入列,如何不影响其他表格,1.3%的人还不会?
  • # 睡眠3秒_床上这样睡觉的人,睡眠质量多半不好
  • l4168升级固件出错如何恢复_苹果 iOS 13 / iPadOS 官方测试版固件 IPSW 下载升级降级与恢复教程...
  • 时序约束优先级_如何写出时序收敛的代码
  • 移动端布局三种视口_移动端布局适配
  • 柱形图无数据可选中_让领导看呆!Excel多层柱形图来了
  • ios 监听一个控制器的属性_iOS控制器间跳转
  • 语言中日期间的天数怎么计算_计算员工工龄,这个问题千万要注意
  • springboot过滤字段_springboot实现拦截器之验证登录示例
  • python计算机入门书籍_计算机学习--摘自python 入门书 侯爵
  • 如何卸载更换MySQL版本_mysql卸载(win10 适用于想更换版本的)
  • dos导入mysql文件_dos下导入mysql备份文件
  • java -jar 未响应_简单易学的测试攻略:JMeter测试Java请求示例
  • python 求余数_Python数据结构与算法——散列(Hash)
  • [笔记] php常见简单功能及函数
  • CSS 三角实现
  • ES6之路之模块详解
  • iOS小技巧之UIImagePickerController实现头像选择
  • JavaScript 奇技淫巧
  • JavaScript新鲜事·第5期
  • PV统计优化设计
  • Python进阶细节
  • springMvc学习笔记(2)
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 关于List、List?、ListObject的区别
  • 关于字符编码你应该知道的事情
  • 回顾2016
  • 机器学习学习笔记一
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 记一次删除Git记录中的大文件的过程
  • 前端技术周刊 2019-01-14:客户端存储
  • 十年未变!安全,谁之责?(下)
  • 提醒我喝水chrome插件开发指南
  • 小程序开发之路(一)
  • 新年再起“裁员潮”,“钢铁侠”马斯克要一举裁掉SpaceX 600余名员工 ...
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • #pragma 指令
  • (1)(1.13) SiK无线电高级配置(五)
  • (附源码)springboot掌上博客系统 毕业设计063131
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • .NET 5种线程安全集合
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地中转一个自定义的弱事件(可让任意 CLR 事件成为弱事件)
  • .Net下C#针对Excel开发控件汇总(ClosedXML,EPPlus,NPOI)
  • .NET中winform传递参数至Url并获得返回值或文件
  • @javax.ws.rs Webservice注解
  • @ModelAttribute注解使用
  • @RequestBody与@ModelAttribute
  • @RequestBody与@ResponseBody的使用
  • [Android]一个简单使用Handler做Timer的例子
  • [Angular] 笔记 7:模块
  • [bzoj1324]Exca王者之剑_最小割
  • [bzoj4240] 有趣的家庭菜园