1

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 からモザイクを作成しようとしましたが、一時イメージへの書き込みに問題があります。

このモザイク プログラムを機能させるにはどうすればよいですか?

4

1 に答える 1