在使用 opencv 构建计算机视觉程序的时候,常会使用 matplotlib 来可视化中间的结果。因为直接为每一个中间结果进行一次单独的输出并不现实,因为如果窗口积累多了,关起来非常麻烦,最好的还是使用子图的形式,每个输出作为一个子图。
创建子图 子图索引的坑实际 *** 作中,这里会涉及到对于子图的索引。matplotlib 本身对子图的索引是按照行列来区分的。当然,这里有个坑,那就是如果使用一行或者一列,那就应该使用一维索引就行,而若涉及到多行多列,那就是二维索引了。
fig, axes = plt.subplots(nrows=1, ncols=1) print(type(axes), axes) fig, axes = plt.subplots(nrows=2, ncols=1) print(type(axes), axes.shape) fig, axes = plt.subplots(nrows=1, ncols=2) print(type(axes), axes.shape) fig, axes = plt.subplots(nrows=2, ncols=2) print(type(axes), axes.shape) """更方便的形式——迭代器AxesSubplot(0.125,0.11;0.775x0.77) (2,) (2,) (2, 2) """
如果代码流程本身是确定的,那么直接使用固定递增的序号来索引子图自然是最直接和直观的,但是如果代码前后顺序随时可能会调整或者中间可能会插入额外的 *** 作和可视化的时候,就不太方便了。这个时候,其实最适合使用迭代器来处理。每次按照顺序“d出”一个对象,并不需要指定索引。
考虑到 fig, axes = plt.subplots(...) 返回的 axes 是一个 ndarray 对象,我们直接将其展平成一维后使用内建方法 iter() 构建迭代器就可以很好的应对这个问题。直接对构建的迭代器对象使用 next() 函数就可以获得一个新的 axis 对象,且同时可以保证前后的 axis 对象对应的子图序号是按照行主序与整体子图一一对应的。由此可以得到以下代码:
axis = next(axes) axis.set_title(title) axis.imshow(image, cmap="gray", vmin=0, vmax=255)
这里要注意 cmap 的设定,因为 matplotlib 默认的 cmap 并不是灰度图的形式所以为了正常展示灰度图,我们需要重新设定其为 gray。
更简洁的形式——包装成独立函数甚至我们可以进一步简化调用的方式,将其包装成一个函数。由于其中需要用到一个共享的 axes,这里可以使用全局变量或者参数的形式进行传递。
python 中仅支持共享传参(指函数的各个形式参数获得实参中各个引用的副本,也就是说,函数内部的形参是实参的别名)。对于这里传入的迭代器,每次 next 都是在修改同一个对象的内部状态,也可以将迭代器看作是一个可变对象:
def imshow_on_axis(image, title, axes): axis = next(axes) axis.set_title(title) axis.imshow(image, cmap="gray", vmin=0, vmax=255)其他参考
关于 python 的可变对象与不可变对象可以简单看看下面这篇文章。虽然细节可能有所欠缺,但是胜在介绍的比较丰富:
python 可变对象与不可变对象 - Dwzb 的文章 - 知乎 https://zhuanlan.zhihu.com/p/34395671
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)