2011-03-02 10 views
7

Ho una mappa di altezza per un'immagine, che indica l'offset di ciascun pixel nella direzione Z. Il mio obiettivo è appiattire un'immagine distorta usando solo la sua mappa di altezza.Distorsione di un'immagine utilizzando una mappa di altezza?

Come faccio a fare questo? Conosco la posizione della telecamera, se questo aiuta.


Per fare questo, pensavo supponendo che ciascun pixel è un punto su un piano, e quindi di tradurre ciascuno di questi punti verticalmente secondo il valore Z ottengo dalla mappa altezza, e da quella traduzione (immagina di guardare i punti dall'alto, lo spostamento farà sì che il punto si muova dalla tua prospettiva).

Da tale spostamento previsto, è stato possibile estrarre lo spostamento X e Y di ciascun pixel, che potrei inserire in cv.Remap().

Ma non ho idea di come sia possibile ottenere l'offset 3D proiettato di un punto con OpenCV, per non parlare di costruire una mappa sfalsata.


Qui sono le mie immagini di riferimento per quello che sto facendo:

Calibration Image Warped Image

So che l'angolo dei laser (45 gradi), e dalle immagini di calibrazione, posso calcolare l'altezza del libro molto facilmente:

h(x) = sin(theta) * abs(calibration(x) - actual(x)) 

Faccio questo per entrambe le linee e interpolare linearmente le due lin es per generare una superficie usando questo approccio (codice Python. E 'all'interno di un ciclo):

height_grid[x][y] = heights_top[x] * (cv.GetSize(image)[1] - y) + heights_bottom[x] * y 

Spero che questo aiuta;)


In questo momento, questo è quello che ho da dewarp l'immagine. Tutta quella roba strana nei progetti di mezzo di coordinate 3D sul piano della macchina fotografica, data la sua posizione (e la posizione della fotocamera, la rotazione, ecc):

class Point: 
    def __init__(self, x = 0, y = 0, z = 0): 
    self.x = x 
    self.y = y 
    self.z = z 

mapX = cv.CreateMat(cv.GetSize(image)[1], cv.GetSize(image)[0], cv.CV_32FC1) 
mapY = cv.CreateMat(cv.GetSize(image)[1], cv.GetSize(image)[0], cv.CV_32FC1) 

c = Point(CAMERA_POSITION[0], CAMERA_POSITION[1], CAMERA_POSITION[2]) 
theta = Point(CAMERA_ROTATION[0], CAMERA_ROTATION[1], CAMERA_ROTATION[2]) 
d = Point() 
e = Point(0, 0, CAMERA_POSITION[2] + SENSOR_OFFSET) 

costx = cos(theta.x) 
costy = cos(theta.y) 
costz = cos(theta.z) 

sintx = sin(theta.x) 
sinty = sin(theta.y) 
sintz = sin(theta.z) 


for x in xrange(cv.GetSize(image)[0]): 
    for y in xrange(cv.GetSize(image)[1]): 

    a = Point(x, y, heights_top[x/2] * (cv.GetSize(image)[1] - y) + heights_bottom[x/2] * y) 
    b = Point() 

    d.x = costy * (sintz * (a.y - c.y) + costz * (a.x - c.x)) - sinty * (a.z - c.z) 
    d.y = sintx * (costy * (a.z - c.z) + sinty * (sintz * (a.y - c.y) + costz * (a.x - c.x))) + costx * (costz * (a.y - c.y) - sintz * (a.x - c.x)) 
    d.z = costx * (costy * (a.z - c.z) + sinty * (sintz * (a.y - c.y) + costz * (a.x - c.x))) - sintx * (costz * (a.y - c.y) - sintz * (a.x - c.x)) 

    mapX[y, x] = x + (d.x - e.x) * (e.z/d.z) 
    mapY[y, x] = y + (d.y - e.y) * (e.z/d.z) 


print 
print 'Remapping original image using map...' 

remapped = cv.CreateImage(cv.GetSize(image), 8, 3) 
cv.Remap(image, remapped, mapX, mapY, cv.CV_INTER_LINEAR) 

