varias una tridimensional superponer sistema puntos imagen hacer graficas fórmula extruir entre distancia dimensiones como cinema 3d geometry 2d photogrammetry reverseprojection

3d - una - superponer graficas en r



¿Cómo proyecto inversamente los puntos 2D en 3D? (14)

Asumiendo que los puntos son de hecho parte de un rectángulo, estoy dando una idea genérica:

Encuentre dos puntos con la máxima inter-distancia: estos probablemente definan una diagonal (excepción: casos especiales donde el rectángulo es casi paralelo al plano YZ, a la izquierda del estudiante). Llámelos A, C. Calcule los MALOS ángulos BCD. Estos, en comparación con los ángulos rectos, le dan orientación en el espacio 3D. Para conocer la distancia z, debe correlacionar los lados proyectados con los lados conocidos, y luego, según el método de proyección 3D (¿es 1 / z?), Está en el camino correcto para conocer las distancias.

Tengo 4 puntos 2D en el espacio de la pantalla, y necesito revertirlos al espacio 3D. Sé que cada uno de los 4 puntos es una esquina de un rectángulo rígido girado en 3D, y sé el tamaño del rectángulo. ¿Cómo puedo obtener coordenadas 3D a partir de esto?

No estoy usando ninguna API en particular, y no tengo una matriz de proyección existente. Solo estoy buscando matemáticas básicas para hacer esto. Por supuesto, no hay datos suficientes para convertir un solo punto 2D en 3D sin otra referencia, pero imagino que si tienes 4 puntos, sabes que están en ángulos rectos entre sí en el mismo plano, y conoces la distancia entre ellos, deberías ser capaz de resolverlo desde allí. Lamentablemente, no puedo entender cómo.

Esto podría caer bajo el paraguas de la fotogrametría, pero las búsquedas en Google no me han llevado a ninguna información útil.


Cuando proyecta de 3D a 2D, pierde información.

En el caso simple de un solo punto, la proyección inversa le daría un rayo infinito a través del espacio 3D.

La reconstrucción estereoscópica generalmente comenzará con dos imágenes en 2D y proyectará ambas a 3D. Luego busque una intersección de los dos rayos 3D producidos.

La proyección puede tomar diferentes formas. Ortogonal o perspectiva. ¿Supongo que estás asumiendo una proyección ortogonal?

En su caso suponiendo que tenía la matriz original, tendría 4 rayos en el espacio 3D. Luego, podría restringir el problema según las dimensiones de su rectángulo 3d e intentar resolverlo.

La solución no será única ya que una rotación alrededor de cualquiera de los ejes que es paralela al plano de proyección 2d será ambigua en la dirección. En otras palabras, si la imagen 2d es perpendicular al eje z, girar el rectángulo 3D en sentido horario o antihorario alrededor del eje x produciría la misma imagen. Del mismo modo para el eje y.

En el caso donde el plano rectangular es paralelo al eje z, tiene aún más soluciones.

Como no tiene la matriz de proyección original, se introduce una mayor ambigüedad mediante un factor de escala arbitario que existe en cualquier proyección. No puede distinguir entre una escala en la proyección y una traducción en 3d en la dirección del eje z. Esto no es un problema si solo está interesado en las posiciones relativas de los 4 puntos en el espacio 3D cuando están relacionados entre sí y no con el plano de la proyección 2d.

En una proyección en perspectiva las cosas se ponen más difíciles ...


La proyección que tienes sobre la superficie 2D tiene infinitamente muchos rectángulos 3D que se proyectarán a la misma forma 2D.

Piénselo de esta manera: tiene cuatro puntos 3D que forman el rectángulo 3D. Llámelos (x0, y0, z0), (x1, y1, z1), (x2, y2, z2) y (x3, y3, z3). Cuando proyecta estos puntos en el plano xy, suelta las coordenadas z: (x0, y0), (x1, y1), (x2, y2), (x3, y3).

Ahora, si desea proyectar nuevamente en el espacio 3D, necesita aplicar ingeniería inversa a lo que eran z0, .., z3. Pero cualquier conjunto de coordenadas z que a) mantenga la misma distancia xy entre los puntos, yb) mantenga la forma en que funcionará un rectángulo. Por lo tanto, cualquier miembro de este conjunto (infinito) lo hará: {(z0 + i, z1 + i, z2 + i, z3 + i) | yo <- R}.

