Skip to content

Trasformazione affine Python/PIL

Dopo aver cercato in vari repository e forum, abbiamo finalmente trovato la risposta che ora condividiamo con voi.

Soluzione:

OK! Ho lavorato per tutto il fine settimana per capire questo problema e credo di avere una risposta che mi soddisfa.
risposta che mi soddisfa. Grazie a tutti per i vostri commenti e suggerimenti!

Inizio guardando questo:

trasformazione affine in PIL python?

Se da un lato vedo che l'autore può effettuare trasformazioni di somiglianza arbitrarie, dall'altro
non spiega perché il mio codice non funzionava, né spiega il layout spaziale dell'immagine che dobbiamo trasformare, né fornisce un metodo di
dell'immagine da trasformare, né fornisce una soluzione algebrica lineare ai miei problemi.
soluzione algebrica lineare ai miei problemi.

Ma dal suo codice vedo che divide la parte della matrice di rotazione in
(a, b, d ed e) nella scala, il che mi è sembrato strano. Sono tornato a leggere
la documentazione del PIL che cito:

"im.transform(size, AFFINE, data, filter) => immagine

Applica una trasformazione affine all'immagine e inserisce il risultato in una nuova immagine
con la dimensione data.

I dati sono 6 tuple (a, b, c, d, e, f) che contengono le prime due righe di una matrice di trasformazione affine.
matrice di trasformazione affine. Per ogni pixel (x, y) nell'immagine di uscita, il nuovo valore
valore viene preso da una posizione (a x + b y + c, d x + e y + f) nell'immagine di ingresso, arrotondata al pixel più vicino.
immagine di ingresso, arrotondato al pixel più vicino.

Questa funzione può essere utilizzata per scalare, traslare, ruotare e tagliare l'immagine originale.
immagine originale".

quindi i parametri (a,b,c,d,e,f) sono una matrice di trasformazione ma quella che mappa
(x,y) nell'immagine di destinazione a (a x + b y + c, d x + e y + f) nell'immagine di origine.
immagine di partenza. Ma non i parametri di della matrice di trasformazione che si vuole applicare, ma
la sua inversa. Ovvero:

  • strano
  • diverso da quello di Matlab
  • ma ora, fortunatamente, da me pienamente compreso

Allego il mio codice:

import Image
import math
from numpy import matrix
from numpy import linalg

def rot_x(angle,ptx,pty):
    return math.cos(angle)*ptx + math.sin(angle)*pty

def rot_y(angle,ptx,pty):
    return -math.sin(angle)*ptx + math.cos(angle)*pty

angle = math.radians(45)
im = Image.open('test.jpg')
(x,y) = im.size
xextremes = [rot_x(angle,0,0),rot_x(angle,0,y-1),rot_x(angle,x-1,0),rot_x(angle,x-1,y-1)]
yextremes = [rot_y(angle,0,0),rot_y(angle,0,y-1),rot_y(angle,x-1,0),rot_y(angle,x-1,y-1)]
mnx = min(xextremes)
mxx = max(xextremes)
mny = min(yextremes)
mxy = max(yextremes)
print mnx,mny
T = matrix([[math.cos(angle),math.sin(angle),-mnx],[-math.sin(angle),math.cos(angle),-mny],[0,0,1]])
Tinv = linalg.inv(T);
print Tinv
Tinvtuple = (Tinv[0,0],Tinv[0,1], Tinv[0,2], Tinv[1,0],Tinv[1,1],Tinv[1,2])
print Tinvtuple
im = im.transform((int(round(mxx-mnx)),int(round((mxy-mny)))),Image.AFFINE,Tinvtuple,resample=Image.BILINEAR)
im.save('outputpython2.jpg')

e l'output di python:

Immettere la descrizione dell'immagine qui

Riporto la risposta a questa domanda in un riassunto finale:

PIL richiede l'inverso della trasformazione affine che si vuole applicare.

Volevo ampliare un po' le risposte di carlosdc e Ruediger Jungbeck, per presentare una soluzione più pratica in codice python con un po' di spiegazioni.

Innanzitutto, è assolutamente vero che PIL utilizza le trasformazioni affini inverse, come indicato nella risposta di carlosdc. Tuttavia, non c'è bisogno di usare l'algebra lineare per calcolare la trasformazione inversa dalla trasformazione originale; al contrario, può essere facilmente espressa direttamente. Per l'esempio utilizzerò il ridimensionamento e la rotazione di un'immagine rispetto al suo centro, come nel codice collegato alla risposta di Ruediger Jungbeck, ma è abbastanza semplice estenderlo per eseguire, ad esempio, anche il taglio.

Prima di affrontare il modo in cui esprimere la trasformazione affine inversa per scalare e ruotare, si consideri come trovare la trasformazione originale. Come accennato nella risposta di Ruediger Jungbeck, la trasformazione per l'operazione combinata di scalatura e rotazione si trova come composizione degli operatori fondamentali di scalare un'immagine rispetto all'origine e rotazione di un'immagine intorno all'origine.