Questo si sta trasformando in un enorme filo di immagini e il codice ora ... Comunque, questo pezzo di codice impiega i miei 7 minuti per girare su un'immagine da 18MP; questo è modo troppo lungo e, alla fine, questo approccio non fa nulla all'immagine (l'offset per ogni pixel è << 1).

Qualche idea?

risposta

3

ho finito per attuare la mia soluzione:

for x in xrange(cv.GetSize(image)[0]): 
    for y in xrange(cv.GetSize(image)[1]): 

    a = Point(x, y, heights_top[x/2] * (cv.GetSize(image)[1] - y) + heights_bottom[x/2] * y) 
    b = Point() 

    d.x = costy * (sintz * (a.y - c.y) + costz * (a.x - c.x)) - sinty * (a.z - c.z) 
    d.y = sintx * (costy * (a.z - c.z) + sinty * (sintz * (a.y - c.y) + costz * (a.x - c.x))) + costx * (costz * (a.y - c.y) - sintz * (a.x - c.x)) 
    d.z = costx * (costy * (a.z - c.z) + sinty * (sintz * (a.y - c.y) + costz * (a.x - c.x))) - sintx * (costz * (a.y - c.y) - sintz * (a.x - c.x)) 

    mapX[y, x] = x + 100.0 * (d.x - e.x) * (e.z/d.z) 
    mapY[y, x] = y + 100.0 * (d.y - e.y) * (e.z/d.z) 


print 
print 'Remapping original image using map...' 

remapped = cv.CreateImage(cv.GetSize(image), 8, 3) 
cv.Remap(image, remapped, mapX, mapY, cv.CV_INTER_LINEAR) 

Questo (lentamente) riassegna ogni pixel utilizzando la funzione cv.Remap, e questo sembra tipo di lavoro ...

0

La distorsione basata sulla distanza dalla telecamera avviene solo con una proiezione prospettica. Se si dispone della posizione (x, y, z) di un pixel, è possibile utilizzare la matrice di proiezione della telecamera per ritrasformare i pixel nello spazio del mondo. Con queste informazioni, puoi rendere i pixel in modo ortogonale. Tuttavia, potresti aver perso i dati, a causa della proiezione prospettica originale.

+0

Can OpenCV mappa 3D in 2D ? O devo venire con la mia formula per questo? Cercherò di implementare questo, però, quindi grazie! – Blender

0

separata la scena come segue:

  • si dispone di un'immagine bitmap sconosciuta I (x, y) -> (R, G, B)
  • si dispone di un campo di altezza nota h (x, y) -> h
  • avete una fotocamera trasformare C (x, y, z) -> (u, v) che sporge la scena di un piano dello schermo

Nota che la videocamera trasforma le informazioni (non ottieni un valore di profondità per ogni pixel dello schermo). Potresti anche sovrapporre alcuni frammenti di scena sullo schermo, nel qual caso viene mostrato solo il primo - il resto viene scartato. Quindi in generale questo non è perfettamente reversibile.

  • è necessario uno schermo catturato S (u, v), che è il risultato di C (x, y, H (x, y)) per x, y in I
  • si desidera generare uno screenshot S ' (u', v '), che è il risultato di C (x, y, 0) per x, y in I

Ci sono due modi ovvi per avvicinarsi a questo; entrambi dipendono dall'avere valori precisi per la trasformazione della telecamera.

  1. Ray-casting: per ogni pixel S, gettato un raggio di nuovo in scena. Scopri dove colpisce l'altezza; questo ti dà (x, y) nell'immagine originale I, e il pixel dello schermo ti dà il colore in quel punto. Una volta che hai più di I come puoi recuperare, ri-trasformalo per trovare S '.

  2. Doppio rendering: per ogni x, y in I, progetto per trovare (u, v) e (u ', v'). Prendi il pixel-color da S (u, v) e copialo su S ' (u', v ').

Entrambi i metodi avranno problemi di campionamento che essere aiutati da Supercampionamento o interpolazione; il metodo 1 lascerà spazi vuoti nelle aree occluse dell'immagine, il metodo 2 "proietterà" dalla prima superficie.

Edit:

avevo presunto si intende un height stile CG, dove ogni pixel in S si trova direttamente sopra nella posizione corrispondente del S '; ma questo non è il modo in cui una pagina si estende su una superficie. Una pagina è fissata alla colonna vertebrale ed è non elastica - sollevando il centro di una pagina si tira il bordo libero verso la colonna vertebrale.

Sulla base dell'immagine del campione, è necessario invertire questa trazione cumulativa: rilevare la posizione e l'orientamento della linea centrale della colonna vertebrale e lavorare progressivamente a sinistra e a destra, individuando il cambiamento di altezza nella parte superiore e inferiore di ciascuna striscia verticale di pagina , calcolando l'aspetto risultante: restringimento e inclinazione, e invertendolo per ricreare la pagina piatta originale.

+0

Ho modificato la mia risposta di conseguenza. Includo anche le immagini di riferimento, solo per vedere cosa intendo. – Blender

+0

Sì, le immagini di esempio sono di grande aiuto. Un paio di pensieri: in primo luogo, puoi rendere l'immagine quasi ortogonale per iniziare usando un teleobiettivo e riprendendo il più lontano possibile. In secondo luogo, le pagine stanno riposando con qualche dislivello verticale su di esse - il punto in cui il bordo inferiore poggia su una superficie planare potrebbe ridurlo o eliminarlo. Quindi la correzione dell'immagine finisce per essere solo la correzione della larghezza con l'arcocoseno dell'angolo di incidenza della pagina (cioè molto semplice). –

+0

Sono bloccato solo con un obiettivo zoom 3X, quindi dovrò vivere con la correzione manuale per la deformazione tangenziale e radiale. Potresti elaborare un po 'di più sul metodo 'arccos()'? Non ci sto riuscendo. – Blender

Problemi correlati