【发布时间】:2017-12-17 05:12:50
【问题描述】:
我正在尝试使用 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 创建马赛克,但无法写入临时图像。
我怎样才能使这个马赛克程序工作?
【问题讨论】:
-
libvips 使用递归算法来计算接下来要计算的像素。这意味着如果您的图像管道变得很长,它可能会溢出 C 堆栈并导致崩溃。看看
arrayjoin:这是一个 libvips 操作,可以在一个步骤中将大量图像连接在一起。我一次加入了 10,000 多个,没有任何问题。 jcupitt.github.io/libvips/API/current/… -
这是个好主意,但是,我无法像在文档中那样工作。当我在图像上调用 arrayjoin 时,它不接受任何参数,并且似乎将每个波段分开,制作每个波段的灰度图像。即:我最终得到了 3 张黑白图像,它们连接在一起......
-
我会在接下来的几天里尝试为你制作一个示例程序。
-
谢谢!我的目标是为圣诞礼物制作一个巨大的马赛克!节日快乐
-
天哪 :( 我的回答可能为时已晚。无论如何,祝你快乐。
标签: python image image-processing vips