Tuttavia, poiché vogliamo scalare e ruotare l'immagine attorno al suo centro e l'origine (0, 0) è definita da PIL come l'angolo superiore sinistro dell'immagine, dobbiamo prima traslare l'immagine in modo che il suo centro coincida con l'origine. Dopo aver applicato il ridimensionamento e la rotazione, occorre anche ritraslare l'immagine in modo che il nuovo centro dell'immagine (che potrebbe non essere lo stesso del vecchio centro dopo il ridimensionamento e la rotazione) finisca al centro della tela dell'immagine.

Quindi la trasformazione affine originale "standard" che cerchiamo sarà la composizione dei seguenti operatori fondamentali:

  1. Trova il centro corrente (C_X, C_Y) dell'immagine e trasla l'immagine di (-c_x, -c_y), in modo che il centro dell'immagine sia nell'origine (0, 0).

  2. Scalare l'immagine intorno all'origine di un fattore di scala (S_X, S_Y).

  3. Ruota l'immagine intorno all'origine di un certo angolo  theta.

  4. Trova il nuovo centro (T_X, T_Y) dell'immagine e trasla l'immagine di (T_X, T_Y) in modo che il nuovo centro si trovi al centro della tela dell'immagine.

Per trovare la trasformazione desiderata, dobbiamo prima conoscere le matrici di trasformazione degli operatori fondamentali, che sono le seguenti:

  • Traslazione di (x, y):
  • Scalare per (S_X, S_Y):
  • Rotazione di  theta:

Quindi, la nostra trasformazione composita può essere espressa come:

che è uguale a

oppure

dove

.

Ora, per trovare l'inverso di questa trasformazione affine composita, basta calcolare la composizione dell'inverso di ciascun operatore fondamentale in ordine inverso. Vale a dire, vogliamo

  1. Traslare l'immagine di (-t_x, -t_y)

  2. Ruotare l'immagine intorno all'origine di - theta.

  3. Scala l'immagine rispetto all'origine di (1/s_x, 1/s_y).

  4. Traslare l'immagine di (C_X, C_Y).

Il risultato è una matrice di trasformazione

dove

.

Questo è esattamente lo stesso come la trasformazione usata nel codice collegato alla risposta di Ruediger Jungbeck. Può essere reso più conveniente riutilizzando la stessa tecnica utilizzata da carlosdc nel suo post per il calcolo di (T_X, T_Y) dell'immagine, e tradurre l'immagine per (T_X, T_Y)-applicando la rotazione a tutti e quattro gli angoli dell'immagine e calcolando quindi la distanza tra i valori minimi e massimi di X e Y. Tuttavia, poiché l'immagine è ruotata attorno al proprio centro, non è necessario ruotare tutti e quattro gli angoli, poiché ogni coppia di angoli opposti è ruotata "simmetricamente".

Ecco una versione riscritta del codice di carlosdc che è stata modificata per utilizzare direttamente la trasformazione affine inversa e che aggiunge anche la scalatura:

from PIL import Image
import math

def scale_and_rotate_image(im, sx, sy, deg_ccw):
    im_orig = im
    im = Image.new('RGBA', im_orig.size, (255, 255, 255, 255))
    im.paste(im_orig)

    w, h = im.size
    angle = math.radians(-deg_ccw)

    cos_theta = math.cos(angle)
    sin_theta = math.sin(angle)

    scaled_w, scaled_h = w * sx, h * sy

    new_w = int(math.ceil(math.fabs(cos_theta * scaled_w) + math.fabs(sin_theta * scaled_h)))
    new_h = int(math.ceil(math.fabs(sin_theta * scaled_w) + math.fabs(cos_theta * scaled_h)))

    cx = w / 2.
    cy = h / 2.
    tx = new_w / 2.
    ty = new_h / 2.

    a = cos_theta / sx
    b = sin_theta / sx
    c = cx - tx * a - ty * b
    d = -sin_theta / sy
    e = cos_theta / sy
    f = cy - tx * d - ty * e

    return im.transform(
        (new_w, new_h),
        Image.AFFINE,
        (a, b, c, d, e, f),
        resample=Image.BILINEAR
    )

im = Image.open('test.jpg')
im = scale_and_rotate_image(im, 0.8, 1.2, 10)
im.save('outputpython.png')

e questo è il risultato (scalato con (sx, sy) = (0,8, 1,2) e ruotato di 10 gradi in senso antiorario):

Ridimensionato e ruotato

valutazioni e recensioni

Se sei d'accordo, hai la possibilità di scrivere cosa ti è piaciuto di questa divisione.



Utilizzate il nostro motore di ricerca

Ricerca
Generic filters

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.