Opencv实验合集——实验九:姿势估计

发布时间:2024年01月09日

在上一章节(相机校准),你已经找到了相机矩阵,畸变系数等等参数。给出一个图案图像,我们便可以利用上面的信息用于计算其姿势,或者物体在空间中位于何处,比如如何旋转,如何移动等等问题。对于一个平面物体,我们可以假定 Z = 0,这样,问题现在便转化为了如何放置摄像机才能查看到我们的图案图像。所以如果我们知道物体在空间中的位置,我们便可以绘制一些 2D 图像用以模拟 3D 效果。

我们的问题是,我们想在我们棋盘的第一个角上绘制 3D 坐标系(x, y, z 坐标系),其中 X 轴是蓝色,Y 轴是绿色,Z 轴是红色。所以从效果上讲,Z 轴应该感觉像是与棋盘垂直的。

1.定义

姿势估计是指通过分析图像或传感器数据来推断物体、人体或相机在三维空间中的姿势,即位置和方向。姿势通常由平移和旋转两个主要组成部分构成。

2.有关的函数方法

本节与上一个实验密切相关,重复的方法就不再一一赘述了

cv2.projectPoints 函数是 OpenCV 中用于将 3D 点投影到图像平面的函数。它是摄像机标定和相机投影中常用的一个函数。该函数的签名如下:

cv2.projectPoints(objectPoints, rvec, tvec, cameraMatrix, distCoeffs[, imagePoints[, jacobian[, aspectRatio]]]) → imagePoints, jacobian

  • objectPoints: 三维物体点的坐标,是一个 numpy 数组,形状为 (N, 3),N 是点的数量。
  • rvec: 旋转向量,描述了物体坐标系相对于相机坐标系的旋转。是一个长度为 3 的 numpy 数组。
  • tvec: 平移向量,描述了物体坐标系相对于相机坐标系的平移。是一个长度为 3 的 numpy 数组。
  • cameraMatrix: 相机内参矩阵,是一个 3x3 的矩阵。
  • distCoeffs: 相机的畸变系数,是一个包含畸变参数的 numpy 数组。
  • imagePoints (可选): 输出参数,是一个 numpy 数组,包含了三维点在图像平面上的投影坐标。
  • jacobian (可选): 输出参数,是一个 numpy 数组,包含了投影函数的导数信息。
  • aspectRatio (可选): 相机的纵横比,即图像的宽高比。

3.代码演示

首先我们先在棋盘上的三个点上建立三角坐标系XYZ,通过绘图进行展示,上个实验已经讲述了如何从世界坐标系转化相机坐标系,获得一系列参数(旋转,平移参数等),如何通过转化成相机坐标系再通过方法将3D点投影到图像平面上。

import numpy as np
import cv2 as cv
import glob

# 终止标准
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)

# 准备对象点, 如 (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
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)
#axis是世界坐标系中的三个点,用来绘制图像上的相机坐标系

# 用于存储所有图像对象点与图像点的矩阵
objpoints = [] # 在真实世界中的 3d 点
imgpoints = [] # 在图像平面中的 2d 点

# images = glob.glob('*.jpg')
images = [r'C:\Users\xiaoou\Desktop\picture\chess.jpg']
def draw(img, corners, imgpts):#在一个角点上建立相机平面坐标系
    corner = tuple(corners[0].ravel())#在检测的众多角点中随机抽取一个
    img = cv.line(img, np.int32(corner), np.int32(tuple(imgpts[0].ravel())), (255,0,0), 5)
    img = cv.line(img, np.int32(corner), np.int32(tuple(imgpts[1].ravel())), (0,255,0), 5)
    img = cv.line(img, np.int32(corner), np.int32(tuple(imgpts[2].ravel())), (0,0,255), 5)
    return img

for fname in images:
    img = cv.imread(fname)
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

    # 找到棋盘上所有的角点
    ret, corners = cv.findChessboardCorners(gray, (7,6), None)

    # 如果找到了,便添加对象点和图像点(在细化后)
    if ret == True:
        objpoints.append(objp)

        corners2 = cv.cornerSubPix(gray,corners, (11,11), (-1,-1), criteria)
        imgpoints.append(corners)
        # 绘制角点
        # cv.drawChessboardCorners(img, (7,6), corners2, ret)

        ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
        imgpts, jac = cv.projectPoints(axis,rvecs[0],tvecs[0],mtx,dist)
        img = draw(img, corners2, imgpts)

        cv.imshow('img', img)

        cv.waitKey(0)

现在把投影的点扩大为8个,构成一个长方体,绘制底部为绿色,顶部为红色,来让姿势估计更加具体。

import numpy as np
import cv2 as cv
import glob

# 终止标准
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)

# 准备对象点, 如 (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)
axis = np.float32([ [0,0,0], [0,1,0], [1,1,0], [1,0,0],
                   [0,0,-1],[0,1,-1],[1,1,-1],[1,0,-1] ])

# 用于存储所有图像对象点与图像点的矩阵
objpoints = [] # 在真实世界中的 3d 点
imgpoints = [] # 在图像平面中的 2d 点

images = [r'C:\Users\xiaoou\Desktop\picture\chess.jpg']

def cube_draw(img, imgpts):#对8个平面的点建立相连建立一个长方体
    imgpts = np.int32(imgpts).reshape(-1,2)
    # 将底面绘制为绿色
    img = cv.drawContours(img, [imgpts[:4]], -1, (0,255,0), -3)
    # 将支柱绘制为蓝色
    for i,j in zip(range(4), range(4,8)):
        img = cv.line(img,tuple(imgpts[i]), tuple(imgpts[j]), (255,0,0), 3)
    # 将顶面绘制为红色
    img = cv.drawContours(img, [imgpts[4:]], -1, (0,0,255), 3)
    return img
for fname in images:
    img = cv.imread(fname)
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

    # 找到棋盘上所有的角点
    ret, corners = cv.findChessboardCorners(gray, (7,6), None)

    # 如果找到了,便添加对象点和图像点(在细化后)
    if ret == True:
        objpoints.append(objp)

        corners2 = cv.cornerSubPix(gray,corners, (11,11), (-1,-1), criteria)
        imgpoints.append(corners)

        ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
        imgpts, jac = cv.projectPoints(axis,rvecs[0],tvecs[0],mtx,dist)
        img = cube_draw(img, imgpts)

        cv.imshow('img', img)

        cv.waitKey(0)

?本次实验主要演示了三维重建中的姿势估计,主要通过将世界坐标系中的目标点转化为平面中的投影点,以此用来估计目标点在平面上的形状。

如有错误或遗漏,希望小伙伴批评指正!!!!?

希望这篇博客对你有帮助!!!!

实验八:Opencv实验合集——实验八:相机校准-CSDN博客

文章来源:https://blog.csdn.net/newxiaoou/article/details/135487609
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。