python - 使用 OpenCV (solvePnP+projectPoints) 绘制棋盘格用于姿势估计的引用框架

标签 python opencv computer-vision

我已按照 https://docs.opencv.org/master/d7/d53/tutorial_py_pose.html 上的教程进行操作基于在 https://docs.opencv.org/master/dc/dbb/tutorial_py_calibration.html 上的教程获得的校准数据.

最终目标是获得棋盘相对于相机的姿势,但首先我试图绘制棋盘的引用框架。

输入数据是一组 2 个快照,我拍摄的网络摄像头提要指向打印的 10x7 棋盘格。

校准似乎成功了:
enter image description here
enter image description here
但是输出是完全错误的:
enter image description here
enter image description here
这是修补后的代码:

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

用于校准和处理的图像是相同的,应该会产生良好的结果。怎么了?

原始图像如下,以防您可能想要重现该行为:
enter image description here
enter image description here

编辑:我已经测试逐帧打开我的网络摄像头并以不同的方向处理 30-40 帧(以 2 FPS)而不是 2 帧以获得更多数据,但引用帧仍然完全不正确地绘制和 校准的 RMS 误差显然是 ~100 .改进后的代码可见here .怎么了?

最佳答案

获得 100 像素 RMS 误差意味着您的校准非常错误。

您的图像显示的目标不是很平坦,并且有些模糊。

建议您关注these guidelines .

关于python - 使用 OpenCV (solvePnP+projectPoints) 绘制棋盘格用于姿势估计的引用框架,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61174530/

相关文章:

python - 深度优先搜索中的每个图成员包含2个符号python

python - 每秒提取文件夹中所有视频的帧

python - 有效地使用 Numpy 将函数值分配给数组

opencv - 我可以指定使用 opencv FastFeatureDetector 时获得的 FAST 关键点编号吗

opencv - 2D坐标到3D世界坐标

python - 我如何使这么长的 if 语句不那么麻烦?

c++ - 使用 c++ api 访问 cv::Mat 中的元素 (x,y)

python - Python OpenCV ORB 图像对齐的掩码问题

opencv - 如何使用scipy.misc.resize用负数调整 'image'的大小?

image-processing - 如何对单个图像执行分水岭分割和 Blob 分析?