搞图形学和HDR(宽动态范围)的同学有时可能碰到OpenEXR格式的数据,后缀名为exr
,这种格式的数据动态范围非常宽,因为它的数据类型是float(32bit或16bit),而一般的图像是uint8(8bit)。
OpenEXR官网:
https://www.openexr.com/
不过从这个官网看不到什么跟读写图片相关的有用信息。
网上查找一番都说imageio可以读写OpenEXR数据(Windows和Linux都可以),如果我第一个搜到的不是imageio就省事了,不过既然坑都踩了,还是记录一下好了。
简单点说,imageio能够读写的图片范围非常广泛(但是效率可能略微有一些慢),如果你碰到了一些非常诡异的图片格式难以通过常用的读图函数读取,可以尝试一下imageio。
官网介绍如下:
Imageio is a Python library that provides an easy interface to read and write a wide range of image data, including animated images, video, volumetric data, and scientific formats. It is cross-platform, runs on Python 3.5+, and is easy to install.
imageio安装包的网址如下:
https://pypi.org/project/imageio/
安装命令如下:
pip install imageio
如果使用的是Anaconda的话,一般默认已安装imageio,但是此时的imageio并不能读写OpenEXR数据,缺少依赖库。
下载网址:
https://github.com/imageio/imageio-binaries/tree/master/freeimage
(到上面网址看一下发现这库已经有点年头了,可能因为年久失修,配置起来也不是那么容易,中间踩了一些坑)
如果我们在python中输入以下命令:
image = imageio.imread('xxx.exr', 'exr')
那么会报一个RuntimeError
:
RuntimeError: The freeimage library could not be loaded: Need FreeImage library. You can obtain it with either:
- download using the command: imageio_download_bin freeimage
- download by calling (in Python): imageio.plugins.freeimage.download()
解决方法看似挺简单,在cmd
里输入imageio_download_bin freeimage
或者在python命令行中输入imageio.plugins.freeimage.download()
,如果能够下载下来,那么恭喜你,问题解决,这一部分后面内容不用再看了;如果下载不下来的话,在输入这两条命令后会提示你需要下载的依赖库版本,目前我尝试出来的Windows和Linux需要的动态链接库分别为:
Windows: FreeImage-3.15.1-win64.dll
Linux: libfreeimage-3.16.0-linux64.so
然后去上面下载网址那里手动把依赖库下载下来。
如果通过下载命令可以成功下载依赖库,那么依赖库会自动放在它该存在的位置。
只有手动下载依赖库的同学才需要看这部分。
以Windows为例(Linux雷同),在python中输入以下命令
import imageio
imageio.core.util.appdata_dir("imageio")
然后就能出现存放路径了:
C:\Users\username\AppData\Local\imageio
依赖库的完整存放路径为:
C:\Users\username\AppData\Local\imageio\freeimage\freeimage-3.15.1-win64.dll
注意freeimage
这个文件夹如果不存在的话手动建立即可
(怎么发现imageio.core.util.appdata_dir("imageio")
能显示存放路径的?从下载命令imageio.plugins.freeimage.download()
出发顺藤摸瓜,在代码里一顿翻找就找出来了)
代码如下:
import imageio
image = imageio.imread('test.exr', 'exr')
imageio.imwrite('save_imageio.exr', image)
如果把save_imageio.exr
再读进来,会发现它与image
的值存在微小差异,怀疑是压缩损失,具体如何避免就不再深究了,因为我突然发现opencv也可以读写,且更方便,且无损。
前面imageio搞得真是一把泪。
python中安装opencv的命令:
pip install opencv-python
我这里装的是4.2.0版本。
opencv读写OpenEXR数据的代码:
import cv2
image = cv2.imread('test.exr', cv2.IMREAD_UNCHANGED)
cv2.imwrite('save_cv2.exr', image)
读图时必须加cv2.IMREAD_UNCHANGED
。如果把save_cv2.exr
再读进来,那么它与image
完全相同,所以保存过程是无损的。
注意: 使用opencv读写OpenEXR数据需要特别注意通道反序
的问题,可能很多人都知道,opencv读进来的图片是BGR通道顺序,与现在常用的RGB相反,如果我们处理的数据是图像,并且后期的显示和保存都仍然使用opencv来做的话,那么通道顺序影响不大,但是如果OpenEXR数据保存的不是图像而是其他什么东西,那就要很小心了。比如图形学中常用的3D模型的position,normal等信息,它们也是3通道的,使用opencv读进来后,通道顺序是(z, y, x)
,如果需要做坐标空间变换,那么得先调整通道顺序,不然就栽坑里了。调整通道顺序的代码如:
position = position[:, :, ::-1]