Edit @Jarrett: Imagina que resolviste esto y terminaste con un rectángulo en el espacio 3D. Ahora, imagine deslizar ese rectángulo arriba y abajo del eje z. Esa cantidad infinita de rectángulos traducidos tiene la misma proyección xy. ¿Cómo sabes que encontraste el "correcto"?

Editar # 2: Muy bien, esto es por un comentario que hice sobre esta pregunta: un enfoque más intuitivo para razonar sobre esto.

Imagina que tienes un papel encima de tu escritorio. Imagine que cada esquina del papel tiene un puntero láser ingrávido que apunta hacia el escritorio. El papel es el objeto 3D y los puntos del puntero láser en el escritorio son la proyección en 2D.

Ahora, ¿cómo puedes saber qué tan alto está el papel en el escritorio mirando solo los puntos del puntero láser?

No puedes. Mueva el papel hacia arriba y hacia abajo. Los punteros láser seguirán brillando en los mismos puntos en el escritorio, independientemente de la altura del papel.

Encontrar las coordenadas z en la proyección inversa es como tratar de encontrar la altura del papel en función de los puntos del puntero láser en el escritorio solo.


Para mi motor OpenGL, el siguiente recorte convertirá las coordenadas del mouse / pantalla en coordenadas mundiales tridimensionales. Lea los comentarios para una descripción real de lo que está sucediendo.

/* FUNCTION: YCamera :: CalculateWorldCoordinates ARGUMENTS: x mouse x coordinate y mouse y coordinate vec where to store coordinates RETURN: n/a DESCRIPTION: Convert mouse coordinates into world coordinates */

void YCamera :: CalculateWorldCoordinates(float x, float y, YVector3 *vec) { // START GLint viewport[4]; GLdouble mvmatrix[16], projmatrix[16];

GLint real_y; GLdouble mx, my, mz; glGetIntegerv(GL_VIEWPORT, viewport); glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix); glGetDoublev(GL_PROJECTION_MATRIX, projmatrix); real_y = viewport[3] - (GLint) y - 1; // viewport[3] is height of window in pixels gluUnProject((GLdouble) x, (GLdouble) real_y, 1.0, mvmatrix, projmatrix, viewport, &mx, &my, &mz); /* ''mouse'' is the point where mouse projection reaches FAR_PLANE. World coordinates is intersection of line(camera->mouse) with plane(z=0) (see LaMothe 306) Equation of line in 3D: (x-x0)/a = (y-y0)/b = (z-z0)/c Intersection of line with plane: z = 0 x-x0 = a(z-z0)/c <=> x = x0+a(0-z0)/c <=> x = x0 -a*z0/c y = y0 - b*z0/c */ double lx = fPosition.x - mx; double ly = fPosition.y - my; double lz = fPosition.z - mz; double sum = lx*lx + ly*ly + lz*lz; double normal = sqrt(sum); double z0_c = fPosition.z / (lz/normal); vec->x = (float) (fPosition.x - (lx/normal)*z0_c); vec->y = (float) (fPosition.y - (ly/normal)*z0_c); vec->z = 0.0f;

}


Si sabe que la forma es un rectángulo en un plano, puede limitar aún más el problema. Ciertamente no se puede determinar el plano "que", por lo que puede elegir que se encuentra en el plano donde z = 0 y una de las esquinas en x = y = 0, y los bordes son paralelos al eje x / y.

Los puntos en 3d son, por lo tanto, {0,0,0}, {w, 0,0}, {w, h, 0} y {0, h, 0}. Estoy bastante seguro de que no se encontrará el tamaño absoluto, por lo que solo la relación w / h es releavant, por lo que este es uno desconocido.

En relación con este plano, la cámara debe estar en algún punto cx, cy, cz en el espacio, debe estar apuntando en una dirección nx, ny, nz (un vector de longitud uno, de modo que uno de estos es redundante), y tener un focal_length / image_width factor de w. Estos números se convierten en una matriz de proyección de 3x3.

Eso da un total de 7 incógnitas: w / h, cx, cy, cz, nx, ny y w.

Tienes un total de 8 knowns: los 4 pares x + y.

