一看到题主的问题,其实就有个猜想,其实底层应该都是一样的,或者说没几个独立的实现吧?主要是关注开源软件一段时间之后,就会发现开源界其实挺缺人的,现有这些人也都挺懒的。挖坑的人多,填坑的人少。说是这活谁都可以参与,但其实真没多少人实际做。一个活有一个人干了,其他人一般就懒得再重复了。以下就是从源码来看这些开源库的具体实现。

1. PIL.Image.open

代码在这里:Pillow/Image.py at 3.1.x · python-pillow/Pillow · GitHub​github.com

open() 函数打开图像,但并不读入,直到有操作发生。

具体的读取操作是在 ImageFile.py 写的。大体流程是先检测文件类型,整块地读入文件内容,然后调用解码器解码,做了很多优化,效率应该还是很高的。

2. scipy.misc.imread

misc 的 __init__.py 在这里:scipy/__init__.py at v0.17.1 · scipy/scipy · GitHub​github.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 · GitHub​github.com

imread 调用 scipy.misc.pilutil.imread。从名字就能看出来其实调用的还是 Pillow。

根据 pilutil 代码:scipy/pilutil.py at v0.17.1 · scipy/scipy · GitHub​github.com

确实是调用 pil.image.open(),然后返回一个 fromimage()。

20180410 更新:scipy.ndimage.imread,其实调用的就是 scipy.misc.imread。我之前没写清楚。代码在这里:https://github.com/scipy/scipy/blob/80e76d43f0ada0a1964195cb6d13ae519feb07e8/scipy/ndimage/io.py#L8​github.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 · GitHub​github.com

