我正在编写一个 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')