Entonces esto puede ser resuelto.

El siguiente paso es usar Matlab o Mathmatica.


Desde el espacio 2-D habrá 2 rectángulos válidos que se pueden construir. Sin conocer la proyección matriz original, no sabrá cuál es la correcta. Es lo mismo que el problema de "caja": ves dos cuadrados, uno dentro del otro, con los 4 vértices interiores conectados a los 4 vértices exteriores respectivos. ¿Estás mirando una caja de arriba hacia abajo o de abajo hacia arriba?

Dicho esto, estás buscando una transformación de matriz T donde ...

{{x1, y1, z1}, {x2, y2, z2}, {x3, y3, z3}, {x4, y4, z4}} x T = {{x1, y1}, {x2, y2}, { x3, y3}, {x4, y4}}

(4 x 3) x T = (4 x 2)

Entonces T debe ser una matriz (3 x 2). Entonces tenemos 6 incógnitas.

Ahora crea un sistema de restricciones en T y resuelve con Simplex. Para construir las restricciones, usted sabe que una línea que pasa por los dos primeros puntos debe ser paralela a la línea que pasa a los dos segundos puntos. Usted sabe que una línea que pasa por los puntos 1 y 3 debe ser paralela a las líneas que pasan por los puntos 2 y 4. Usted sabe que una línea que pasa por 1 y 2 debe ser ortogonal a una línea que pasa por los puntos 2 y 3. Usted sabe que la longitud de la línea de 1 y 2 debe ser igual a la longitud de la línea de 3 y 4. Usted sabe que la longitud de la línea de 1 y 3 debe ser igual a la longitud de la línea de 2 y 4.

Para hacer esto aún más fácil, conoces el rectángulo, para que conozcas la longitud de todos los lados.

Eso debería darte muchas limitaciones para resolver este problema.

Por supuesto, para volver, puedes encontrar T-inverso.

@Rob: Sí, hay un número infinito de proyecciones, pero no un número infinito de proyectos donde los puntos deben cumplir los requisitos de un rectángulo.

@nlucaroni: Sí, esto solo se puede resolver si tienes cuatro puntos en la proyección. Si el rectángulo se proyecta a solo 2 puntos (es decir, el plano del rectángulo es ortogonal a la superficie de proyección), entonces esto no se puede resolver.

Hmmm ... Debería irme a casa y escribir esta pequeña joya. Esto suena divertido.

Actualizaciones:

  1. Hay un número infinito de proyecciones a menos que arregles uno de los puntos. Si arreglas los puntos del rectángulo original, entonces hay dos posibles rectángulos originales.


Para seguir con el enfoque de Rons: puedes encontrar tus valores z si sabes cómo has rotado tu rectángulo.

El truco es encontrar la matriz proyectiva que hizo la proyección. Afortunadamente esto es posible e incluso barato de hacer. Las matemáticas relevantes se pueden encontrar en el documento "Asignaciones proyectivas para deformación de imágenes" de Paul Heckbert.

http://pages.cs.wisc.edu/~dyer/cs766/readings/heckbert-proj.pdf

De esta forma puede recuperar la parte homogénea de cada vértice que se perdió durante la proyección.

Ahora todavía te quedan cuatro líneas en lugar de puntos (como explicó Ron). Como sabes el tamaño de tu rectángulo original, sin embargo, no se pierde nada. Ahora puede conectar los datos del método de Ron y del enfoque 2D en un solucionador de ecuaciones lineales y resolver para z. Obtiene los valores z exactos de cada vértice de esa manera.

Nota: Esto solo funciona porque:

  1. La forma original era un rectángulo
  2. Usted sabe el tamaño exacto del rectángulo en el espacio 3D.

Es un caso especial realmente.

Espero que ayude, Nils


Voy a sacar mi libro lineal de Algebra cuando llegue a casa si nadie responde. Pero @ DG, no todas las matrices son invertibles. Las matrices singulares no son invertibles (cuando determinante = 0). Esto sucederá todo el tiempo, ya que una matriz de proyección debe tener valores propios de 0 y 1, y debe ser cuadrada (ya que es idempotente, entonces p ^ 2 = p).

Un ejemplo fácil es, [[0 1] [0 1]] ya que el determinante = 0, y eso es una proyección en la línea x = y!


