Seite 1 von 1

pil pixelversatz crop paste

Verfasst: Dienstag 25. Oktober 2011, 00:52
von kirby
Hallo zusammen,

ich habe eine PIL-Funktion geschrieben die aus einem Bild verschieden große Stücke ausschneidet, diese dann vertauscht und wieder einfügt.
Das ganze wird mit Hilfe der random Funktionen bewerkstelligt. Die Stücke sind in der Breite identisch, und gehen über die gesamte Bildbreite. Die Höhe wird via random bestimmt. Auch die Anzahl der Stücke ist variabel. Das Script funktioniert ganz gut, bis auf die Tatsache das ich immer wieder Pixelversatz zwischen meinen Stücken habe. Will heißen das zwischen den Stücken immer wieder 1 Pixel platz ist obwohl sie aneinader liegen sollen. Hat jemand eine Idee woran es liegen könnte? Bzw. vielleicht hat jemand eine Idee wie ich das ganze schöner lösen könnte?

Code: Alles auswählen

def rand_crop_shuffle(im):
    size = im.size
    array = []
    height = 0
    array2 = []
    dict = []
    im_list = []
    
    paste = []
    while True:
        array.append(height)
        rand_height = random.randint(0,size[1]-1)
        
        height = height + rand_height
        # array2.append(rand_height - 1)
        
        
        if(height >= size[1]):
            array2.append((size[1] - (height - rand_height)) + 1)
            break;
        else:
            array2.append(rand_height)    

    
    
    for i in range(len(array)):
        if(i < len(array)-1):
            end_x = array[i+1]-1
        else:
            end_x = size[1]
            
        dict.append([0,array[i],size[0],end_x])
        
        
    for j in range(len(dict)):
        
        im_list.append([array2[j],im.crop(dict[j])])
        # print dict[j]
        print(array)
        # im33.paste(im.crop(dict[j]), dict[j])

    im33 = Image.new(im.mode,size)
    
    paste_height = -1
    paste_height_end = im_list[0][0]

    random.shuffle(im_list)
    
    for k in range(len(im_list)):
        
        paste_height_end = paste_height + im_list[k][0]
        box2 = [0,paste_height + 1,size[0],paste_height_end]
        paste.append(box2)
        im33.paste(im_list[k][1], box2)
        paste_height = paste_height_end
        
    return im33

im_result = rand_crop_shuffle(im2)
im_result.save("result22.jpg", "JPEG",quality=100)

Re: pil pixelversatz crop paste

Verfasst: Dienstag 25. Oktober 2011, 08:29
von BlackJack
@kirby: Schöner wäre es sicherlich kürzer. Und mit weniger lokalen Namen. Und die sollten vielleicht nicht wie eingebaute Datentypen heissen oder so komische Namen wie `im33` tragen. Oder noch schlimmer an den Namen `dict` eine *Liste* zu binden. Wer soll denn solche Programme noch verstehen? Namen sollten dem Leser die bedeutung des Objektes für das Programm vermitteln und nicht so nichtssagend, durchnummeriert, oder sogar total irreführend sein.

``for i in range(len(indexable))`` ist unpythonisch, vor allem wenn man die Laufvariable dann nur als Index verwendet. Über die Elemente von solchen Objekten kann man auch *direkt* iterieren. Wenn man *zusätzlich* einen Index benötigt, gibt es die `enumerate()`-Funktion.

Hinter dem ``break`` in der ersten Schleife steht ein unnötiges Semikolon. Das zusammen mit den Indexschleifen und Klammern um ``if``-Bedingungen deutet darauf hin, dass Du versuchst in einer anderen Programmiersprache zu denken. Auch das vorbelegen von lokalen Namen am Anfang der Funktion sieht so ein bisschen nach einem „Deklarationsversuch“ aus.

Zusammengehörige Information sollte man nicht auf verschiedene Datenstrukturen verteilen. Wenn ich das richtig sehe werden in `array` zufällige Startzeilen von einem Ausschnitt und in `array2` die dazugehörigen Höhe gespeichert. Da sollte man besser eine Liste erstellen, die Elemente mit beiden Informationen enthält.

Letztendlich ist das Ganze viel zu lang und umständlich mit viel zu komplexen Zwischenergebnissen formuliert. Was man doch eigentlich nur haben möchte ist: 1. Bestimme die Positionen der Streifen, 2. mische diese, und 3. kopiere Streifen aus Eingabebild in Ergebnisbild. Für 1. und 3. benötigt man eine Schleife, für die Streifen eine Liste mit den Informationen. Alles andere macht es nur komplizierter als es sein müsste.

(Nur kurz angetestet):

Code: Alles auswählen

import random
from PIL import Image


def random_stripe_shuffle(image):
    image_width, image_height = image.size
    # 
    # Stripes consists of pairs describing start and height of the stripe.
    # 
    stripes = list()
    line = 0
    while line < image_height:
        random_height = random.randrange(0, image_height)
        next_line = line + random_height
        if next_line >= image_height:
            random_height = image_height - line
        stripes.append((line, random_height))
        line = next_line

    random.shuffle(stripes)
    
    result = Image.new(image.mode, image.size)
    paste_line = 0
    for source_line, height in stripes:
        result.paste(
            image.crop((0, source_line, image_width, source_line + height)),
            (0, paste_line)
        )
        paste_line += height

    return result

Re: pil pixelversatz crop paste

Verfasst: Mittwoch 26. Oktober 2011, 22:01
von kirby
Hi BlackJack,

zuerst einmal, vielen Dank für deine ausführliche Antwort. Deine Funktion läuft einfach nur perfekt durch und macht genau das was ich will nur ohne den Pixelversatz. Ich merke immer wieder, dass man sich nicht nur grundlegend vor dem Programmieren Gedanken machen sollte sondern sich auch davor nochmal anschauen sollte was eine Programmiersprache eigentlich so alles kann. Ich komme eher vom PHP und habe ein wenig Erfahrung in C++. Das mit den Namen ist natürlich Vollkommen richtig. Im Eifer des Gefechts achte ich auf sowas leider zu wenig. Ich muß auch gestehen das ich mir nie ein Buch zu Python durch gelesen habe und in Mathe immer sehr schlecht war. Naja. Ich werde mir deine Funktion nochmal in Ruhe genau ansehen und mir jedenfalls versuchen mir deine Effektivität anzueignen. Ich denke leider immer viel zu kompliziert.
Grüße
Kirby