6

Ich spielte mit PIL und Transformationsmatrizen herum, um zu verstehen, was hinter der einfachen 2D-Bildbearbeitung steckt.Gedrehtes Bild sieht aus, als ob es Pixel fehlen

In meinem Versuch, ein Bild als „low level“ wie möglich zu drehen (das heißt, keine rotate(degrees) Funktion verwenden, aber das tut Mathe) habe ich beschlossen, eine Drehung im Uhrzeigersinn Matrix jedes Pixel des Bildes zu drehen, mit:

enter image description here

Die Drehung ging gut, aber das Bild sieht jetzt aus, als ob es einige Pixel fehlt.

Originalbild auf einem 435x353 schwarzen Hintergrund gemalt:

enter image description here

Rotated 45 ° im Uhrzeigersinn und um 300 Pixel nach rechts verschoben:

enter image description here

Seltsamer, das Problem tritt nicht auf, wenn das Bild um 90 ° im Uhrzeigersinn gedreht wird (und um 400 px nach rechts verschoben wird):

enter image description here

Was könnte das verursachen? Die Verwendung von Image.Image.rotate funktioniert gut, also denke ich, dass das Problem in meinem Code liegt. Es ist erwähnenswert, dass das Originalbild einen transparenten Hintergrund hat, der beim Hochladen in die Komprimierung verloren ging. Allerdings habe ich die gleiche Operation für ein JPEG-Bild (nicht transparent) gemacht und das Ergebnis war das gleiche.

-Code verwendet, um die Drehung zu tun:

import Image, ImageDraw 
from scipy import misc 
import math 

WHITE = (255,255,255) 
BLACK = (0,0,0) 
W, H = 435, 353 
im = Image.new('RGBA', (W, H), BLACK) 
draw = ImageDraw.Draw(im) 
bitmap = misc.imread('Image.png') 

def affine_t(x, y, a, b, c, d, e, f): 
    """Returns ((a, b), (c, d))*((x), (y)) + ((e), (f)).""" 
    return a*x + b*y + e, c*x + d*y + f 

def crotate(x, y, r): 
    """Rotate (x, y) clockwise by r radians.""" 
    # And move 300 px to the right for this example 
    return affine_t(
     x, y, math.cos(-r), math.sin(-r), -math.sin(-r), math.cos(-r), 300, 0 
    ) 

x, y = 0, 0 
angle = math.pi/4 
for row in bitmap: 
    for pt in row: 
     draw.point([crotate(x, y, angle),],fill=tuple(pt)) 
     x+= 1 
    x = 0 
    y += 1 

im.save('out.png') 
+1

Wenn Sie hart in Pillow tauchen, können Sie sehen, wie es es macht (meistens in C für Geschwindigkeit; ein mittelgroßes Bild ist leicht ein Millionen-Byte-Array) Hier ist das [generische] (https://github.com/ python-imaging/Pillow/blob/c74738a964e56cb42f08ac35da081ec6e4c8ce84/libImaging/Geometry.C# L585) und [Affine Transformation] (https://github.com/python-imaging/Pillow/blob/c74738a964e56cb42f08ac35da081ec6e4c8ce84/libImaging/Geometry.c#L777) (angeblich schneller, ich weiß nicht die Mathematik) funktioniert. –

+0

+1 für die Verwendung von "orient" watch – roippi

+1

Sie können die Warping-Funktionalität in skimage nützlich für das Experimentieren finden: http://scikit-image.org/docs/dev/auto_examples/applications/plot_geometric.html#example-applications-plot -geometric-py Die API von '' skimage.transform'' ist hier dokumentiert: http://scikit-image.org/docs/0.9.x/api/skimage.transform.html –

Antwort

9

Für jedes Zielpixel müssen Sie die Quellpixel, aber nicht die umgekehrt berechnen. Aufgrund von Rundungen haben Sie mehrere Quellpixel im selben Zielpixel abgebildet. Deshalb können Sie keine gute 45 ° -Drehung ohne Interpolation erreichen. Mein Vorschlag ist eigentlich eine Interpolation der nächsten Nachbarn.

+0

[Bilineare Interpolation] (http://en.wikipedia.org/wiki/Bilinear_interpolation) zwischen entsprechenden Quellpixeln jedes invers transformierten Zielpixels würde besser aussehende Ergebnisse liefern, als einfach den nächsten Nachbarn zu verwenden. Dies wird im Wikipedia-Artikel zu [Bildskalierung] (http://en.wikipedia.org/wiki/Resampling_%28bitmap%29) veranschaulicht. – martineau

+0

Noch besser zum Drehen und Skalieren ist der [RotSprite] (http://en.wikipedia.org/wiki/RotSprite#RotSprite) Algorithmus. – martineau

+0

RotSprite sieht ziemlich elegant und effizient aus, danke für den Link. – Mikhail

Verwandte Themen