Сравнение областей пикселей

#gimp #python-fu

#gimp #python-fu

Вопрос:

Я пытаюсь написать скрипт на python для GIMP, целью которого является нарезать изображение на набор листов (идентифицировать каждую уникальную плитку размером 16×16 на изображении).

До сих пор я могу читать фрагменты (фактически область размером 16×16 пикселей) и записывать их куда-нибудь. Но все мои попытки сравнить плитки не увенчались успехом.

Я что-то пропустил? Мой сценарий выглядит следующим образом:

 #!/usr/bin/env python

from gimpfu import *

    # compare 2 tiles,
    # return 1 if identical, false otherwise
def tileCompare(tile1, tile2):
    if(tile1 == tile2):
        return 1
    return 0

     # return tile at (x, y) coordinates
def readTile(layer, x, y):
    pr = layer.get_pixel_rgn(x,y,16,16)
    return pr[x:x 16, y:y 16]

    # write tile at (x, y) coordinates on given layer
def writeTile(layer, x, y, tile):    
    pr = layer.get_pixel_rgn(x,y,16,16)
    pr[x:x 16, y:y 16] = tile

def TilesSlicer(sourceLayer, targetLayer):
        # Actual plug-in code will go here

        # iterate tiles (result in tileSource)
    for x in range(0, sourceLayer.width, 16):
        for y in range(0, sourceLayer.height, 16):
            tileSource = readTile(sourceLayer, x, y)
            found = 0
                # iterate tiles again (result in tileIterator)
            for a in range(0, sourceLayer.width, 16):
                for b in range(0, sourceLayer.height, 16):
                    tileIterator = readTile(sourceLayer, x, y)
                        # compare tiles
                        # if identical and not yet found
                        # write it in the target layer
                    if (tileCompare(tileSource, tileIterator) == 1):
                        if(found == 0):
                            writeTile(tileIterator, a, b, tileSource)
                        found = 1

register(
    "TilesSlicer",
    "Tiles slicer",
    "Slice a picture into tiles",
    "Fabrice Lambert",
    "Fabrice Lambert",
    "April 2019",
    "Tiles slicer...",
    "RGB*",
    [
    (PF_DRAWABLE, "sourceLayer", "Source Layer: ", None),
    (PF_DRAWABLE, "targetLayer", "Target Layer: ", None),
    ],
    [],
    TilesSlicer,
        menu="<Image>/Filters/My Scripts")

main()
  

Спасибо за ваши предложения.

Комментарии:

1. Пожалуйста, уточните «мои попытки не увенчались успехом». Как вы можете определить, что они потерпели неудачу? Вы получили сообщение об ошибке? Если да, пожалуйста, добавьте его.

2. Считывание фрагмента в тех же координатах (другими словами: тот же фрагмент) и сравнение возвращают 0 (в то время как он должен возвращать 1), см. Функцию tileCompare ..

3. Обычно первым аргументом вашего плагина должно быть изображение. Если первые два аргумента являются изображением и «рисуемым», то предполагается, что они являются активным изображением и рисуемым (слоем, маской или каналом), и автоматически сгенерированное диалоговое окно параметров будет запрашивать только дополнительные аргументы, целевой слой в вашем случае. Но соглашение Gimp заключается в том, что активный слой является измененным, поэтому у вас должно быть изображение / Цель / источник. Если вы играете с плитками в Python, вы можете использовать Numpy, смотрите Здесь .

4. 1-й: это зависит от того, что вы ожидаете от него: нарезать все изображение? Нарезать один слой? Я выбрал 2-й вариант, поскольку у одного могут быть «рабочие слои», которые не должны быть нарезаны. 2-й: аргументы не являются проблемой.

Ответ №1:

Nvm,

Я обнаружил проблему:
tileIterator = readTile(исходный слой, a, b)
вместо:
tileIterator = readTile(исходный слой, x, y)

Ответ №2:

Хорошо,

После небольшой доработки сценарий выглядит следующим образом:
— Добавлены ширина и высота плиток для обработки любого размера плитки.
— Удален параметр целевого слоя, теперь скрипт создает его.
— Добавлено отображение в реальном времени для обратной связи с пользователем (к сожалению, индикатор выполнения не работает).
— Улучшена скорость.

 #!/usr/bin/env python

from gimpfu import *

    # compare 2 tiles,
    # return 1 if identical, 0 otherwise
def tileCompare(tile1, tile2):
    if(tile1 == tile2):
        return 1
    return 0

     # return tile at (x, y) coordinates
def readTile(layer, x, y, width, height):
    pr = layer.get_pixel_rgn(x, y, width, height)
    return pr[x:x width, y:y height]

    # write tile at (x, y) coordinates on given layer
def writeTile(layer, x, y, width, height, tile):    
    pr = layer.get_pixel_rgn(x, y, width, height)
    pr[x:x width, y:y height] = tile
    layer.update(x, y, width, height)
    gimp.displays_flush()

def TilesSlicer(sourceLayer, tileWidth, tileHeight):
        # Actual plug-in code will go here
    if((sourceLayer.width % tileWidth) != 0):
        gimp.message("The layer width is not multiple of "   str(tileWidth))
        gimp.quit()
    if((sourceLayer.height % tileWidth) != 0):
        gimp.message("The layer height is not multiple of "   str(tileHeight))
        gimp.quit()
    totalTiles = (sourceLayer.width / tileWidth) * (sourceLayer.height / tileHeight)
    tilesProcessed = 0

    gimp.progress_init("Processing...")
    gimp.progress_update(0.0)

    sourceImage = sourceLayer.image
    targetLayer = pdb.gimp_layer_new(sourceImage, sourceLayer.width, sourceLayer.height, sourceImage.base_type, "Target", 100.0, sourceLayer.mode)
    targetLayer.add_alpha()
    targetLayer.fill(TRANSPARENT_FILL)
    sourceImage.add_layer(targetLayer, 0)
        # iterate tiles (result in tileSource)
    for x in range(0, sourceLayer.width, tileWidth):
        for y in range(0, sourceLayer.height, tileHeight):
            tileSource = readTile(sourceLayer, x, y, tileWidth, tileHeight)
            found = 0
                # iterate tiles again (result in tileIterator)
            for a in range(0, sourceLayer.width, tileWidth):
                for b in range(0, sourceLayer.height, tileHeight):
                    tileIterator = readTile(sourceLayer, a, b, tileWidth, tileHeight)
                        # compare tiles
                        # if identical and not yet found
                        # write it in the target layer
                        # and abort iteration (for speed purpose)
                    if (tileCompare(tileSource, tileIterator) == 1):
                        if(found == 0):
                            writeTile(targetLayer, a, b, tileWidth, tileHeight, tileIterator)
                        found = 1
                        break
                if(found == 1):
                    break
            tilesProcessed = tilesProcessed   1
            gimp.progress_update(tilesProcessed / totalTiles)
            gimp.displays_flush()

register(
    "TilesSlicer",
    "Tiles slicer",
    "Slice a picture into tiles",
    "Fabrice Lambert",
    "Fabrice Lambert",
    "April 2019",
    "Tiles slicer...",
    "RGB*",
    [
    (PF_DRAWABLE, "sourceLayer", "Source Layer: ", None),
    (PF_INT8, "tileWidth", "Tile width: ", 16),
    (PF_INT8, "tileHeight", "Tile height: ", 16),
    ],
    [],
    TilesSlicer, 
        menu="<Image>/Filters/My Scripts")

main()
  

Вероятно, его можно улучшить лучше, и если у кого-то есть что-то, что связано с индикатором выполнения, дайте мне знать.
Я открыт для предложений.