2

我有顺序或 10^5 个二进制文件,我for用 numpy's 循环读取它们fromfile并用 pyplot's 绘制imshow。每个文件大约需要一分钟来读取和绘制。

有没有办法加快速度?

这是一些伪代码来解释我的情况:

#!/usr/bin/env python

import numpy as np
import matplotlib as mpl
mpl.use('Agg')

import matplotlib.pyplot as plt

nx = 1200 ; ny = 1200

fig, ax = plt.subplots()
ax.set_xlabel('x')
ax.set_ylabel('y')

for f in files:
  data = np.fromfile(open(f,'rb'), dtype=float32, count=nx*ny)
  data.resize(nx,ny)
  im = ax.imshow(data)
  fig.savefig(f+'.png', dpi=300, bbox_inches='tight')
  im.remove()

我发现最后一步很关键,这样内存就不会爆炸

4

2 回答 2

3

由于图像数量非常大并且您正在使用imshow,我建议采用不同的方法。

  1. 创建具有所需尺寸和空白图像的输出文件(任何颜色都可以,只要它与书脊颜色不同)
  2. 将图形保存到template.png
  3. template.png通过使用加载scipy.ndimage.imread
  4. 将图像数据加载到数组中
  5. 使用颜色图将数据转换为颜色
  6. 缩放图像以适合模板的像素尺寸 ( scipy.ndimage.zoom)
  7. 将像素数据复制到模板中
  8. 保存生成的图像scipy.ndimage.save
  9. 根据需要多次重复步骤 4 - 8

这将绕过很多渲染内容。一些评论:

  • 第 1 步可能需要花很多时间(尤其是抗锯齿可能需要注意,在刺的边缘有一个清晰的黑/白边框是有益的)
  • 如果第 4 步很慢(我不明白为什么),请尝试numpy.memmap
  • 如果可以的话,尝试使用可以通过简单的算术运算从数据中生成的颜色图(例如,灰度、带有伽马的灰度等),那么您可以加快第 5 步
  • 如果您可以处理数据未缩放的图像(即原始使用的区域imshow为 1200x1200),则可以摆脱缓慢的缩放操作(步骤 6);如果您可以按整数下采样,它也有帮助
  • 如果您需要在步骤 6 中重新采样图像,您还可以检查cv2(OpenCV) 模块中的函数,这可能比更通用的函数更快scipy.ndimage

性能方面,最慢的操作是 5、6 和 9。我希望该函数每秒能够处理十个数组。在此之上,磁盘 I/O 将开始成为一个限制因素。如果处理步骤是限制因素,我将启动脚本的四个(假设有四个核心)副本,每个副本都可以访问不同的 2.5 x 10^4 图像集。对于 SSD 磁盘,这不会导致 I/O 寻道灾难。

不过,只有分析才能说明问题。

于 2014-08-22T07:14:06.823 回答
0

奇怪的是,重新启动后,我通常不采用的解决方案,每个文件的读取时间降低到 ~0.002 秒(平均),渲染时间是 ~0.02 秒。保存.png文件大约需要 2.6 秒,所以总而言之,每帧大约需要 2.7 秒。

我接受了@DrV 的建议,

...我将启动脚本的四个(假设有四个核心)副本,每个副本都可以访问不同的 2.5 x 10^4 图像集。对于 SSD 磁盘,这不会导致 I/O 寻道灾难。

将文件列表划分为 8 个子列表并运行我的脚本的 8 个实例。

@DrV 的评论

此外,如果文件不在 RAM 缓存中,则读取 5.7 MB 文件的 0.002 秒读取时间听起来并不现实,因为它表明磁盘读取速度为 2.8 GB/秒。(快速 SSD 可能仅达到 500 MB/s。)

让我对笔记本电脑(MacBookPro10,1)的读/写速度进行了基准测试。我使用以下代码生成了 1000 个具有 1200*1200 随机浮点数(4 字节)的文件,使得每个文件为 5.8 MB(1200*1200*4 = 5,760,000 字节),然后一个一个地读取它们,对过程进行计时。代码从终端运行,永远不会占用超过 50 MB 或内存(对于仅在内存中保存一个 5.8 MB 的数据数组来说,这是相当多的,不是吗?)。

编码:

#!/usr/bin/env ipython

import os
from time import time
import numpy as np

temp = 'temp'
if not os.path.exists(temp):
    os.makedirs(temp)
    print 'temp dir created'
os.chdir(temp)

nx = ny = 1200
nof = 1000
print '\n*** Writing random data to files ***\n'
t1 = time(); t2 = 0; t3 = 0
for i in range(nof):
    if not i%10:
        print str(i),
    tt = time()
    data = np.array(np.random.rand(nx*ny), dtype=np.float32)
    t2 += time()-tt
    fn = '%d.bin' %i
    tt = time()
    f = open(fn, 'wb')
    f.write(data)
    f.close
    t3 += time()-tt
print '\n*****************************'
print 'Total time: %f seconds' %(time()-t1)
print '%f seconds (on average) per random data production' %(t2/nof)
print '%f seconds (on average) per file write' %(t3/nof)

print '\n*** Reading random data from files ***\n'
t1 = time(); t3 = 0
for i,fn in enumerate(os.listdir('./')):
    if not i%10:
        print str(i),
    tt = time()
    f = open(fn, 'rb')
    data = np.fromfile(f)
    f.close
    t3 += time()-tt
print '\n*****************************'
print 'Total time: %f seconds' %(time()-t1)
print '%f seconds (on average) per file read' %(t3/(i+1))

# cleen up:
for f in os.listdir('./'):
    os.remove(f)
os.chdir('../')
os.rmdir(temp)

结果:

temp dir created

*** Writing random data to files ***

0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 240 250 260 270 280 290 300 310 320 330 340 350 360 370 380 390 400 410 420 430 440 450 460 470 480 490 500 510 520 530 540 550 560 570 580 590 600 610 620 630 640 650 660 670 680 690 700 710 720 730 740 750 760 770 780 790 800 810 820 830 840 850 860 870 880 890 900 910 920 930 940 950 960 970 980 990 
*****************************
Total time: 25.569716 seconds
0.017786 seconds (on average) per random data production
0.007727 seconds (on average) per file write

*** Reading random data from files ***

0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 240 250 260 270 280 290 300 310 320 330 340 350 360 370 380 390 400 410 420 430 440 450 460 470 480 490 500 510 520 530 540 550 560 570 580 590 600 610 620 630 640 650 660 670 680 690 700 710 720 730 740 750 760 770 780 790 800 810 820 830 840 850 860 870 880 890 900 910 920 930 940 950 960 970 980 990 
*****************************
Total time: 2.596179 seconds
0.002568 seconds (on average) per file read
于 2014-08-23T12:55:56.067 回答