Я пытаюсь создать генератор мозаики изображений, используя pyvips. Таким образом, для данного изображения (далее называемого исходным) создайте новое, более крупное изображение, похожее на исходное, за исключением того, что каждый пиксель (или, что более реалистично, группы пикселей) заменен меньшими отдельными фрагментами изображения.
Меня нарисовали. к pyvips, потому что говорят, что он может обрабатывать огромные изображения и что он может обрабатывать изображения без необходимости полной загрузки их в память. Однако у меня возникла проблема с созданием пустой мозаики, чтобы затем заполнить ее изображениями фрагментов.
В приведенном ниже коде я пытаюсь соединить фрагменты вместе ряд за рядом, чтобы создать мозаику, но этот код, к сожалению, съедает мою оперативную память и всегда дает сбои.
import os
import pyvips
from os.path import join
from scipy.spatial import cKDTree
class Mosaic(object):
def __init__(self, dir_path, original_path, tree=None, averages=None):
self.dir_path = dir_path
self.original = original_path
self.tree = tree
if averages:
self.averages = averages
else:
self.averages = {}
def get_image(self, path):
return pyvips.Image.new_from_file(path, access="sequential")
def build_tree(self):
for root, dirs, files in os.walk(self.dir_path):
print('Loading images from', root, '...')
for file_name in files:
path = join(root, file_name)
try:
image = pyvips.Image.new_from_file(path)
self.averages[self.avg_rgb(image)] = path
except pyvips.error.Error:
print('File', path, 'not recognized as an image.')
self.tree = cKDTree(self.averages.keys())
print('Loaded', len(self.averages), 'images.')
def avg_rgb(self, image):
m = image.stats()
return tuple(m(4,i)[0] for i in range(1,4))
def get_tile_name(self, patch):
avg = self.avg_rgb(patch)
index = self.tree.query(avg)[1]
return self.averages[tuple(self.tree.data[index])]
def get_tile(self, x, y, step):
patch = self.get_image(self.original).crop(x, y, step, step)
patch_name = self.get_tile_name(patch)
return pyvips.Image.new_from_file(patch_name, access="sequential")
def make_mosaic(self, tile_num, tile_size, mosaic_path):
original = self.get_image(self.original)
mosaic = None
step = min(original.height, original.width) / tile_num
for y in range(0, original.height, step):
mosaic_row = None
print('Building row', y/step, '/', original.height/step)
for x in range(0, original.width, step):
tile = self.get_tile(x, y, step)
tile = tile.resize(float(tile_size) / float(min(tile.width, tile.height)))
tile = tile.crop(0, 0, tile_size, tile_size)
#mosaic.draw_image(tile, x, y)
mosaic_row = tile if not mosaic_row else mosaic_row.join(tile, "horizontal")
mosaic = mosaic_row if not mosaic else mosaic.join(mosaic_row, "vertical")
mosaic.write_to_file(mosaic_path)
Я также пытался создать мозаику, изменив размер исходного изображения, а затем используя draw_image, как показано ниже, но это также дает сбой.
mosaic = self.get_image(self.original).resize(tile_size)
mosaic.draw_image(tile, x, y)
Наконец, я попытался создать мозаику из файла new_temp_file, и у меня возникли проблемы с записью во временное изображение.
Как заставить работать эту мозаичную программу?
arrayjoin
: это операция libvips, которая может объединять огромное количество изображений за один шаг. Я присоединился к более чем 10 000 сразу без проблем. jcupitt.github.io/libvips/API/current/ - person jcupitt   schedule 18.12.2017