D. DeMenthon ideó un algoritmo para calcular la posición de un objeto (su posición y orientación en el espacio) a partir de los puntos característicos de una imagen 2D al conocer el modelo del objeto: este es su problema exacto :

Describimos un método para encontrar la pose de un objeto a partir de una sola imagen. Suponemos que podemos detectar y combinar en la imagen cuatro o más puntos característicos no coplanarios del objeto, y que conocemos su geometría relativa en el objeto.

El algoritmo se conoce como Posit y se describe en el artículo clásico "Pose de objetos basada en modelos en 25 líneas de código" (disponible en su sitio web , sección 4).

Enlace directo al artículo: http://www.cfar.umd.edu/~daniel/daniel_papersfordownload/Pose25Lines.pdf Implementación de OpenCV: http://opencv.willowgarage.com/wiki/Posit

La idea es aproximar repetidamente la proyección en perspectiva mediante una proyección ortográfica a escala hasta converger a una postura precisa.


Este es el problema clásico para la Realidad Aumentada basada en marcadores.

Tiene un marcador cuadrado (código de barras 2D) y desea encontrar su posición (traducción y rotación en relación con la cámara), después de encontrar los cuatro bordes del marcador. Descripción general-Picture

No estoy al tanto de las últimas contribuciones al campo, pero al menos hasta cierto punto (2009) se suponía que RPP superaría a POSIT que se mencionó anteriormente (y de hecho es un enfoque clásico para esto) Consulte los enlaces, también proporcionar la fuente

(PD: sé que es un tema un poco viejo, pero de todos modos, la publicación podría ser útil para alguien)


Muy bien, vine aquí en busca de una respuesta y no encontré algo simple y sencillo, así que seguí e hice lo tonto pero efectivo (y relativamente simple): la optimización de Monte Carlo.

En pocas palabras, el algoritmo es el siguiente: perturbe de forma aleatoria su matriz de proyección hasta que proyecte sus coordenadas 3D conocidas a sus coordenadas 2D conocidas.

Aquí hay una foto fija de Thomas the Tank Engine:

Digamos que usamos GIMP para encontrar las coordenadas 2D de lo que creemos que es un cuadrado en el plano de tierra (si el cuadrado es o no depende de tu juicio de la profundidad):

Obtengo cuatro puntos en la imagen 2D: (318, 247) , (326, 312) , (418, 241) y (452, 303) .

Por convención, decimos que estos puntos deben corresponderse con los puntos 3D: (0, 0, 0) , (0, 0, 1) , (1, 0, 0) y (1, 0, 1) . En otras palabras, un cuadrado unitario en el plano y = 0.

Proyectar cada una de estas coordenadas 3D en 2D se hace multiplicando el vector 4D [x, y, z, 1] con una matriz de proyección 4x4, y luego dividiendo las componentes x e y por z para obtener realmente la corrección de perspectiva. Esto es más o menos lo que hace gluProject () , excepto que gluProject() también toma en cuenta la ventana gluProject() actual y toma en cuenta una matriz de vista modelo (podemos suponer que la matriz de vista de modelo es la matriz de identidad). Es muy útil mirar la documentación de gluProject() porque realmente quiero una solución que funcione para OpenGL, pero tenga cuidado de que a la documentación le falta la división por z en la fórmula.

Recuerde, el algoritmo debe comenzar con una matriz de proyección y perturbarla al azar hasta que proporcione la proyección que queremos. Entonces, lo que vamos a hacer es proyectar cada uno de los cuatro puntos 3D y ver cuán cerca estamos de los puntos 2D que queríamos. Si nuestras perturbaciones aleatorias hacen que los puntos 2D proyectados se acerquen a los que marcamos arriba, entonces mantenemos esa matriz como una mejora sobre nuestra conjetura inicial (o previa).

Vamos a definir nuestros puntos:

# Known 2D coordinates of our rectangle i0 = Point2(318, 247) i1 = Point2(326, 312) i2 = Point2(418, 241) i3 = Point2(452, 303) # 3D coordinates corresponding to i0, i1, i2, i3 r0 = Point3(0, 0, 0) r1 = Point3(0, 0, 1) r2 = Point3(1, 0, 0) r3 = Point3(1, 0, 1)

