我已按照 https://docs.opencv.org/master/d7/d53/tutorial_py_pose.html 上的教程进行操作基于在 https://docs.opencv.org/master/dc/dbb/tutorial_py_calibration.html 上的教程获得的校准数据.
最终目标是获得棋盘相对于相机的姿势,但首先我试图绘制棋盘的引用框架。
输入数据是一组 2 个快照,我拍摄的网络摄像头提要指向打印的 10x7 棋盘格。
校准似乎成功了:
但是输出是完全错误的:
这是修补后的代码:
import cv2 as cv
import numpy as np
import glob
import argparse
# algorithm parameters
CHECKERBOARD_WIDTH = 9
CHECKERBOARD_HEIGHT = 6
# termination criteria
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)
#=== CALIBRATE CAMERA ============================================================================
#Prepare object points
objp = np.zeros((CHECKERBOARD_HEIGHT * CHECKERBOARD_WIDTH, 3), np.float32)
objp[:,:2] = np.mgrid[0:CHECKERBOARD_HEIGHT, 0:CHECKERBOARD_WIDTH].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.
# Load the images
ap = argparse.ArgumentParser()
ap.add_argument('-f', '--folder', required=True, help='Path to the images folder with last slash')
ap.add_argument('-e', '--ext', required=True, help='Extension of image files without the dot')
args = vars(ap.parse_args())
images = glob.glob(args['folder']+'*.'+args['ext'])
#Process the images
for fname in images:
print('Calibrating on '+fname)
img = cv.imread(fname)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# Find the chess board corners
ret, corners = cv.findChessboardCorners(gray, (CHECKERBOARD_WIDTH,CHECKERBOARD_HEIGHT), None)
# If found, add object points, image points (after refining them)
if ret == True:
print('Found corners')
objpoints.append(objp)
corners2 = cv.cornerSubPix(gray,corners, (11,11), (-1,-1), criteria)
imgpoints.append(corners)
# Draw and display the corners as feedback to the user
cv.drawChessboardCorners(img, (CHECKERBOARD_WIDTH,CHECKERBOARD_HEIGHT), corners2, ret)
cv.imshow('Calibration', img)
k = cv.waitKey(0) & 0xFF
if k == ord('s'):
cv.imwrite(fname+'_calib.png', img)
cv.destroyAllWindows()
#Obtain camera parameters
ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
#=== FIND POSE OF TARGETS ===========================================================================
#Prepare object points
objp = np.zeros((CHECKERBOARD_HEIGHT * CHECKERBOARD_WIDTH, 3), np.float32)
objp[:,:2] = np.mgrid[0:CHECKERBOARD_HEIGHT, 0:CHECKERBOARD_WIDTH].T.reshape(-1,2)
axis = np.float32([[3,0,0], [0,3,0], [0,0,-3]]).reshape(-1,3)
#Display
def draw(img, corners, imgpts):
corner = tuple(corners[0].ravel())
img = cv.line(img, corner, tuple(imgpts[0].ravel()), (255,0,0), 5)
img = cv.line(img, corner, tuple(imgpts[1].ravel()), (0,255,0), 5)
img = cv.line(img, corner, tuple(imgpts[2].ravel()), (0,0,255), 5)
return img
for fname in images:
print('Processing '+fname)
img = cv.imread(fname)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret, corners = cv.findChessboardCorners(gray, (CHECKERBOARD_WIDTH,CHECKERBOARD_HEIGHT), None)
if ret == True:
print('Found corners')
corners2 = cv.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
# Find the rotation and translation vectors.
ret,rvecs, tvecs = cv.solvePnP(objp, corners2, mtx, dist)
# project 3D points to image plane
imgpts, jac = cv.projectPoints(axis, rvecs, tvecs, mtx, dist)
img = draw(img,corners2,imgpts)
cv.imshow('img',img)
k = cv.waitKey(0) & 0xFF
if k == ord('s'):
cv.imwrite(fname+'_output.png', img)
cv.destroyAllWindows()
称为例如和:
python3 test_cvpnp.py --folder ./images/ --ext png
用于校准和处理的图像是相同的,应该会产生良好的结果。怎么了?
原始图像如下,以防您可能想要重现该行为:
编辑:我已经测试逐帧打开我的网络摄像头并以不同的方向处理 30-40 帧(以 2 FPS)而不是 2 帧以获得更多数据,但引用帧仍然完全不正确地绘制和 校准的 RMS 误差显然是 ~100 .改进后的代码可见here .怎么了?
最佳答案
获得 100 像素 RMS 误差意味着您的校准非常错误。
您的图像显示的目标不是很平坦,并且有些模糊。
建议您关注these guidelines .
关于python - 使用 OpenCV (solvePnP+projectPoints) 绘制棋盘格用于姿势估计的引用框架,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61174530/