Newsgroup: it.comp.lang.visual-basic
Titolo: Prospettiva

Come posso fare a calcolare la lunghezza di una linea in una immagine in
prospettiva?
per esempio:
    /\
 a /  \c
b /    \d
in questa immagine come posso fare a calcolare le distanze tra (a-c) e
(b-d) che nella realtà sono uguali mentre nella immagine sono diverse?
Mi servirebbe un algoritmo che moltipli la lunghezza della base per un
moltiplicatore in base all'altezza dove il segmento si trova nella figura.
Grazie.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

[...]
Un algoritmo di questo genere non si può fae nel caso generale.. Cioè si può 
fare solo se lo spazio fotografato è strutturato.. cioè, ad esempio, sai che 
è tutto su un piano..
Intanto ti servono come minimo la linea dell'orizzonte e due lunghezze di 
riferimento (magari ortogonali)..
ma se lo spazio fotografato non ha una struttura che tu già conosci non puoi 
comunque dire niente, ti faccio un esempio:
prendi i punti a e c della tua immagine (mettiamo che siano quelli alla base 
delle /  \), se tu sai a priori che sono sullo stesso piano di b e d e 
dell'orizzonte puoi dire qualcosa, perchè si tratta della proiezione di un 
piano.. ..altrimenti non puoi dire niente.. ..metti infatti che a e c siano 
su un piano più basso, allora a-c è necessarimente più grande di quella che 
si potrebbe calcolare se fossero sullo stesso piano..
Non so se mi sono spiegato bene, ma senza un disegnetto è difficile..
Casomai prova a specificare meglio il tuo scopo, magari possiamo individuare 
la struttura dello spazio (che non deve per forza essere piano) e vedere..
Aspetta, forse così è più chiaro:
    secondo me, non puoi misurare contemporaneamente distanza e dimensione 
di un oggetto..
Ad esempio pensa ad una sfera, può essere lontana e grande o piccola e 
vicina e dare la stessa immagine proiettata..
Quindi devi conoscerne almeno una delle due: distanza o grandezza!
Se quello che analizzi è tutto su un piano la cosa è possibile perchè ogni 
punto dell'immagine individua un preciso punto del piano quindi conosci la 
posizione. Mentre se ti manca il piano di riferimento (la struttura) non fai 
niente.. 

Grazie x la risposta circostanziata.
In effetti non avevo pensato alle varianti tridimensionali della
prospettiva.
Ti confermo che si tratta di una immagine struttura su un piano, una
strada praticamente.
Un po' come i circuiti automobilistici dei videogames.
Come posso calcolare le dimensioni reali in rapporto alla lunghezza in
pixel dell'immagini delle varie sezioni verticali?


[...]
Dunque, supponendo per semplicità che la strada sia il piano XY orizzontale, 
l'immagine sia sul piano verticale  XZ e l'osservatore (O) sia un punto si 
ha
osservatore:            O(xo, yo, zo) o
Punto immagine:      P(xi,0,zi)
allora la retta che passa per questi due punti è
X = O + t (P-O)
cioè
(x,y,z) = (xo, yo, zo) +t*((xi,0,zi)-(xo, yo, zo))
          =(xo, yo, zo) +t*(xi-xo,-yo,zi-zo)
Mentre il piano XY ovviamente ha equazione z=0
dunque il punto reale Q(xp,yp,zp) rappresentato nell'immagine è calcolabile 
imponendo z=0
dunque..
z = zo + t*(zi-zo) = 0
da cui
t = zo / (zo-zi)
quindi il punto rappresentato è noto sostituendo t in
(x,y,z) = (xo, yo, zo) + t*(xi-xo,-yo,zi-zo)
           = (xo,yo,zo) + (zo / (zo-zi)) * (xi-xo,-yo,zi-zo)
           = (xo + zo * (xi-xo) / (zo-zi), yo*(1 - zo / (zo-zi)), 0)