Necesitamos comenzar con una matriz, la matriz de identidad parece una elección natural:

mat = [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1], ]

Necesitamos implementar realmente la proyección (que es básicamente una multiplicación de matrices):

def project(p, mat): x = mat[0][0] * p.x + mat[0][1] * p.y + mat[0][2] * p.z + mat[0][3] * 1 y = mat[1][0] * p.x + mat[1][1] * p.y + mat[1][2] * p.z + mat[1][3] * 1 w = mat[3][0] * p.x + mat[3][1] * p.y + mat[3][2] * p.z + mat[3][3] * 1 return Point(720 * (x / w + 1) / 2., 576 - 576 * (y / w + 1) / 2.)

Esto es básicamente lo que hace gluProject() , 720 y 576 son el ancho y alto de la imagen, respectivamente (es decir, la ventana gráfica), y restamos de 576 para contar el hecho de que contamos las coordenadas y de la parte superior, mientras que OpenGL ellos desde abajo. Notará que no estamos calculando z, es porque realmente no lo necesitamos aquí (aunque podría ser útil para asegurarse de que esté dentro del rango que OpenGL usa para el buffer de profundidad).

Ahora necesitamos una función para evaluar cuán cerca estamos de la solución correcta. El valor devuelto por esta función es lo que usaremos para verificar si una matriz es mejor que otra. Elegí ir por suma de distancias cuadradas, es decir:

# The squared distance between two points a and b def norm2(a, b): dx = b.x - a.x dy = b.y - a.y return dx * dx + dy * dy def evaluate(mat): c0 = project(r0, mat) c1 = project(r1, mat) c2 = project(r2, mat) c3 = project(r3, mat) return norm2(i0, c0) + norm2(i1, c1) + norm2(i2, c2) + norm2(i3, c3)

Para perturbar la matriz, simplemente elegimos un elemento para perturbar por una cantidad aleatoria dentro de un rango:

def perturb(amount): from copy import deepcopy from random import randrange, uniform mat2 = deepcopy(mat) mat2[randrange(4)][randrange(4)] += uniform(-amount, amount)

(Vale la pena señalar que nuestra función project() no usa en realidad mat[2] , ya que no calculamos z, y dado que todas nuestras coordenadas y son 0, los valores de mat[*][1] son irrelevantes como Bien, podríamos usar este hecho y nunca tratar de perturbar esos valores, lo que daría una pequeña aceleración, pero eso queda como un ejercicio ...)

Para mayor comodidad, agreguemos una función que hace la mayor parte de la aproximación llamando a perturb() una y otra vez sobre cuál es la mejor matriz que hemos encontrado hasta ahora:

def approximate(mat, amount, n=100000): est = evaluate(mat) for i in xrange(n): mat2 = perturb(mat, amount) est2 = evaluate(mat2) if est2 < est: mat = mat2 est = est2 return mat, est

Ahora todo lo que queda por hacer es ejecutarlo ...

for i in xrange(100): mat = approximate(mat, 1) mat = approximate(mat, .1)

Encuentro que esto ya da una respuesta bastante precisa. Después de correr por un tiempo, la matriz que encontré fue:

[ [1.0836000765696232, 0, 0.16272110011060575, -0.44811064935115597], [0.09339193527789781, 1, -0.7990570384334473, 0.539087345090207 ], [0, 0, 1, 0 ], [0.06700844759602216, 0, -0.8333379578853196, 3.875290562060915 ], ]

con un error de alrededor de 2.6e-5 . (Observe cómo los elementos que dijimos que no se usaron en el cálculo no se han cambiado de nuestra matriz inicial, porque cambiar estas entradas no cambiaría el resultado de la evaluación y, por lo tanto, el cambio nunca se llevaría a cabo).

Podemos pasar la matriz a OpenGL usando glLoadMatrix() (pero recuerde transponerla primero, y recuerde cargar su matriz modelview con la matriz de identidad):

def transpose(m): return [ [m[0][0], m[1][0], m[2][0], m[3][0]], [m[0][1], m[1][1], m[2][1], m[3][1]], [m[0][2], m[1][2], m[2][2], m[3][2]], [m[0][3], m[1][3], m[2][3], m[3][3]], ] glLoadMatrixf(transpose(mat))

