Una lacuna per risolvere un algoritmo di distorsione di un'immagine
Sono un programmatore e sto cercando di realizzare un programma per trasformare un'area di un quadrilatero in un'altra immagine dove l'area precedente viene organizzata come un comune rettangolo.
So che sembra off topic ma per riuscire in questo obiettivo quello che mi manca e' qualche nozione trigonometrica che probabilmente avevo studiato ma ora (decenni dopo la fine della scuola) non riesco piu' a ricordare.
Per chiarire il problema osservate questa immagine:

Io parto dall'immagine di sinistra dove conosco i 4 punti A, B, C e D, e devo ottenere qualcosa di simile all'immagine di destra, dove l'area viene rimodellata in un comune rettangolo.
Io pensavo di aver capito come risolvere il problema ma mi sfugge un aspetto, probabilmente di trigonometria.
Con i punti A e B (immagine di sinistra) posso ottenere la funzione della retta passante per questi punti.
Posso poi conoscere anche la distanza tra i due punti A e B.
Supponendo che l'immagine finale (di destra) sia di 100 x 100 pixel, dovrei dividere la distanza tra A e B (a sinistra) per 100, e questo valore (incremento) lo usero' per leggere 100 punti (pixel) sulla retta A e B (sempre di sinistra)
Poi trasferiro' questi pixel nell'immagine finale ma rendendo la retta parallela all'asse delle X.
Quello che non capisco e' come fare a calcolare questi punti intermedi conoscendo la distanza da A.
Nell'immagine per esempio, come potrei calcolare le coordinate del punto P conoscendo i punti A e B e la distanza tra A e P?
Mi sembra di ricordare qualcosa su seno e coseno ma in pratica non so come costruire una formula generale per ottenere il punto P.
Vi ringrazio in anticipo.
Paolo
So che sembra off topic ma per riuscire in questo obiettivo quello che mi manca e' qualche nozione trigonometrica che probabilmente avevo studiato ma ora (decenni dopo la fine della scuola) non riesco piu' a ricordare.
Per chiarire il problema osservate questa immagine:

Io parto dall'immagine di sinistra dove conosco i 4 punti A, B, C e D, e devo ottenere qualcosa di simile all'immagine di destra, dove l'area viene rimodellata in un comune rettangolo.
Io pensavo di aver capito come risolvere il problema ma mi sfugge un aspetto, probabilmente di trigonometria.
Con i punti A e B (immagine di sinistra) posso ottenere la funzione della retta passante per questi punti.
Posso poi conoscere anche la distanza tra i due punti A e B.
Supponendo che l'immagine finale (di destra) sia di 100 x 100 pixel, dovrei dividere la distanza tra A e B (a sinistra) per 100, e questo valore (incremento) lo usero' per leggere 100 punti (pixel) sulla retta A e B (sempre di sinistra)
Poi trasferiro' questi pixel nell'immagine finale ma rendendo la retta parallela all'asse delle X.
Quello che non capisco e' come fare a calcolare questi punti intermedi conoscendo la distanza da A.
Nell'immagine per esempio, come potrei calcolare le coordinate del punto P conoscendo i punti A e B e la distanza tra A e P?
Mi sembra di ricordare qualcosa su seno e coseno ma in pratica non so come costruire una formula generale per ottenere il punto P.
Vi ringrazio in anticipo.
Paolo
Risposte
Più che la trigonometria a me sembra che qui serva un po' di geometria descrittiva abbinata alla geometria analitica, per ora senza fare calcoli:
- prima considerazione: il quadrilatero da trasformare deve essere una figura piana e quindi deve appartenere ad un piano;
- seconda considerazione: se i lati opposti del quadrilatero da trasformare non sono apparentemente paralleli significa che stiamo osservando la figura in prospettiva;
- tramite la geometria descrittiva dovresti determinare l'inclinazione del piano a cui appartiene la figura rispetto al piano dell'osservatore, quindi traslare dalla vista prospettica ad una vista ortogonale (o assonometrica);
- a questo punto tramite la geometrica analitica dovresti effettuare una rotazione del piano a cui appartiene la figura per renderlo parallelo al piano dell'osservatore.
Non è un procedimento banale, c'è da studiare un bel po'.
- prima considerazione: il quadrilatero da trasformare deve essere una figura piana e quindi deve appartenere ad un piano;
- seconda considerazione: se i lati opposti del quadrilatero da trasformare non sono apparentemente paralleli significa che stiamo osservando la figura in prospettiva;
- tramite la geometria descrittiva dovresti determinare l'inclinazione del piano a cui appartiene la figura rispetto al piano dell'osservatore, quindi traslare dalla vista prospettica ad una vista ortogonale (o assonometrica);
- a questo punto tramite la geometrica analitica dovresti effettuare una rotazione del piano a cui appartiene la figura per renderlo parallelo al piano dell'osservatore.
Non è un procedimento banale, c'è da studiare un bel po'.
In realta' l'immagine fornita e' un po' ingannevole.
L'immagine di sinistra sembra presa in prospettiva come fosse in origine un quadrato distorto secondo una qualche prospettiva ma in realta' e' solo un'area racchiusa in un piano e quest'area non e' realmente un quadrato o un rettangolo ruotato.
Forse per chiarire vale la pena spiegare a cosa mi serve questo algoritmo.
Devo importare in un motore grafico che accetta solo texture (porizioni di immagini da applicare alle facce delle mesh) di tipo rettangolare, partendo da oggetti dove invece le texture potrebbero avere qualunque forma, comunque delimitata in un poligono con vertici.
Il lavoro per trasformare i poligoni irregolari in rettangoli mi serve per far accettare l'oggetto, poi, quando il programma applichera' queste texture rettangolari cosi' ottenute, lo fara' su facce che avevano la forma poligonale irregolare, per cui anche se con qualche distorsione dovrebbe il motore 3d ricreare le texture correttamente.
Una cosa molto ingannevole dell'immagine e' che quella di destra che sarebbe quella finale, in realta' non verra' mai cosi' perche' il minore spesssore della colonna piu' a destra (che vediamo nell'immagine a sinistra) restera' anche in quella di destra.
Per dare un'idea avevo usato una funzione di photoshop che per l'appunto muoveva un'immagine in modo 3d, e da li' e' nato l'equivoco.
L'immagine di sinistra sembra presa in prospettiva come fosse in origine un quadrato distorto secondo una qualche prospettiva ma in realta' e' solo un'area racchiusa in un piano e quest'area non e' realmente un quadrato o un rettangolo ruotato.
Forse per chiarire vale la pena spiegare a cosa mi serve questo algoritmo.
Devo importare in un motore grafico che accetta solo texture (porizioni di immagini da applicare alle facce delle mesh) di tipo rettangolare, partendo da oggetti dove invece le texture potrebbero avere qualunque forma, comunque delimitata in un poligono con vertici.
Il lavoro per trasformare i poligoni irregolari in rettangoli mi serve per far accettare l'oggetto, poi, quando il programma applichera' queste texture rettangolari cosi' ottenute, lo fara' su facce che avevano la forma poligonale irregolare, per cui anche se con qualche distorsione dovrebbe il motore 3d ricreare le texture correttamente.
Una cosa molto ingannevole dell'immagine e' che quella di destra che sarebbe quella finale, in realta' non verra' mai cosi' perche' il minore spesssore della colonna piu' a destra (che vediamo nell'immagine a sinistra) restera' anche in quella di destra.
Per dare un'idea avevo usato una funzione di photoshop che per l'appunto muoveva un'immagine in modo 3d, e da li' e' nato l'equivoco.
Quindi partendo da un quadrilatero di cui conosci le coordinate dei vertici vuoi arrivare ad un rettangolo di cui "conosci" le coordinate dei vertici, questo già semplifica le cose.
Ovviamente sei coscente che non esiste un'unica equazione lineare che ti permette di traslare tutti i punti del quadrilatero nella forma rettangolare, ovvero già solo i vertici vengono traslati con equazioni lineari diverse figuriamoci tutti i punti.
Per affrontare un caso generale l'unico modo è ricavare l'equazione della distorsione (che non sarà sicuramente lineare) passando per un sistema di equazioni in due variabili.
Come ti dicevo i passi sono (e conoscendo la forma finale del quadrilatero diventa tutto più semplice):
- Collocare il piano a cui appartiene il quadrilatero in uno spazio ortogonale (si passa da equazioni ad una variabile a sistemi di equazioni in due variabili);
- Ruotare il piano fino a renderlo parallelo con uno dei piani cartesiani (a questo punto una coordinata diventa costante e si ritorna ad un'equazione ad una variabile);
- Con le equazioni di ortogonalizzazione e di rotazione del piano puoi traslare tutti i punti del quadrilatero dal piano di partenza (ruotato e distorto) al piano di destinazione (parallelo alla vista osservatore) mostrandoti la sua forma reale.
Sei convinto di questo passaggio o hai ancora dubbi?
Ovviamente sei coscente che non esiste un'unica equazione lineare che ti permette di traslare tutti i punti del quadrilatero nella forma rettangolare, ovvero già solo i vertici vengono traslati con equazioni lineari diverse figuriamoci tutti i punti.
Per affrontare un caso generale l'unico modo è ricavare l'equazione della distorsione (che non sarà sicuramente lineare) passando per un sistema di equazioni in due variabili.
Come ti dicevo i passi sono (e conoscendo la forma finale del quadrilatero diventa tutto più semplice):
- Collocare il piano a cui appartiene il quadrilatero in uno spazio ortogonale (si passa da equazioni ad una variabile a sistemi di equazioni in due variabili);
- Ruotare il piano fino a renderlo parallelo con uno dei piani cartesiani (a questo punto una coordinata diventa costante e si ritorna ad un'equazione ad una variabile);
- Con le equazioni di ortogonalizzazione e di rotazione del piano puoi traslare tutti i punti del quadrilatero dal piano di partenza (ruotato e distorto) al piano di destinazione (parallelo alla vista osservatore) mostrandoti la sua forma reale.
Sei convinto di questo passaggio o hai ancora dubbi?
Potresti fornire maggiori dettagli riguardo a quello che stai cercando di fare e quali librerie/programmi stai usando? Siccome le trasformazioni usate per rendere bidimensionale un mondo tridimensionali sono quelle proiettive, sono queste le trasformazioni che vengono usate anche per le texture. Ma il problema non viene normalmente risolto ragionando in 2D..
@Drake76
Non dubito che il procedimento che suggerisci sia corretto, il problema e' che cercavo di passare dall'astrazione del problema ad un algoritmo che realizza quel procedimento, temo pero' che la memoria non mi assista sulle funzioni da usare per applicare quel procedimento.
@apatriarca
Riguardo ai maggiori dettagll...
Io sono un mod di tomb raider level editor, una vecchia versione rilasciata assieme al tomb raider chronicles.
La faccenda e' un po' complicata nei dettagli ma in pratica quando noi appassionati creavamo nuovi oggetti 3d avevamo sempre il problema della texturizzazione quando l'oggetto aveva forme non elementari (parellelogrammi) ma antropomorfe, come il viso di una persona.
A quel punto si doveva lavorare faccia per faccia come in un puzzle.
Usando invece l'UV mapping si riesce a proiettare una texture ampia e inzialmente rettangolare su una serie di facce col risultato di avere poi i giusti frammenti gia' calcolati, faccia per faccia.
Il problema e' che i file intermedi che usiamo non accettano texture diverse da quelle rettangolari, in pratica accettano solo Origine(x,y) and Dimensione(dx, dy) mentre le textures generate dall'uv mapping sono quadrilateri anche irregolari (non ortogonali e richiedono quindi quattro punti.
La mia idea era di leggere le texture delimitate da quattro punti e distorcerle come dimensione e come orientamento in modo da rincondurle ad un rettangolo.
A quel punto potrei importare l'oggetto perche' ogni faccia avrebbe una texture rettangolare.
Visto poi che l'engine di gioco, quando applica una texture (sempre rettangolare) su una faccia che rettangolare non e', la distorce, la mia speranza e' che questa nuova distorsione riportera' la texture alla sua forma originale.
Detto cosi' sembra una grossa complicazione per nulla ma in realta' la differenza tra texturizzare gli oggetti con l'UV mapping o manualmente texture per texture e' enorme.
Cosi' io almeno ci provo, poi vedro' come verra' in gioco
Non dubito che il procedimento che suggerisci sia corretto, il problema e' che cercavo di passare dall'astrazione del problema ad un algoritmo che realizza quel procedimento, temo pero' che la memoria non mi assista sulle funzioni da usare per applicare quel procedimento.
@apatriarca
Riguardo ai maggiori dettagll...
Io sono un mod di tomb raider level editor, una vecchia versione rilasciata assieme al tomb raider chronicles.
La faccenda e' un po' complicata nei dettagli ma in pratica quando noi appassionati creavamo nuovi oggetti 3d avevamo sempre il problema della texturizzazione quando l'oggetto aveva forme non elementari (parellelogrammi) ma antropomorfe, come il viso di una persona.
A quel punto si doveva lavorare faccia per faccia come in un puzzle.
Usando invece l'UV mapping si riesce a proiettare una texture ampia e inzialmente rettangolare su una serie di facce col risultato di avere poi i giusti frammenti gia' calcolati, faccia per faccia.
Il problema e' che i file intermedi che usiamo non accettano texture diverse da quelle rettangolari, in pratica accettano solo Origine(x,y) and Dimensione(dx, dy) mentre le textures generate dall'uv mapping sono quadrilateri anche irregolari (non ortogonali e richiedono quindi quattro punti.
La mia idea era di leggere le texture delimitate da quattro punti e distorcerle come dimensione e come orientamento in modo da rincondurle ad un rettangolo.
A quel punto potrei importare l'oggetto perche' ogni faccia avrebbe una texture rettangolare.
Visto poi che l'engine di gioco, quando applica una texture (sempre rettangolare) su una faccia che rettangolare non e', la distorce, la mia speranza e' che questa nuova distorsione riportera' la texture alla sua forma originale.
Detto cosi' sembra una grossa complicazione per nulla ma in realta' la differenza tra texturizzare gli oggetti con l'UV mapping o manualmente texture per texture e' enorme.
Cosi' io almeno ci provo, poi vedro' come verra' in gioco
Io penso di aver capito il procedimento da applicare anche se non saprei mai creare una formula per generalizzarlo.
Vi spiego pero' una dimostrazione piu' algoritmica che altro cosi' poi chiarisco meglio le informazioni che mi mancano per realizzarlo.

Questa volta uso queste due immagini per evitare la confusione dell'immagine 3d distorta.
Assunto che io posso stabilire arbitrariamente A1 B1 C1 e D2, anche se poi A1 sara' sempre (0,0) e la distanza tra A1-B1 sara' sempre la distanza maggiore tra A-B e C-D, il mio procedimento e' basato su un concetto che non so definire in termini algebrici ma in pratica io posso copiare i pixel (ossia punti) dall'immagine a sinistra a quella di destra, trovando una posizione diversa ovviamnete.
Questa scansione avverra' in linee che partano da un vettore di punti S(i) (0 -n) (dove S starebbe per Start) che giace sul segmento A-D. Dove S(0) coincide con A e S(n) con D.
Sul lato opposto, ci sara' un vettore E (come End) con lo stesso numero di elementi n, e questi punti giaceranno sul segmento B-C.
A questo punto io scandisco tutti i segmenti S(0-n) - E(0-n) e ognuno di questi punti, li copiero' in altri n segmenti dell'immagine finale.
Per cui, per esempio:
I punti nel segmento S(0)-E(0) verranno posizionati sul nuovo segmento (immagine di destra) S(0)-E(0) (era meglio usare S1 ed E1 per l'immagine di destra).
Ovviamente nell'immagine di destra i segmenti saranno sempre paraelli all'asse delle X.
Il mio problema e' come calcolare i punti dei vettori S() ed (E).
In pratica potrei esporre questo sottoproblema in questi termini.
Se avete due punti A e B e vi viene chiesto di fornire gli n (numero arbitrario fornito) di punti intermedi al segmento A-B che divideranno il segmento in (n+1) micro segmenti di eguale dimensione, che soluzione fornireste?
Vi spiego pero' una dimostrazione piu' algoritmica che altro cosi' poi chiarisco meglio le informazioni che mi mancano per realizzarlo.

Questa volta uso queste due immagini per evitare la confusione dell'immagine 3d distorta.
Assunto che io posso stabilire arbitrariamente A1 B1 C1 e D2, anche se poi A1 sara' sempre (0,0) e la distanza tra A1-B1 sara' sempre la distanza maggiore tra A-B e C-D, il mio procedimento e' basato su un concetto che non so definire in termini algebrici ma in pratica io posso copiare i pixel (ossia punti) dall'immagine a sinistra a quella di destra, trovando una posizione diversa ovviamnete.
Questa scansione avverra' in linee che partano da un vettore di punti S(i) (0 -n) (dove S starebbe per Start) che giace sul segmento A-D. Dove S(0) coincide con A e S(n) con D.
Sul lato opposto, ci sara' un vettore E (come End) con lo stesso numero di elementi n, e questi punti giaceranno sul segmento B-C.
A questo punto io scandisco tutti i segmenti S(0-n) - E(0-n) e ognuno di questi punti, li copiero' in altri n segmenti dell'immagine finale.
Per cui, per esempio:
I punti nel segmento S(0)-E(0) verranno posizionati sul nuovo segmento (immagine di destra) S(0)-E(0) (era meglio usare S1 ed E1 per l'immagine di destra).
Ovviamente nell'immagine di destra i segmenti saranno sempre paraelli all'asse delle X.
Il mio problema e' come calcolare i punti dei vettori S() ed (E).
In pratica potrei esporre questo sottoproblema in questi termini.
Se avete due punti A e B e vi viene chiesto di fornire gli n (numero arbitrario fornito) di punti intermedi al segmento A-B che divideranno il segmento in (n+1) micro segmenti di eguale dimensione, che soluzione fornireste?
Che i segmenti S(x), E(x) e tutti quelli intermedi oltre ad avere dimensioni diverse giacciono anche su rette che hanno tutte equazioni completamente diverse.
Sembrerebbe che non ci sia alternativa ad un passaggio dal 2D al 3D e viceversa, ma forse mi è venuto in mente qualcosa per risovere il tuo problema usando rotazioni e distorsioni sul piano.
Vediamo prima i concetti senza impostare equazioni:
- prendendo ad esempio la tua figura, di cui conosci le coordinate dei vertici, dovrai per prima cosa effettuare una traslazione che posizioni il vertice D nell'origine, con le equazioni che effettuano questo spostamento si possono spostare tutti i punti del quadrilatero nella nuova posizione;
- tramite le nuove coordinate del vertice A puoi trovare l'equazione della retta su cui giace il segmento DA e trovare le equazioni che effettuano la rotazione di questa retta per renderla coincidente con l'asse delle y, tramite queste equazioni si possono ruotare tutti i punti del quadrilatero in modo che questo abbia il segmento DA sull'asse delle y;
- ora dovrai effettuare una scalatura del quadrilatero sull'asse delle y in modo che il segmento DA abbia le stesse dimensioni del segmento D1A1, ovviamente avrai una sola equazione ma questa volta sarà di secondo grado in quanto lo spostamento della coordinata y sarà tanto maggiore quanto più ci si troverà lontani dall'asse delle x, con questa equazione potrai spostare tutti i punti del quadrilatero che assumerà una nuova forma scalata lungo l'asse y;
- si procede con l'allineare il segmendo DC sull'asse x, per farlo puoi effettuare una traslazione del vertice C sull'asse x, quindi all'equazione aggiungerai una componente di secondo grado in modo che la traslazione dei punti del quadrilatero sia tanto minore quanto più ci si avvicina all'asse y fino ad annullarsi, questo eviterà una deformazione del segmento DA che già possiede le misure che vogliamo;
- si procede con l'allineare il segmendo AB all'asse x ed il segmento BC all'asse y, per farlo dovrai effettuare una traslazione del vertice B fino a fargli assumere la coordinata x di C e la coordinata y di A, a questa equazione dovrai aggiungere due componenti di secondo grado, una per ridurre la traslazione dei punti vicini all'asse x e una per i punti vicini all'asse y;
- avrai ottenuto un rettango dell'altezza desiderata ma non della larghezza, ma a questo punto dovrai solo effettuare una scalatura sull'asse x per ridurre il segmento DC fino alla misura di D1C1, l'equazione sarà simile a quella usata per ridurre il segmento DA.
Concatenando queste equazioni otterrai due sole equazioni con le quali potrai traslare tutti i punti del quadrilatero di partenza fino a fargli assumere la forma del rettangolo di destinazione.
Con i problemi di CGI non posso aiutarti, ad esempio come riempire i buchi in un segmento di pixel allungato che proviene da un segmento molto più corto.
Sembrerebbe che non ci sia alternativa ad un passaggio dal 2D al 3D e viceversa, ma forse mi è venuto in mente qualcosa per risovere il tuo problema usando rotazioni e distorsioni sul piano.
Vediamo prima i concetti senza impostare equazioni:
- prendendo ad esempio la tua figura, di cui conosci le coordinate dei vertici, dovrai per prima cosa effettuare una traslazione che posizioni il vertice D nell'origine, con le equazioni che effettuano questo spostamento si possono spostare tutti i punti del quadrilatero nella nuova posizione;
- tramite le nuove coordinate del vertice A puoi trovare l'equazione della retta su cui giace il segmento DA e trovare le equazioni che effettuano la rotazione di questa retta per renderla coincidente con l'asse delle y, tramite queste equazioni si possono ruotare tutti i punti del quadrilatero in modo che questo abbia il segmento DA sull'asse delle y;
- ora dovrai effettuare una scalatura del quadrilatero sull'asse delle y in modo che il segmento DA abbia le stesse dimensioni del segmento D1A1, ovviamente avrai una sola equazione ma questa volta sarà di secondo grado in quanto lo spostamento della coordinata y sarà tanto maggiore quanto più ci si troverà lontani dall'asse delle x, con questa equazione potrai spostare tutti i punti del quadrilatero che assumerà una nuova forma scalata lungo l'asse y;
- si procede con l'allineare il segmendo DC sull'asse x, per farlo puoi effettuare una traslazione del vertice C sull'asse x, quindi all'equazione aggiungerai una componente di secondo grado in modo che la traslazione dei punti del quadrilatero sia tanto minore quanto più ci si avvicina all'asse y fino ad annullarsi, questo eviterà una deformazione del segmento DA che già possiede le misure che vogliamo;
- si procede con l'allineare il segmendo AB all'asse x ed il segmento BC all'asse y, per farlo dovrai effettuare una traslazione del vertice B fino a fargli assumere la coordinata x di C e la coordinata y di A, a questa equazione dovrai aggiungere due componenti di secondo grado, una per ridurre la traslazione dei punti vicini all'asse x e una per i punti vicini all'asse y;
- avrai ottenuto un rettango dell'altezza desiderata ma non della larghezza, ma a questo punto dovrai solo effettuare una scalatura sull'asse x per ridurre il segmento DC fino alla misura di D1C1, l'equazione sarà simile a quella usata per ridurre il segmento DA.
Concatenando queste equazioni otterrai due sole equazioni con le quali potrai traslare tutti i punti del quadrilatero di partenza fino a fargli assumere la forma del rettangolo di destinazione.
Con i problemi di CGI non posso aiutarti, ad esempio come riempire i buchi in un segmento di pixel allungato che proviene da un segmento molto più corto.
A me sembra che vi stiate complicando la vita. La trasformazione che stai cercando è semplicemente una trasformazione bilineare:
\[ P(u, v) = (1 - v)\,\bigl( (1 - u)\,A + u\,B \bigr) + v\,\bigl( (1 - u)\,D + u\,C \bigr) \]
con i parametri \( 0 \leq u, v \leq 1. \) Quello che devi fare è calcolarti le coordinate parametriche dei vari pixel nel rettangolo allineato con gli assi e poi calcolarti il valore del pixel corrispondente nell'altro rettangolo. Qualcosa del genere insomma (mancano controllo errori e le strutture e funzioni sono ovviamente inventate - è C):
Spero sia abbastanza chiaro. Ovviamente image_get è stata definita in modo da poter accedere a valori dell'immagine in coordinate non intere. Per farlo hai bisogno di usare un qualche tipo di filtro.
\[ P(u, v) = (1 - v)\,\bigl( (1 - u)\,A + u\,B \bigr) + v\,\bigl( (1 - u)\,D + u\,C \bigr) \]
con i parametri \( 0 \leq u, v \leq 1. \) Quello che devi fare è calcolarti le coordinate parametriche dei vari pixel nel rettangolo allineato con gli assi e poi calcolarti il valore del pixel corrispondente nell'altro rettangolo. Qualcosa del genere insomma (mancano controllo errori e le strutture e funzioni sono ovviamente inventate - è C):
typedef struct Image Image; typedef uint32_t ColorRGBA; void image_write(Image *, int, int, ColorRGBA); ColorRGBA image_get(Image *, float , float); typedef struct Point2 Point2; struct Point2 { float x, y; }; typedef struct Quad Quad; struct Quad { Point2 A, B, C, D; }; typedef struct Rect Rect; struct Rect { int i_min, i_max, j_min, j_max; } static inline Point2 lerp(Point2 p0, Point2 p1, float t) { const float oneMinusT = 1.0 - t; return (Point2f){ oneMinusT*p0.x + t*p1.x, oneMinusT*p0.y + t*p1.y }; } void deformaQuadrato(Image *uvImage, Quad *uvQuad, Image *outImage, Rect *outRect) { for (int i = i_min; i < i_max; ++i) { const float u = (float)(i - outRect->i_min) / (float)(outRect->i_max - outRect->i_min); const Point2 q0 = lerp(uvQuad->A, uvQuad->B, u); const Point2 q1 = lerp(uvQuad->D, uvQuad->C, u); for (int j = j_min; j < j_max; ++j) { const float v = (float)(j - outRect->j_min) / (float)(outRect->j_max - outRect->j_min); const Point2 p = lerp(q0, q1, v); image_write(outImage, i, j, image_get(uvImage, p.x, p.y)); } } }
Spero sia abbastanza chiaro. Ovviamente image_get è stata definita in modo da poter accedere a valori dell'immagine in coordinate non intere. Per farlo hai bisogno di usare un qualche tipo di filtro.
Grazie davvero, a entrambi.
Il C e' perfetto, e' proprio il linguaggio che sto usando per questo programma.
Ora lo adatto e provo, devo studiarci un po' su, poi vi faccio sapere gli sviluppi.
grazie ancora.
Paolo
Il C e' perfetto, e' proprio il linguaggio che sto usando per questo programma.
Ora lo adatto e provo, devo studiarci un po' su, poi vi faccio sapere gli sviluppi.
grazie ancora.
Paolo
Funziona! 
Per ora l'ho provato come programmino in visual basic per verificare l'algoritmo.
Poi lo inseriro' nel codice di rimappatura delle texture in C.
C'e' una lieve distorsione nei bordi dell'immagine finale ma immagino sia fisiologico vista la griglia ortogonale dei pixel.
Questo e' il sorgente VB del programmino di prova:
http://www.webalice.it/paolone2011/download/distorsione_img.zip
Come immaginavo funziona anche con i triangoli, basta solo far coincidere C con D e l'immagine finale sara' un rettangolo dove l'immagine sorgente era il triangolo A-B-(CD)
Cosa molto utile perche' se come texture finale devo ottenere solo rettangoli, a livello sorgente possono anche esserci texture triangolari.
Grazie ancora, mi avete risparmiato settimane di bizzarri tentativi.

Per ora l'ho provato come programmino in visual basic per verificare l'algoritmo.
Poi lo inseriro' nel codice di rimappatura delle texture in C.
C'e' una lieve distorsione nei bordi dell'immagine finale ma immagino sia fisiologico vista la griglia ortogonale dei pixel.
Questo e' il sorgente VB del programmino di prova:
http://www.webalice.it/paolone2011/download/distorsione_img.zip
Come immaginavo funziona anche con i triangoli, basta solo far coincidere C con D e l'immagine finale sara' un rettangolo dove l'immagine sorgente era il triangolo A-B-(CD)
Cosa molto utile perche' se come texture finale devo ottenere solo rettangoli, a livello sorgente possono anche esserci texture triangolari.
Grazie ancora, mi avete risparmiato settimane di bizzarri tentativi.

Hai quindi mesh con topologia mista e non solo quadrangolare? È curioso come dopo parecchi anni da Tomb Raider Chronicles si stia tornando a soluzioni simili (PTEX) a quelle che hai descritto (anche se più che altro nei film e con tool/algoritmi di molto superiori). Un'alternativa a quella di passare per gli UV potrebbe probabilmente in effetti essere quella di convertire un file PTEX. Ovviamente devi avere accesso ad un programma in grado di lavorare con tali file e non credo che ci siano al momento software open-source o a basso prezzo che lo supportino.
In pratica e' mista sia a livello di sorgente (con texture quadrangolari o triangolari) che come destinazione, solo che in questo caso sono sempre basate su una texture rettangolare dove il triangolo e' sempre scelto tra uno dei quattro triangoli rettangolo che idealmente formano quel rettangolo.
A questo proposito mi rendo conto di avere gridato vittoria troppo presto...
E' vero che applicando quella formula posso convertire anche un un triangolo in un rettangolo, facendo coincidere C e D, ma ora mi rendo conto che non e' quello che voglio ottenere.
Non per i triangoli intendo.
Visto che tomb raider quando ha una faccia triangolare da riempire, vuole un triangolo rettangolo, incluso in un rettangolo, trasformare la texture orginale (UVmap) in un rettangolo non va bene, devo proprio trasformarla in un altro triangolo rettangolo.

In pratica avendo la texture di sinistra, dovrei ottenere quella di destra.
Che modifiche dovrei fare all'algoritmo precedente per riuscirci?
A questo proposito mi rendo conto di avere gridato vittoria troppo presto...
E' vero che applicando quella formula posso convertire anche un un triangolo in un rettangolo, facendo coincidere C e D, ma ora mi rendo conto che non e' quello che voglio ottenere.
Non per i triangoli intendo.
Visto che tomb raider quando ha una faccia triangolare da riempire, vuole un triangolo rettangolo, incluso in un rettangolo, trasformare la texture orginale (UVmap) in un rettangolo non va bene, devo proprio trasformarla in un altro triangolo rettangolo.

In pratica avendo la texture di sinistra, dovrei ottenere quella di destra.
Che modifiche dovrei fare all'algoritmo precedente per riuscirci?

Un metodo semplice potrebbe essere quello di definire un punto D come A + (B - A) + (C - A) e usare questo punto come quarto vertice del quadrilatero. In effetti hai che D1 = A1 + (B1 - A1) + (C1 - A1) anche nell'altro caso.
Grande, semplice ma geniale, grazie ancora. Vado a provare.
