Blog
Pose Estimación o coordenadas 3D de angulos
- Publicado por: Rafael Fernandez
- Categoría: Blog OpenCV Procesamiento de Imagenes
Aprenderemos a explotar el módulo calib3d para crear algunos efectos 3D en imágenes.
Fundamentos
Esta va a ser una pequeña sección. Durante la última sesión de calibración de la cámara, se ha encontrado la matriz de la cámara, los coeficientes de distorsión, etc. Dada una imagen patrón, podemos utilizar la información anterior para calcular su posición, o cómo el objeto está situado en el espacio, como por ejemplo cómo se rota, cómo se desplaza, etc. Para un objeto plano, podemos asumir Z=0, de manera que el problema ahora es cómo se coloca la cámara en el espacio para ver nuestra imagen patrón. Por lo tanto, si sabemos cómo se encuentra el objeto en el espacio, podemos dibujar algunos diagramas 2D en él para simular el efecto 3D. Veamos cómo hacerlo.
Nuestro problema es que queremos dibujar nuestro eje de coordenadas 3D (ejes X, Y, Z) en la primera esquina de nuestro tablero de ajedrez. Eje X en color azul, eje Y en color verde y eje Z en color rojo. Así que en efecto, el eje Z debería sentirse como si fuera perpendicular a nuestro plano de ajedrez.
Primero, vamos a cargar la matriz de la cámara y los coeficientes de distorsión del resultado de calibración anterior.
import cv2 import numpy as np import glob # Load previously saved data with np.load('B.npz') as X: mtx, dist, _, _ = [X[i] for i in ('mtx','dist','rvecs','tvecs')]
Ahora vamos a crear una función, draw que toma las esquinas en el tablero de ajedrez (obtenido usando cv2.findChessboardCorners () y los ejes apuntan a dibujar un eje 3D.
def draw(img, corners, imgpts): corner = tuple(corners[0].ravel()) img = cv2.line(img, corner, tuple(imgpts[0].ravel()), (255,0,0), 5) img = cv2.line(img, corner, tuple(imgpts[1].ravel()), (0,255,0), 5) img = cv2.line(img, corner, tuple(imgpts[2].ravel()), (0,0,255), 5) return img
Luego, como en el caso anterior, creamos criterios de terminación, puntos de objeto (puntos 3D de esquinas en tablero de ajedrez) y puntos de eje. Los puntos de eje son puntos en el espacio 3D para dibujar el eje. Dibujamos el eje de longitud 3 (las unidades serán en términos de ajedrez de tamaño cuadrado ya que nos calibramos en base a ese tamaño). Así que nuestro eje X está dibujado de (0,0,0,0) a (3,0,0,0), así que para el eje Y. Para el eje Z, se toma de (0,0,0,0) a (0,0, -3). Negativo significa que se dibuja hacia la cámara.
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) objp = np.zeros((6*7,3), np.float32) objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2) axis = np.float32([[3,0,0], [0,3,0], [0,0,-3]]).reshape(-1,3)
Ahora, como siempre, cargamos cada imagen. Busca la cuadrícula 7×6. Si lo encontramos, lo refinamos con subpíxel. A continuación, para calcular la rotación y la traslación, utilizamos la función cv2.solutionPnPRansac (). Una vez esas matrices de transformación las usamos para proyectar nuestros ejes al plano de la imagen. En palabras simples, encontramos los puntos en el plano de la imagen correspondientes a cada uno de (3,0,0,0), (0,3,0,0), (0,0,3) en el espacio 3D. Una vez que los tenemos, dibujamos líneas desde la primera esquina hasta cada uno de estos puntos usando nuestra función draw ().
for fname in glob.glob('left*.jpg'): img = cv2.imread(fname) gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret, corners = cv2.findChessboardCorners(gray, (7,6),None) if ret == True: corners2 = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria) # Find the rotation and translation vectors. ret,rvecs, tvecs, inliers = cv2.solvePnP(objp, corners2, mtx, dist) # project 3D points to image plane imgpts, jac = cv2.projectPoints(axis, rvecs, tvecs, mtx, dist) img = draw(img,corners2,imgpts) cv2.imshow('img',img) k = cv2.waitKey(0) & 0xFF if k == ord('s'): cv2.imwrite(fname[:6]+'.png', img) cv2.destroyAllWindows()
Vea algunos resultados a continuación. Observe que cada eje tiene 3 cuadrados de longitud:
Renderizar un cubo
Si desea dibujar un cubo, modifique la función draw () y los puntos de los ejes como se indica a continuación.
Función de dibujo modificado ():
def draw(img, corners, imgpts): imgpts = np.int32(imgpts).reshape(-1,2) # draw ground floor in green img = cv2.drawContours(img, [imgpts[:4]],-1,(0,255,0),-3) # draw pillars in blue color for i,j in zip(range(4),range(4,8)): img = cv2.line(img, tuple(imgpts[i]), tuple(imgpts[j]),(255),3) # draw top layer in red color img = cv2.drawContours(img, [imgpts[4:]],-1,(0,0,255),3) return img
Puntos de eje modificados. Son las 8 esquinas de un cubo en el espacio 3D:
axis = np.float32([[0,0,0], [0,3,0], [3,3,0], [3,0,0], [0,0,-3],[0,3,-3],[3,3,-3],[3,0,-3] ])
Si estás interesado en gráficos, realidad aumentada, etc., puedes usar OpenGL para mostrar figuras más complicadas.
Enhorabuena, continua con nosotros. Únete a nuestro curso Python de OpenCV
y aprende mucho mas de temas similares:
[…] ➡ Pose Estimación o coordenadas 3D de angulos […]
Necesito a una persona que me ayude a corregir una aplicación de estimación de pose es un estudio sobre pacientes de alzheiemer