python imread函数_Python的各种imread函数在实现方式和读取速度上有何区别?
一看到题主的问题,其实就有个猜想,其实底层应该都是一样的,或者说没几个独立的实现吧?主要是关注开源软件一段时间之后,就会发现开源界其实挺缺人的,现有这些人也都挺懒的。挖坑的人多,填坑的人少。说是这活谁都可以参与,但其实真没多少人实际做。一个活有一个人干了,其他人一般就懒得再重复了。以下就是从源码来看这些开源库的具体实现。
1. PIL.Image.open
代码在这里:Pillow/Image.py at 3.1.x · python-pillow/Pillow · GitHubgithub.com
open() 函数打开图像,但并不读入,直到有操作发生。
具体的读取操作是在 ImageFile.py 写的。大体流程是先检测文件类型,整块地读入文件内容,然后调用解码器解码,做了很多优化,效率应该还是很高的。
2. scipy.misc.imread
misc 的 __init__.py 在这里:scipy/__init__.py at v0.17.1 · scipy/scipy · GitHubgithub.com
调用的还是 pilutil 中的 imread
相关代码如下:
try:
from .pilutil import *
from . import pilutil
__all__ += pilutil.__all__
del pilutil
except ImportError:
pass
也算是学了一招,从 pilutil 导入其所有函数添加到当前空间,然后又删除了 pilutil 消除影响。
3. scipy.ndimage.imread
代码在这里:scipy/io.py at v0.17.1 · scipy/scipy · GitHubgithub.com
imread 调用 scipy.misc.pilutil.imread。从名字就能看出来其实调用的还是 Pillow。
根据 pilutil 代码:scipy/pilutil.py at v0.17.1 · scipy/scipy · GitHubgithub.com
确实是调用 pil.image.open(),然后返回一个 fromimage()。
20180410 更新:scipy.ndimage.imread,其实调用的就是 scipy.misc.imread。我之前没写清楚。代码在这里:https://github.com/scipy/scipy/blob/80e76d43f0ada0a1964195cb6d13ae519feb07e8/scipy/ndimage/io.py#L8github.com
_have_pil = True
try:
from scipy.misc.pilutil import imread as _imread
except ImportError:
_have_pil = False
挺过分的,本身已经用的是 pillow 的 imread 了。又在自己的包里面提供了两个不同的接口。不知道的,还以为做了多少工作呢。其实同一个代码文件里面也标记了,这个 imread 要废弃了,还请直接调用 matplotlib……啊???什么鬼!!!你自己包里面用了两处 pillow 的 imread,然后废弃一个,却推荐别人用 matplotlib 替代,口是心非傲娇代码包。戏精代码如下:
# Use the implementation of `imread` in `scipy.misc.pilutil.imread`.
# If it weren't for the different names of the first arguments of
# ndimage.io.imread and misc.pilutil.imread, we could simplify this file
# by writing
# from scipy.misc.pilutil import imread
# Unfortunately, because the argument names are different, that
# introduces a backwards incompatibility.
@np.deprecate(message="`imread` is deprecated in SciPy 1.0.0.\n"
"Use ``matplotlib.pyplot.imread`` instead.")
def imread(fname, flatten=False, mode=None):
if _have_pil:
return _imread(fname, flatten, mode)
raise ImportError("Could not import the Python Imaging Library (PIL)"
" required to load image files. Please refer to"
" http://pillow.readthedocs.org/en/latest/installation.html"
" for installation instructions.")
4. skimage.io.imread
代码在这里:scikit-image/_io.py at master · scikit-image/scikit-image · GitHubgithub.com
(20180410 更新:该部分代码已修改,链接不可用了
是通过插件 plugin 来读入不同的文件,而且会试用几个不同的 plugins 来找到合适的。
使用 call_plugin 来调用,代码在这里:scikit-image/manage_plugins.py at master · scikit-image/scikit-image · GitHubgithub.com
可以根据如下代码查看插件调用的优先级
# For each plugin type, default to the first available plugin as defined by
# the following preferences.
preferred_plugins = {
# Default plugins for all types (overridden by specific types below).
'all': ['pil', 'matplotlib', 'qt', 'freeimage'],
'imshow': ['matplotlib'],
'imshow_collection': ['matplotlib']
}
plugins 的源代码在这里:scikit-image/scikit-imagegithub.com
可以看到 pil 的 imread,是用 open 打开图像之后,再转换成 ndarray。
20180410 更新:skimage 的插件管理,代码改在了这里:https://github.com/scikit-image/scikit-image/blob/37ed59d2880fa96ff908608d7f723b98cd319c9b/skimage/io/manage_plugins.py#L46github.com
最近一次更新去掉了 freeimage 的插件选项。图像读取的基本原理还是没变。还是优先调用 Pillow,就是插件里面的 pil。
preferred_plugins = {
# Default plugins for all types (overridden by specific types below).
'all': ['pil', 'matplotlib', 'qt'],
'imshow': ['matplotlib'],
'imshow_collection': ['matplotlib']
}
5. cv2.imread
这里是调用的 CV::imread(),代码在这里:opencv/loadsave.cpp at master · opencv/opencv · GitHubgithub.com
。一般来说 C\C++ 的实现,应该比 python 速度快一点。
20180410 更新:看了一下 opencv 的 python3 接口。imread 读进来的 Mat,在转换为 PyObject(Python 对象)的时候,会检查一下,是不是无符号的 UMat。如果是,直接拷贝一个指针给 PyObject;如果不是,会新开一个 Mat,读数据,再生成 PyObject。
而 CV::imread() 本身,调用的,是内部的 imread_() 函数:https://github.com/opencv/opencv/blob/6d83a8038525cf64b0edd866ebbd94906eb5691d/modules/imgcodecs/src/loadsave.cpp#L633github.com
cvLoadImage 到 IplImage 和 cvLoadImageM 到 CvMat,其实也都是调用的 imread_(),详情见代码:https://github.com/opencv/opencv/blob/6d83a8038525cf64b0edd866ebbd94906eb5691d/modules/imgcodecs/src/loadsave.cpp#L966github.com
就是这段:
CV_IMPL IplImage*
cvLoadImage( const char* filename, int iscolor )
{
return (IplImage*)cv::imread_(filename, iscolor, cv::LOAD_IMAGE );
}
CV_IMPL CvMat*
cvLoadImageM( const char* filename, int iscolor )
{
return (CvMat*)cv::imread_( filename, iscolor, cv::LOAD_CVMAT );
}
这里 imread_() 是图像读取的总接口,为表面的各种函数提供核心功能。图像读取的真正魔法,其实发生在 ImageDecoder 里面,代码则在 imgcodecs 目录:opencv/opencvgithub.com
6. matplotlib.image.imread
matplotlib 的文档里面说,matplotlib 原生只可以读取 PNG 文件,有 PIL 的时候,可以读取其他类型的文件。如果使用 URL 打开在线图像文件,需要符合 PIL 的文档要求。
matplotlib.image.imread 的代码在这里:matplotlib/image.py at master · matplotlib/matplotlib · GitHubgithub.com
matplotlib 的原生 PNG 读取和写入,是用 C 实现的,代码在这里:matplotlib/_png.cpp at master · matplotlib/matplotlib · GitHubgithub.com
matplotlib 是先用 pil 的 open 打开图像,如果格式是 png,就用原生方法打开。相关代码如下:
handlers = {'png': _png.read_png, }
if format is None:
if cbook.is_string_like(fname):
parsed = urlparse(fname)
# If the string is a URL, assume png
if len(parsed.scheme) > 1:
ext = 'png'
else:
basename, ext = os.path.splitext(fname)
ext = ext.lower()[1:]
elif hasattr(fname, 'name'):
basename, ext = os.path.splitext(fname.name)
ext = ext.lower()[1:]
else:
ext = 'png'
else:
ext = format
if ext not in handlers:
im = pilread(fname)
if im is None:
raise ValueError('Only know how to handle extensions:%s; '
'with Pillow installed matplotlib can handle '
'more images' % list(six.iterkeys(handlers)))
return im
声明的处理器只有 png。如果是 png 文件,调用 _png.read_png。如果不是 png 直接使用 pilread(就是用 pil 的 Image.open 然后 pil_to_array)。
matplotlib 的源码确实比较复杂,一大部分主体是用 C 写的,改动很激进,功能更新猛烈。
20180410 更新:matplotlib.image.imread() 是原生的。改名版有 matplotlib.pyplot.imread(),车祸现场见:https://github.com/matplotlib/matplotlib/blob/dec87a31379c617704fce7225bfd1ad0dd799141/lib/matplotlib/pyplot.py#L2209github.com
from matplotlib.image import imread as _imread
...
@docstring.copy_dedent(_imread)
def imread(fname, format=None):
return _imread(fname, format)
改名版还有 matplotlib.pylab.imread,代码见:https://github.com/matplotlib/matplotlib/blob/438aa08df1037f059b4915b9a28871a90ae89976/lib/matplotlib/pylab.py#L246github.com
from matplotlib.pyplot import *
小结
从源码看,绝大多数常用代码库其实都还是用的 PIL。原因容易理解,PIL 是纯 Python 实现的,而且经过了优化,性能应该还不错。除了 PIL 之外,常用的就是 OpenCV 和 Qt。OpenCV 和 Qt 是 C/C++ 实现的,可能速度会快一些,但具体要测试才知道。稍后会在 GitHub 上开一个对比测试的 Repo 再测试一下性能。
scikit-images 的插件机制很灵活有趣,尤其是它提供了其他几种图像读取的实现。
matplotlib 代码稍显乱一点,但更证明了其功能迭代速度快,开发激进。用 matplotlib 尽量多用PNG 以便利用原生的 PNG 支持
补充
补充一些读代码时遇到的一些其他的图像读取方法。
7. PyQt4.QtGui.QImage.load(filename)
8. freeimage
scikit-image 是使用 ctype 调用 freeimage 的动态链接库,来调用 Freeimage_Load()。代码在此:freeimage/FreeImage.h at master · imazen/freeimage · GitHubgithub.com
9. imread
其在 PyPi 上的主页:Python Package Indexpypi.python.org
代码在此:imread/imread.py at master · luispedro/imread · GitHubgithub.com
python imread函数_Python的各种imread函数在实现方式和读取速度上有何区别?相关推荐
- python数字类型转换函数_Python的数据类型转换函数
玩蛇网这篇文章给大家介绍关于,Python数据类型的转换函数. Python提供了一些可以把某个值从一种数据类型,转换成为另一种数据类型的内置函数和方法.int函数可以将任何可以转换为整型的值转换为整 ...
- python hist函数_Python主要数据探索函数
Python中用于数据探索的库主要是pandas(数据分析)和 Matplotlib(数据可视化),其中pandas提供了大量的与数据库探索相关的函数,这些数据探索函数壳大致分为统计特征函数与统计绘图 ...
- python阶乘匿名函数_python的高阶函数与匿名函数
一.高阶函数的定义 高阶函数:就是把函数当成参数传递的一种函数,例如: defadd(x,y,f):return f(x)+f(y)print(add(-8,11,abs) 结果:19 解释: 1.调 ...
- python中itemgetter函数_Python中的sorted函数以及operator.itemgetter函数
operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号(即需要获取的数据在对象中的序号),下面看例子. a = [1,2,3] >>> b=op ...
- python日期函数_python 时间及日期函数
本人最近新学python ,用到关于时间和日期的函数,经过一番研究,从网上查找资料,经过测试,总结了一下相关的方法. import time import datetime '''时间转化为时间戳: ...
- python拷贝文件函数_Python Set集合,函数,深入拷贝,浅入拷贝,文件处理
1.Set基本数据类型 a.set集合,是一个无序且不重复的元素集合 classset(object):"""set() -> new empty set obje ...
- python中range 函数_Python中的range函数
本篇介绍range函数的特点及如何灵活运用. 工具/原料 Python3.7.5 Windows7环境 方法/步骤 1 查看range函数的帮助信息, range(stop) range(start, ...
- 什么是python函数_Python之什么是函数
Python内置了很多有用的函数,我们可以直接调用. 要调用一个函数,需要知道函数的名称和参数,比如求绝对值的函数 abs,它接收一个参数. 可以直接从Python的官方网站查看文档: http:// ...
- python getattr函数_Python中的getattr()函数详解
在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么.它知道什么以及它能做什么.自省向程序员提供了极大的灵活性和控制力. 自省(introspection),在计算机编程领域里,是指在运行时来 ...
最新文章
- 每日一皮:当产品经理试图让程序员冷静下来的时候...
- iphonex如何关机_iphonex常用手势操作有哪些 iphonex常用手势操作介绍【详解】
- gettype拿不到值_拼多多场景实操——这样实操场景推广有效拿高投产【下篇】...
- Java命令行界面(第10部分):picocli
- MSSQL · 最佳实践 · 利用文件组实现冷热数据隔离备份方案
- aop框架 php,xaop: 支持三种模式的AOP框架,弥补PHPer的不足,并且自带了文档的解析类库,可以一并使用,性能极好,欢迎 STAR 与 FORK。...
- html背景动起来,CSS+HTML 循环滚动背景效果
- 华为可以升级鸿蒙的机型,首批升级鸿蒙机型提前泄露,华为这保密措施需要加强...
- Linux Install telnet
- Python列表和字典的本质和区别
- 警惕AI军事间谍!找出导弹基地人类用2.5天,AI只要42分钟
- OC字符串相加,结果按照字符串形式输出
- Java实战之管家婆记账系统(24)——项目总结
- 全网目前最全python例子(附源码)
- Word文档插入没有可用的联机内容
- sql2000个人版semobj.rll有病毒
- 中国农业大学计算机考研参考书目,中国农业大学(专业学位)计算机技术考研参考书目...
- 2022年度猫狗粮销售数据:十大热门品牌排行榜,哪些品牌入围?
- 黑马程序员--typedef关键字和结构体 枚举类型
- hive3编译 on tez+tez-ui配置和遇到的兼容问题与踩坑记录
热门文章
- 02 AP AUTOSAR 与 面向服务的架构SOA
- 中国首架共享公务专机“天九一号”在海口实现首飞
- unity使用AVPRO插件播放大分辨率视频
- egg.js redis缓存的简单简单应用(存储和获取)
- 函数C语言基础代码总结
- java毕业设计企业产品在线展示销售平台源码+lw文档+mybatis+系统+mysql数据库+调试
- C/C++三种函数入参方法
- 大数据课程——课后练习3
- interface与abstract类的区别
- H3C 路由器配置单臂路由实现不同vlan之间相互通信