Python usa opencv para la calibración de la cámara (versión completa)

Mi blog: el blog de usg

Las cámaras de una sola apertura de bajo precio de hoy en día (cámaras) introducen mucha distorsión en la imagen. Hay dos
tipos principales de distorsión: distorsión radial y distorsión tangencial. Como se muestra en la figura a continuación, marque los dos lados del tablero de ajedrez con una línea recta roja,
pero encontrará que el borde del tablero de ajedrez no coincide con la línea roja. Todo lo que pensábamos que debería ser una línea recta también se abulta
.

En aplicaciones relacionadas con 3D, primero se deben corregir estas distorsiones. Para encontrar estos parámetros de corrección, debemos
proporcionar algunas imágenes de muestra que contengan patrones de patrones obvios (como un tablero de ajedrez). Podemos encontrar algunos puntos especiales en él
(como las cuatro esquinas del tablero de ajedrez). Averiguamos dónde están estos puntos particulares en la imagen y
dónde están realmente. Con esta información, podemos usar métodos matemáticos para resolver el coeficiente de distorsión. Ese
es el resumen de toda la historia. Para obtener mejores resultados, necesitamos al menos 10
patrones de este tipo.

Pasos de implementación

Tome un diagrama de tablero de ajedrez

Primero imprima la imagen a continuación: descargue o guarde directamente

Fíjelo en un avión y use la cámara para tomar (10-20) fotografías de calibración desde diferentes ángulos y posiciones. Algo como esto:

Python llama al código de la cámara de la cámara opencv (ejemplo):

import cv2
camera=cv2.VideoCapture(0)
i = 0
while 1:
    (grabbed, img) = camera.read()
    cv2.imshow('img',img)
    if cv2.waitKey(1) & 0xFF == ord('j'):  # 按j保存一张图片
        i += 1
        u = str(i)
        firename=str('./img'+u+'.jpg')
        cv2.imwrite(firename, img)
        print('写入:',firename)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

Presione jpara tomar fotos, se guardarán en lotes en secuencia, presione qpara salir del programa.


Encuentre el tablero de ajedrez y calibre + vea los resultados calibrados

Usa opencv para encontrar el tablero de ajedrez

Para encontrar el patrón del tablero de ajedrez, usamos la función cv2.findChessboardCorners().
También necesitamos pasar el tipo de patrón, como cuadrícula de 8x8 o cuadrícula de 5x5, etc. En este ejemplo
usamos una cuadrícula de 9x6. (Por lo general, el tablero es de 8x8 o 7x7). Devolverá
las esquinas, y el tipo de retorno (Retval) será True si se obtiene una imagen. Estos puntos de las esquinas se
organizarán en orden (de izquierda a derecha, de arriba a abajo)

Es posible que esta función no encuentre patrones que deberían estar presentes en todas las imágenes. Entonces, un buen enfoque es escribir
un código que encienda la cámara y verifique cada cuadro en busca del patrón esperado. Después de obtener el patrón, necesitamos encontrar las esquinas y guardarlas como una lista. Establezca un cierto intervalo antes de leer el siguiente cuadro de imagen, de modo que tengamos suficiente tiempo para ajustar la dirección del tablero de ajedrez. Continúe este proceso hasta que obtenga suficientes patrones buenos. Incluso si tomamos este ejemplo, no sabemos cuántas de las 14 imágenes son buenas. Así que tenemos que leer cada imagen y encontrar una buena.

En lugar de usar un tablero de ajedrez, también podemos usar una cuadrícula circular, pero use la función
cv2.findCirclesGrid() para encontrar el patrón. Se dice que solo
se requiere una pequeña cantidad de imágenes para usar la cuadrícula circular.

Después de encontrar estas esquinas, podemos usar la función cv2.cornerSubPix() para aumentar la precisión
. Dibujamos los patrones usando la función cv2.drawChessboardCorners(). Todos estos
pasos están incluidos en el siguiente código:

calibración

Después de obtener estos puntos de objeto y puntos de imagen, estamos listos para realizar la calibración de la cámara.
La función que vamos a utilizar es cv2.calibrateCamera(). Devuelve la matriz de la cámara,
los coeficientes de distorsión, los vectores de rotación y transformación, etc.

Corrección de distorsión

Ahora que tenemos lo que queremos, podemos encontrar una imagen para corregirlo
. OpenCV proporciona dos métodos, aprendamos sobre ellos. Pero antes podemos optimizar la matriz de la cámara usando
el factor de escala libre obtenido de la función cv2.getOptimalNewCameraMatrix() .
Si el factor de escala alfa = 0, la imagen devuelta sin distorsión tendrá una cantidad mínima
de píxeles no deseados. Incluso es posible eliminar algunos píxeles en las esquinas de la imagen. Si alfa = 1,
se devolverán todos los píxeles y algunas imágenes en negro. También devuelve una imagen de ROI que podemos
usar para recortar el resultado.

El parámetro en función: cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h), 1,(w,h)) 1es un hoyo,

Aquí usamos cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h), 0,(w,h)) Los parámetros se establecen en0

distorsionado a no distorsionado

