我正在尝试使用 pyvips 制作图像马赛克生成器。所以基本上,给定一个图像(以下称为原始图像)创建一个新的、更大的图像,它类似于原始图像,除了每个像素(或更实际的像素组)被更小的不同图像块替换。
我被 pyvips 所吸引,因为据说它可以处理巨大的图像,并且可以处理图像而无需将它们完全加载到内存中。但是,我在创建空白马赛克然后填充平铺图像时遇到问题。
在下面的代码中,我尝试将瓷砖逐行连接在一起以创建马赛克,但不幸的是,这段代码会耗尽我的 RAM 并且总是出现段错误。
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 创建马赛克,但无法写入临时图像。
我怎样才能使这个马赛克程序工作?