(20180410 更新:该部分代码已修改,链接不可用了

是通过插件 plugin 来读入不同的文件,而且会试用几个不同的 plugins 来找到合适的。

使用 call_plugin 来调用,代码在这里:scikit-image/manage_plugins.py at master · scikit-image/scikit-image · GitHub​github.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-image​github.com

可以看到 pil 的 imread,是用 open 打开图像之后,再转换成 ndarray。

20180410 更新:skimage 的插件管理,代码改在了这里:https://github.com/scikit-image/scikit-image/blob/37ed59d2880fa96ff908608d7f723b98cd319c9b/skimage/io/manage_plugins.py#L46​github.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 · GitHub​github.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#L633​github.com

cvLoadImage 到 IplImage 和 cvLoadImageM 到 CvMat,其实也都是调用的 imread_(),详情见代码:https://github.com/opencv/opencv/blob/6d83a8038525cf64b0edd866ebbd94906eb5691d/modules/imgcodecs/src/loadsave.cpp#L966​github.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/opencv​github.com

6. matplotlib.image.imread

matplotlib 的文档里面说,matplotlib 原生只可以读取 PNG 文件,有 PIL 的时候,可以读取其他类型的文件。如果使用 URL 打开在线图像文件,需要符合 PIL 的文档要求。

matplotlib.image.imread 的代码在这里:matplotlib/image.py at master · matplotlib/matplotlib · GitHub​github.com

matplotlib 的原生 PNG 读取和写入,是用 C 实现的,代码在这里:matplotlib/_png.cpp at master · matplotlib/matplotlib · GitHub​github.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#L2209​github.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#L246​github.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 · GitHub​github.com

9. imread

其在 PyPi 上的主页:Python Package Index​pypi.python.org

代码在此:imread/imread.py at master · luispedro/imread · GitHub​github.com

python imread函数_Python的各种imread函数在实现方式和读取速度上有何区别?相关推荐

  1. python数字类型转换函数_Python的数据类型转换函数

    玩蛇网这篇文章给大家介绍关于,Python数据类型的转换函数. Python提供了一些可以把某个值从一种数据类型,转换成为另一种数据类型的内置函数和方法.int函数可以将任何可以转换为整型的值转换为整 ...

  2. python hist函数_Python主要数据探索函数

    Python中用于数据探索的库主要是pandas(数据分析)和 Matplotlib(数据可视化),其中pandas提供了大量的与数据库探索相关的函数,这些数据探索函数壳大致分为统计特征函数与统计绘图 ...

  3. python阶乘匿名函数_python的高阶函数与匿名函数

    一.高阶函数的定义 高阶函数:就是把函数当成参数传递的一种函数,例如: defadd(x,y,f):return f(x)+f(y)print(add(-8,11,abs) 结果:19 解释: 1.调 ...

  4. python中itemgetter函数_Python中的sorted函数以及operator.itemgetter函数

    operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号(即需要获取的数据在对象中的序号),下面看例子. a = [1,2,3] >>> b=op ...

  5. python日期函数_python 时间及日期函数

    本人最近新学python ,用到关于时间和日期的函数,经过一番研究,从网上查找资料,经过测试,总结了一下相关的方法. import time import datetime '''时间转化为时间戳: ...

  6. python拷贝文件函数_Python Set集合,函数,深入拷贝,浅入拷贝,文件处理

    1.Set基本数据类型 a.set集合,是一个无序且不重复的元素集合 classset(object):"""set() -> new empty set obje ...

  7. python中range 函数_Python中的range函数

    本篇介绍range函数的特点及如何灵活运用. 工具/原料 Python3.7.5 Windows7环境 方法/步骤 1 查看range函数的帮助信息, range(stop) range(start, ...

  8. 什么是python函数_Python之什么是函数

    Python内置了很多有用的函数,我们可以直接调用. 要调用一个函数,需要知道函数的名称和参数,比如求绝对值的函数 abs,它接收一个参数. 可以直接从Python的官方网站查看文档: http:// ...

  9. python getattr函数_Python中的getattr()函数详解

    在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么.它知道什么以及它能做什么.自省向程序员提供了极大的灵活性和控制力. 自省(introspection),在计算机编程领域里,是指在运行时来 ...

最新文章

  1. 每日一皮:当产品经理试图让程序员冷静下来的时候...
  2. iphonex如何关机_iphonex常用手势操作有哪些 iphonex常用手势操作介绍【详解】
  3. gettype拿不到值_拼多多场景实操——这样实操场景推广有效拿高投产【下篇】...
  4. Java命令行界面(第10部分):picocli
  5. MSSQL · 最佳实践 · 利用文件组实现冷热数据隔离备份方案
  6. aop框架 php,xaop: 支持三种模式的AOP框架,弥补PHPer的不足,并且自带了文档的解析类库,可以一并使用,性能极好,欢迎 STAR 与 FORK。...
  7. html背景动起来,CSS+HTML 循环滚动背景效果
  8. 华为可以升级鸿蒙的机型,首批升级鸿蒙机型提前泄露,华为这保密措施需要加强...
  9. Linux Install telnet
  10. Python列表和字典的本质和区别
  11. 警惕AI军事间谍!找出导弹基地人类用2.5天,AI只要42分钟
  12. OC字符串相加,结果按照字符串形式输出
  13. Java实战之管家婆记账系统(24)——项目总结
  14. 全网目前最全python例子(附源码)
  15. Word文档插入没有可用的联机内容
  16. sql2000个人版semobj.rll有病毒
  17. 中国农业大学计算机考研参考书目,中国农业大学(专业学位)计算机技术考研参考书目...
  18. 2022年度猫狗粮销售数据:十大热门品牌排行榜,哪些品牌入围?
  19. 黑马程序员--typedef关键字和结构体 枚举类型
  20. hive3编译 on tez+tez-ui配置和遇到的兼容问题与踩坑记录

热门文章

  1. 02 AP AUTOSAR 与 面向服务的架构SOA
  2. 中国首架共享公务专机“天九一号”在海口实现首飞
  3. unity使用AVPRO插件播放大分辨率视频
  4. egg.js redis缓存的简单简单应用(存储和获取)
  5. 函数C语言基础代码总结
  6. java毕业设计企业产品在线展示销售平台源码+lw文档+mybatis+系统+mysql数据库+调试
  7. C/C++三种函数入参方法
  8. 大数据课程——课后练习3
  9. interface与abstract类的区别
  10. H3C 路由器配置单臂路由实现不同vlan之间相互通信