Ahora podemos, por ejemplo, traducir a lo largo del eje z para obtener diferentes posiciones a lo largo de las pistas:

glTranslate(0, 0, frame) frame = frame + 1 glBegin(GL_QUADS) glVertex3f(0, 0, 0) glVertex3f(0, 0, 1) glVertex3f(1, 0, 1) glVertex3f(1, 0, 0) glEnd()

Por supuesto, esto no es muy elegante desde el punto de vista matemático; no obtienes una ecuación de formulario cerrada en la que simplemente puedes ingresar tus números y obtener una respuesta directa (y precisa). SIN EMBARGO, le permite agregar restricciones adicionales sin tener que preocuparse por complicar sus ecuaciones; por ejemplo, si también quisiéramos incorporar altura, podríamos usar esa esquina de la casa y decir (en nuestra función de evaluación) que la distancia desde el suelo al techo debería ser tal y así, y ejecutar el algoritmo de nuevo. Entonces sí, es una especie de fuerza bruta, pero funciona y funciona bien.


Gracias a @Vegard por una excelente respuesta. Limpié el código un poco:

import pandas as pd import numpy as np class Point2: def __init__(self,x,y): self.x = x self.y = y class Point3: def __init__(self,x,y,z): self.x = x self.y = y self.z = z # Known 2D coordinates of our rectangle i0 = Point2(318, 247) i1 = Point2(326, 312) i2 = Point2(418, 241) i3 = Point2(452, 303) # 3D coordinates corresponding to i0, i1, i2, i3 r0 = Point3(0, 0, 0) r1 = Point3(0, 0, 1) r2 = Point3(1, 0, 0) r3 = Point3(1, 0, 1) mat = [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1], ] def project(p, mat): #print mat x = mat[0][0] * p.x + mat[0][1] * p.y + mat[0][2] * p.z + mat[0][3] * 1 y = mat[1][0] * p.x + mat[1][1] * p.y + mat[1][2] * p.z + mat[1][3] * 1 w = mat[3][0] * p.x + mat[3][1] * p.y + mat[3][2] * p.z + mat[3][3] * 1 return Point2(720 * (x / w + 1) / 2., 576 - 576 * (y / w + 1) / 2.) # The squared distance between two points a and b def norm2(a, b): dx = b.x - a.x dy = b.y - a.y return dx * dx + dy * dy def evaluate(mat): c0 = project(r0, mat) c1 = project(r1, mat) c2 = project(r2, mat) c3 = project(r3, mat) return norm2(i0, c0) + norm2(i1, c1) + norm2(i2, c2) + norm2(i3, c3) def perturb(mat, amount): from copy import deepcopy from random import randrange, uniform mat2 = deepcopy(mat) mat2[randrange(4)][randrange(4)] += uniform(-amount, amount) return mat2 def approximate(mat, amount, n=1000): est = evaluate(mat) for i in xrange(n): mat2 = perturb(mat, amount) est2 = evaluate(mat2) if est2 < est: mat = mat2 est = est2 return mat, est for i in xrange(1000): mat,est = approximate(mat, 1) print mat print est

La llamada aproximada con .1 no funcionó para mí, así que la saqué. Lo ejecuté por un tiempo también, y la última vez que lo revisé fue en

[[0.7576315397559887, 0, 0.11439449272592839, -0.314856490473439], [0.06440497208710227, 1, -0.5607502645413118, 0.38338196981556827], [0, 0, 1, 0], [0.05421620936883742, 0, -0.5673977598434641, 2.693116299312736]]

con un error alrededor de 0.02.


Sí, Monte Carlo funciona, pero encontré una mejor solución para este problema. Este código funciona perfectamente (y usa OpenCV):

Cv2.CalibrateCamera(new List<List<Point3f>>() { points3d }, new List<List<Point2f>>() { points2d }, new Size(height, width), cameraMatrix, distCoefs, out rvecs, out tvecs, CalibrationFlags.ZeroTangentDist | CalibrationFlags.FixK1 | CalibrationFlags.FixK2 | CalibrationFlags.FixK3);

Esta función toma conocidos puntos 3d y 2d, tamaño de la pantalla y devuelve rotación (rvecs [0]), traducción (tvecs [0]) y matriz de valores intrínsecos de la cámara. Es todo lo que necesitas.