如何在python / OpenCV中执行一个非常大的图像平均序列?

时间:2014-11-18 17:47:43

标签: python performance image-processing numpy out-of-memory

我正在处理30,000 x 30,000像素的TIFF图像,并希望一次平均11张图像。

如果可能的话,我更愿意在python中使用它,并且想知道最好的方法是什么?

我应该使用OpenCV还是仅使用numpy完成?

平均每个RGBA通道是否会独立提高性能?

或者我应该将图像分成较小的图像并单独处理它们,然后将生成的碎片拼接在一起?

直接使用openCV这样会导致内存错误:

im0 = cv2.imread( '5014.tif' )
im1 = cv2.imread( '5114.tif' )
im2 = cv2.imread( '5214.tif' )
im3 = cv2.imread( '5314.tif' )
im4 = cv2.imread( '5414.tif' )
cv2.imwrite( 'avg.tif', .01*im0 -.002*im1 -.002*im2 -.002*im3 -.002*im4 )

3 个答案:

答案 0 :(得分:3)

libvips是用于大图像的图像处理系统。它可以流式传输图像,而不是单独执行加载/处理/保存步骤,因此您可以使用比计算机内存量大得多的图像。它有一个方便的high-level python binding。这类任务应该是quicker than opencv

你可以用Python解决你的问题:

#!/usr/bin/python

import sys
from gi.repository import Vips

if len(sys.argv) < 3:
    print("usage: %s output-file in1 in2 ..." % sys.argv[0])
    sys.exit(1)

input_names = sys.argv[2:]
n_images = len(input_names)
outfile = sys.argv[1]

sum = 0
for filename in input_names:
    new_image = Vips.Image.new_from_file(filename, access =
                                         Vips.Access.SEQUENTIAL_UNBUFFERED)
    sum += new_image

avg = sum / n_images

# avg will be a float image, cast back to 8-bit for write, or we'll 
# get a float tiff
avg.cast(Vips.BandFormat.UCHAR).write_to_file(outfile)

像这样跑:

$ time ./avg.py x.tif ~/pics/wtc*.tif
memory: high-water mark 38.50 MB
real    0m5.759s
user    0m2.584s
sys 0m0.457s

在具有机械硬盘的机器上平均有四万个10,000 x 10,000 RGB图像,所以我猜你的数据集大约需要两分钟。内存使用量应在100mb左右。

答案 1 :(得分:2)

要改善哪些表现?

  1. SMALLER 静态内存占用 - 由于处理执行任何复杂的计算,只需将处理方案更改为从30GB静态RAM中获取占地面积约为5GB。 (代码示例以这种方式运行,迭代11个文件的序列)

  2. aListOfFNAMEs = [ ''5014.tif', ...                      ] # SETUP: FNAMEs
    aListOfCOEFFs = [ .01, -.002, -.002, -.002, -.002, .... ] #        COEFFs till the 11-th
    
    anInputIMG    = cv2.imread( aListOfFNAMEs[0] )            # LOAD
    anAveragedIMG = numpy.zeros( anInputIMG.shape )           # ensure .copy, not view
    
    anAveragedIMG += aListOfCOEFFs[0]*anInputIMG              # process the 1st LOAD-ed
    
    for aPtr in range( 1, len(aListOfCOEFFs ) ):              # iterate, process the rest
        anInputIMG     = cv2.imread( aListOfFNAMEs[aPtr] )    #          re-use MEM on LOAD(s)
        anAveragedIMG += aListOfCOEFFs[aPtr] * anInputIMG     #          process <next>
    
    cv2.imwrite( "avg.TIF", anAveragedIMG )                   # SAVE
    del anInputIMG                                            # release for GC
    del anAveragedIMG                                         # release for GC, DONE.
    

    1. 更快矢量化矩阵运算 - 由于处理允许numpy / openCV矢量化矩阵运算,RGB-colorplane分离为独立处理提高速度,恰恰相反。 (以上代码以这种方式运行)

    2. 最快基于GPU的阻止操作 - 尽管可能,会介绍您的项目,以便花费大量时间安排GPU设备/ HOST设备数据传输,以便每个块移动的数据少于GPU-DRAM所允许的大小。请求的计算具有如此低的数学/计算密度,这使得这些开销无法进入基于GPU的模式。

答案 2 :(得分:0)

您的“堆叠”具有“形状”(30000, 30000, 4, 11)。我不担心以任何方式手动循环这两个维度 - 我会担心你遇到的内存不足。

我不知道OpenCV语法,但是如果您可以在没有内存问题的情况下读取一个图像,请执行以下操作:

image_filenames = ['5014.tif', '5114.tif', ...]
N = float(len(image_filenames))

output = # empty array of image dimensions

for image_filename in image_filenames:
    # read in this image
    # add image / N to output

# save the output