quindi in definitiva
Q = (xo + zo * (xi-xo) / (zo-zi), yo*(1 - zo / (zo-zi)), 0)
considerando che zp = 0 tanto vale veanche scriverla..
Q = (xo + zo * (xi-xo) / (zo-zi), yo*(1 - zo / (zo-zi)))
A questo punto prendi i tuoi due  punti e fai la distanza con pitagora come 
al solito.
Alcune note:
- sta a te decidere in che posizione del piano XZ è posizionata l'immagine, 
ciò comporta usare le proprietà scale dell'immagine per modificarne il 
sistema di coordinate, oppure farti la trasformazione da coordinate pixel a 
coordinate di P(xi,0,zi)
- dovresti impostare la posizione dell'osservatore in modo che i punti 
dell'orizzonte siano alla stessa z dell'osservatore (poi ovviamente se vuoi 
un punto al di sopra dell'rizzonte le formule ti restituiscono un punto 
dietro all'immagine, ma sta a te calcolare le distanze solo sulla strada 
come avevamo ipotizzato..
- se hai bisogno ci sono ancora, per ciarimenti, qui ho buttato giù le 
formule e ricavato al momento.. ..ci sipuò spiegare anche meglio, ma non 
vorrei toglierti tutto il divertimento..
Ciao,
    Diego 

Mi appunto le tue preziose indicazioni e me lo studio con calma.
Grazie di nuovo.


Ci ho provato, ma non so da dove prendere il toro per le corna :(
Potresti provare a postarmi un esempio in codice per misurare un segmento
in base alla posizione e alla dimensione in pixel?


[...]
Allora direi..
Ricordando che
Q = (xo + (xi-xo) * zo / (zo-zi), yo*(1 - zo / (zo-zi)))
se lo scopo è misurarre distanze possiamo fare delle semplificazioni ed 
eliminare tutti i temini costanti che tanto poi spariscono col calcolo della 
distanza..
Quindi
Q' =((xi-xo) * zo / (zo-zi), - yo * zo / (zo-zi)))
Chiamiamo K un punto dell'immagine sulla linea dell'orizzonte
allora le sue coordinate sono K(xk,0,zk)
..poi per altri ragionamenti fatti in testa mia la riscrivo come..
Q'=((xi-xk)*a/(yk-yi), b*a/(yk-yi))
Da cui si vede che
Xq= a*(xi-xk)/(yk-yi)
Yq= a*b/(yk-yi)
Come si vede siamo arrivati a formule semplici semplici..
Per impostare xk e zk devi specificare in che punto dell'immagine si trova K
quindi qualcosa del tipo:
Private Sub picImmagine_MouseDown(......)
    xk=X
    zk=Y
End Sub
Restano i parametri a e b che ho introdotto sopra..
Come avevo scritto ancora nella prima risposta ci ritoviamo che dopo aver 
individuato l'orizzonte ci mancano due misure note nell'immagine..
Quindi a e b si possono calcolare se conosci due misure nell'immagine.
      /\
 A /   \ C
B /      \ D
metti che conosci  (A-C)
allora cliccando nell'immagine abbiamo (xa,ya)
Private Sub picImmagine_MouseDown(......)
    xa=X
    ya=Y
End Sub
e (xc,yc)
Private Sub picImmagine_MouseDown(......)
    xc=X
    yc=Y
End Sub
Visto che a e c sono sulla stessa orizzontale si ha che
    (ricordando anche che ya=yc)
(A-C) = |Xa-Xc|
      = |a*(xa-xk)/(yk-ya) - a*(xc-xk)/(yk-yc)|
      = a*|(xa-xc)/(yk-ya)|
quindi:
a = (A-C) * |(yk-ya)/(xa-xc)|
come si vede se dobbiamo fare solo misure orizzontali siamo a posto: basta 
a!
per calcolare b occorre un'altra distanza nota, faccio notare che deve 
essere linearmente indipendente da quella diprima cipè non vale un'altra 
misura orizzontale..
Quindi mettiamo di conoscere (A-B)
dunque
(A-B) = |Ya-Yb|
          = |a*b/(yk-ya) - a*b/(yk-yb)|
          = a*b*|1/(yk-ya)-1/(yk-yb)|
          = a*b*| (ya-yb)/((yk-ya)*(yk-yb))|
b = |(A-B) * (yk-ya)*(yk-yb)/(a*(ya-yb))|
Una volta fatta questa fase di impostazione sei pronto a prendere tutte le 
misure che vuoi..
Le formule sono sempre le stesse:
Xq= a*(xi-xk)/(yk-yi)
Yq= a*b/(yk-yi)
e per ottenere (xi,yi) usi
Private Sub picImmagine_MouseDown(......)
    xi=X
    yi=Y
End Sub
Ciao