【发布时间】:2015-11-11 19:56:52
【问题描述】:
我正在编写一个 Python(3.4.3) 程序,该程序在 Ubuntu 14.04 LTS 上使用 VIPS(8.1.1) 使用多个线程读取许多小图块并将它们组合成一个大图像。
在一个非常简单的测试中:
from concurrent.futures import ThreadPoolExecutor
from multiprocessing import Lock
from gi.repository import Vips
canvas = Vips.Image.black(8000,1000,bands=3)
def do_work(x):
img = Vips.Image.new_from_file('part.tif') # RGB tiff image
with lock:
canvas = canvas.insert(img, x*1000, 0)
with ThreadPoolExecutor(max_workers=8) as executor:
for x in range(8):
executor.submit(do_work, x)
canvas.write_to_file('complete.tif')
我得到正确的结果。在我的完整程序中,每个线程的工作涉及从源文件读取二进制文件,将它们转换为 tiff 格式,读取图像数据并插入到画布中。它似乎有效,但是当我尝试检查结果时,我遇到了麻烦。由于图像非常大(~50000*100000 像素),我无法将整个图像保存在一个文件中,所以我尝试了
canvas = canvas.resize(.5)
canvas.write_to_file('test.jpg')
这需要很长时间,并且生成的 jpeg 只有黑色像素。如果我确实调整了 3 次,程序就会被杀死。我也试过了
canvas.extract_area(20000,40000,2000,2000).write_to_file('test.tif')
这会导致错误消息segmentation fault(core dumped),但它确实保存了图像。里面有图片内容,但是好像放错地方了。
我想知道问题可能是什么?
以下是完整程序的代码。使用 OpenCV + sharedmem 也实现了相同的逻辑(sharedmem 处理了多处理部分)并且它没有问题地工作。
import os
import subprocess
import pickle
from multiprocessing import Lock
from concurrent.futures import ThreadPoolExecutor
import threading
import numpy as np
from gi.repository import Vips
lock = Lock()
def read_image(x):
with open(file_name, 'rb') as fin:
fin.seek(sublist[x]['dataStartPos'])
temp_array = np.fromfile(fin, dtype='int8', count=sublist[x]['dataSize'])
name_base = os.path.join(rd_path, threading.current_thread().name + 'tempimg')
with open(name_base + '.jxr', 'wb') as fout:
temp_array.tofile(fout)
subprocess.call(['./JxrDecApp', '-i', name_base + '.jxr', '-o', name_base + '.tif'])
temp_img = Vips.Image.new_from_file(name_base + '.tif')
with lock:
global canvas
canvas = canvas.insert(temp_img, sublist[x]['XStart'], sublist[x]['YStart'])
def assemble_all(filename, ramdisk_path, scene):
global canvas, sublist, file_name, rd_path, tilesize_x, tilesize_y
file_name = filename
rd_path = ramdisk_path
file_info = fetch_pickle(filename) # A custom function
# this info includes where to begin reading image data, image size and coordinates
tilesize_x = file_info['sBlockList_P0'][0]['XSize']
tilesize_y = file_info['sBlockList_P0'][0]['YSize']
sublist = [item for item in file_info['sBlockList_P0'] if item['SStart'] == scene]
max_x = max([item['XStart'] for item in file_info['sBlockList_P0']])
max_y = max([item['YStart'] for item in file_info['sBlockList_P0']])
canvas = Vips.Image.black((max_x+tilesize_x), (max_y+tilesize_y), bands=3)
with ThreadPoolExecutor(max_workers=4) as executor:
for x in range(len(sublist)):
executor.submit(read_image, x)
return canvas
上面的模块(作为mcv导入)在驱动脚本中被调用:
canvas = mcv.assemble_all(filename, ramdisk_path, 0)
为了检查内容,我使用了
canvas.extract_area(25000, 40000, 2000, 2000).write_to_file('test_vips1.jpg')
【问题讨论】:
-
我想到了另一个可能的问题:vips 使用递归算法来遍历管道并计算出接下来要计算的位。如果您的管道非常长并且您平台上的 C 堆栈相当小,您可能会遇到 C 堆栈溢出。这可能是问题吗?我会编辑您的问题以包含一个失败的完整示例程序,以及您的平台和 vips 版本的描述。您也可以在 vips 跟踪器上打开一个问题,这是一个更好的调试位置:github.com/jcupitt/libvips/issues
-
感谢您的评论!我将不得不阅读 C 堆栈溢出。我不太确定这意味着什么......我在这里包含了完整的程序。要读取的文件包含以 .jxr 格式保存的约 5000 个小图块。
标签: python multithreading image-processing vips