Является ли фокусное расстояние в единицах пикселей линейным измерением

#camera #computer-vision #camera-calibration

#камера #компьютерное зрение #камера-калибровка

Вопрос:

У меня есть камера с панорамированием и зумом (фокусное расстояние меняется со временем). Нет представления о его базовом фокусном расстоянии (например, фокусном расстоянии в момент времени 0). Тем не менее, можно отслеживать изменение фокусного расстояния между кадром и другим на основе некоторых известных ограничений и предположений (выполнение SLAM).

Если я предполагаю случайное фокусное расстояние (в единицах пикселей), например, 1000 пикселей. Затем новые фокусные расстояния отслеживаются кадр за кадром. Получу ли я правильные результаты относительно? Будут ли результаты (фокусные расстояния) в каждом кадре корректными с точностью до масштаба основного фокусного расстояния?

Для панорамирования и наклона допустимым будет предположение, что 0 в начале. Хотя это неверно, оценочные значения нового кадра будут правильными с точностью до смещения. Однако я подозреваю, что расчетное фокусное расстояние не будет даже правильным с точностью до масштаба или смещения.. Это правильно или нет?

Ответ №1:

Для быстрого короткого ответа — если камера с поворотным зумом приближена к тонкой линзе, то это соотношение между расстоянием (z) и фокусным расстоянием (f):

введите описание изображения здесь

Это всего лишь приближение. Не совсем корректно. Для более точных расчетов см. Матрицу камеры. Фокусное расстояние является внутренним параметром матрицы камеры. Даже если оно неизвестно, его можно рассчитать, используя некоторые методы калибровки камеры, такие как DLT, метод Чжана и RANSAC. Если у вас есть матрица камеры, фокусное расстояние составляет лишь небольшую его часть. Вместе с этим вы получаете еще много полезных вещей.

OpenCV имеет встроенную реализацию метода Чжана. (Посмотрите на эту документацию для объяснений, но код старый и непригодный для использования. Новый обновленный код ниже.) Вам нужно сделать несколько снимков шахматной доски с помощью вашей камеры. Вот некоторый вспомогательный код:

 import cv2
from matplotlib import pyplot as plt
import numpy as np
from glob import glob
from scipy import linalg

x,y = np.meshgrid(range(6),range(8))

world_points=np.hstack((x.reshape(48,1),y.reshape(48,1),np.zeros((48,1)))).astype(np.float32)

_3d_points=[]
_2d_points=[]

img_paths=glob('./*.JPG') #get paths of all checkerboard images

for path in img_paths:
    im=cv2.imread(path)
    
    ret, corners = cv2.findChessboardCorners(im, (6,8))
    
    if ret: #add points only if checkerboard was correctly detected:
        _2d_points.append(corners) #append current 2D points
        _3d_points.append(world_points) #3D points are always the same


ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(_3d_points, _2d_points, (im.shape[1],im.shape[0]), None, None)

print ("Ret:n",ret)
print ("Mtx:n",mtx)
print ("Dist:n",dist)
  

Возможно, вам потребуется неискажение: коррекция радиального искажения

 # termination criteria
criteria = (cv2.TERM_CRITERIA_EPS   cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)

# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6*8,3), np.float32)
objp[:,:2] = np.mgrid[0:6,0:8].T.reshape(-1,2)

# Arrays to store object points and image points from all the images.
objpoints = [] # 3d point in real world space
imgpoints = [] # 2d points in image plane.

for fname in img_paths:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

    # Find the chess board corners
    ret, corners = cv2.findChessboardCorners(gray, (6,8),None)    
    
    # If found, add object points, image points (after refining them)
    if ret == True:
        objpoints.append(objp)

        cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
        imgpoints.append(corners)

    if 'IMG_5456.JPG' in fname:
        plt.figure(figsize=(20,10))
        img_vis=img.copy()
        cv2.drawChessboardCorners(img_vis, (6,8), corners, ret) 
        plt.imshow(img_vis)
        plt.show() 
  

введите описание изображения здесь

 #Calibration
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1],None,None)

# Reprojection Error
tot_error = 0
for i in range(len(objpoints)):
    imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
    error = cv2.norm(imgpoints[i],imgpoints2, cv2.NORM_L2)/len(imgpoints2)
    tot_error  = error

print ("Mean Reprojection error: ", tot_error/len(objpoints))

# undistort
mapx,mapy = cv2.initUndistortRectifyMap(mtx,dist,None,newcameramtx,(w,h),5)
dst = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
# crop the image
x,y,w,h = roi
dst = dst[y:y h, x:x w]
plt.figure(figsize=(20,10))
#cv2.drawChessboardCorners(dst, (6,8), corners, ret) 
plt.imshow(dst)
plt.show() 
  

введите описание изображения здесь

 # Reprojection Error
tot_error = 0
for i in range(len(objpoints)):
    imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
    error = cv2.norm(imgpoints[i],imgpoints2, cv2.NORM_L2)/len(imgpoints2)
    tot_error  = error

print ("Mean Reprojection error: ", tot_error/len(objpoints))
  

Комментарии:

1. Большое вам спасибо за ваш подробный ответ. Однако я не спрашивал о том, как найти это начальное фокусное расстояние, поскольку в моем случае это невозможно. Я спрашивал о том, как случайная оценка этого фокусного расстояния повлияет на весь путь отслеживания. Еще раз спасибо за ваши усилия!

2. @HumamHelfawi Простая оценка не сработает из-за обсуждаемых сложностей. и это не линейное отношение. Ваша интуиция верна, что расчетное фокусное расстояние будет неверным с точностью до масштаба или смещения. Люди используют калибровку камеры через матрицу камеры для SLAM. Это хороший блог kudan.io/archives/356

3. Спасибо. теперь у вас есть идея.