En el siguiente código

  • La imagen dst1 usa cv2.undistort(), que es la forma más fácil. Simplemente use esta función y el ROI obtenido arriba para recortar el resultado

  • La imagen dst2 usa reasignación, que debería pertenecer a la "curva para salvar el país". Primero tenemos que encontrar la ecuación de mapeo de la imagen distorsionada a la imagen no distorsionada. Luego usa la ecuación de reasignación. (uso detallado en el código)

Los dos efectos pueden ser comparados por ti mismo.

Comparación antes y después de la corrección:

error de retroproyección

Podemos usar el error de retroproyección para estimar la precisión de los parámetros que encontramos.
Cuanto más cerca esté el resultado de 0, mejor. Con parámetros internos, parámetros de distorsión y matriz de transformación de rotación, podemos usar
cv2.projectPoints() para convertir puntos de objeto en puntos de imagen. Luego se puede calcular la transformación para obtener
la diferencia absoluta entre la imagen y el algoritmo de detección de esquinas. Luego calculamos el promedio de los errores sobre todas las imágenes de calibración.

(Pero este artículo no lo necesita, por lo que no está escrito)

código principal

Bibliotecas requeridas:opencv-python numpy glob

import cv2
import numpy as np
import glob



# 找棋盘格角点
# 设置寻找亚像素角点的参数,采用的停止准则是最大循环次数30和最大误差容限0.001
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) # 阈值
#棋盘格模板规格
w = 9   # 10 - 1
h = 6   # 7  - 1
# 世界坐标系中的棋盘格点,例如(0,0,0), (1,0,0), (2,0,0) ....,(8,5,0),去掉Z坐标,记为二维矩阵
objp = np.zeros((w*h,3), np.float32)
objp[:,:2] = np.mgrid[0:w,0:h].T.reshape(-1,2)
objp = objp*18.1  # 18.1 mm

# 储存棋盘格角点的世界坐标和图像坐标对
objpoints = [] # 在世界坐标系中的三维点
imgpoints = [] # 在图像平面的二维点
#加载pic文件夹下所有的jpg图像
images = glob.glob('./*.jpg')  #   拍摄的十几张棋盘图片所在目录

i=0
for fname in images:

    img = cv2.imread(fname)
    # 获取画面中心点
    #获取图像的长宽
    h1, w1 = img.shape[0], img.shape[1]
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    u, v = img.shape[:2]
    # 找到棋盘格角点
    ret, corners = cv2.findChessboardCorners(gray, (w,h),None)
    # 如果找到足够点对,将其存储起来
    if ret == True:
        print("i:", i)
        i = i+1
        # 在原角点的基础上寻找亚像素角点
        cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
        #追加进入世界三维点和平面二维点中
        objpoints.append(objp)
        imgpoints.append(corners)
        # 将角点在图像上显示
        cv2.drawChessboardCorners(img, (w,h), corners, ret)
        cv2.namedWindow('findCorners', cv2.WINDOW_NORMAL)
        cv2.resizeWindow('findCorners', 640, 480)
        cv2.imshow('findCorners',img)
        cv2.waitKey(200)
cv2.destroyAllWindows()
#%% 标定
print('正在计算')
#标定
ret, mtx, dist, rvecs, tvecs = \
    cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)


print("ret:",ret  )
print("mtx:\n",mtx)      # 内参数矩阵
print("dist畸变值:\n",dist   )   # 畸变系数   distortion cofficients = (k_1,k_2,p_1,p_2,k_3)
print("rvecs旋转(向量)外参:\n",rvecs)   # 旋转向量  # 外参数
print("tvecs平移(向量)外参:\n",tvecs  )  # 平移向量  # 外参数
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (u, v), 0, (u, v))
print('newcameramtx外参',newcameramtx)
#打开摄像机
camera=cv2.VideoCapture(0)
while True:
    (grabbed,frame)=camera.read()
    h1, w1 = frame.shape[:2]
    newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (u, v), 0, (u, v))
    # 纠正畸变
    dst1 = cv2.undistort(frame, mtx, dist, None, newcameramtx)
    #dst2 = cv2.undistort(frame, mtx, dist, None, newcameramtx)
    mapx,mapy=cv2.initUndistortRectifyMap(mtx,dist,None,newcameramtx,(w1,h1),5)
    dst2=cv2.remap(frame,mapx,mapy,cv2.INTER_LINEAR)
    # 裁剪图像,输出纠正畸变以后的图片
    x, y, w1, h1 = roi
    dst1 = dst1[y:y + h1, x:x + w1]

    #cv2.imshow('frame',dst2)
    #cv2.imshow('dst1',dst1)
    cv2.imshow('dst2', dst2)
    if cv2.waitKey(1) & 0xFF == ord('q'):  # 按q保存一张图片
        cv2.imwrite("../u4/frame.jpg", dst1)
        break

camera.release()
cv2.destroyAllWindows()


Coloque el código en la misma carpeta que la imagen y ejecútelo directamente

Comparación de efectos

Antes y después de la corrección:


Calibración de cámara completada~

Supongo que te gusta

Origin blog.csdn.net/dgut_guangdian/article/details/107467070
Recomendado
Clasificación