pose3d部署记录(按尝试流程进行记录)
本文最后更新于 840 天前,其中的信息可能已经有所发展或是发生改变。

Github:https://github.com/SwathiSheshadri/pose3d

观前提示:该文始作于2022.9.14,因此可能会和最新版本有所差异;

一、运行pose3d demo

没学过Matlab,概率论也忘得差不多了,纯粹走一步查一步,和我一样的如果遇到什么问题可以看看;

将Github的文档部署到Matlab后,记得将当前目录设置为主文件夹,否则无法运行demo;

之后需要修改demo_DLC2d_plotter.m里的multcompare函数,设置第二个参数也就是ALPHA参数(显著性水平),一般取0.05(也就是1-置信水平),然后就可以运行demo了;

二、摄像头标定

组里给我的是两个intel realsense D435双目深度摄像头,必须要用USB3.0及以上版本的接口才能使用;

这俩货可以去https://github.com/IntelRealSense下载对应的软件(Intel.RealSense.Viewer.exe和Intel.RealSense.SDK-WIN10-X.XX.X.XXXX.exe,如果是WINDOWS的话);

接下来是几个疑问的解答:

1.摄像头标定是什么、为什么?

对于单目摄像头而言,拍摄到的图片只是一张平面的像素点集合,并且会产生不同程度的畸变,而标定就是通过求摄像头的各类参数从而在后面图像处理时通过这些参数进行反畸变;

2.摄像头的参数是什么(这段来源于网络,没找到出处)?

1)相机矩阵:包括焦距(fx,fy),光学中心(Cx,Cy),完全取决于相机本身,是相机的固有属性,只需要计算一次,可用矩阵表示如下:[fx,0,Cx;0,fy,cy;0,0,1];

2)畸变系数:畸变数学模型的5个参数 D=(k1,k2,P1,P2,k3);

3)相机内参:相机矩阵和畸变系数统称为相机内参,在不考虑畸变的时候,相机矩阵也会被称为相机内参;

4)相机外参:通过旋转和平移变换将3D的坐标转换为相机2维的坐标,其中的旋转矩阵和平移矩阵就被称为相机的外参;描述的是将世界坐标系转换成相机坐标系的过程;

3.摄像头标定的原理是什么?

1)首先要知道四个坐标系:

①世界坐标系(描述物体真实位置)

②相机坐标系(摄像头镜头中心)

③图像坐标系(图像传感器成像中心,图片中心,影布中心,单位mm)

④像素坐标系(图像左上角为原点,描述像素的位置,单位是多少行,多少列)

2)坐标系的三次转化过程:

①世界坐标系 ⇒ 相机坐标系:求解摄像头外参(旋转和平移矩阵)

②相机坐标系 ⇒ 图像坐标系:求解相机内参(摄像头矩阵和畸变系数)

③图像坐标系 ⇒ 像素坐标系:求解像素转化矩阵(可简单理解为原点从图片中心到左上角,单位厘米变行列)

3)在四种坐标系的三次转化过程中即可求得摄像头的参数


好了,接下来要尝试实际标定了,标定的方法和工具有很多种,这是使用的是相较比较常用的张氏标定法以及Matlab上的校准工具,详细流程可参见Matlab官方教程(https://ww2.mathworks.cn/help/vision/ug/single-camera-calibrator-app.html?#bt19jdq-1),这里只作文字版说明;

首先需要的是一张标定棋盘格,在Matlab的命令行窗口输入open checkerboardPattern.pdf即可打开,将之用硬板纸打印,如果没有白色硬板纸也可以使用普通打印纸固定在硬板上,A4或A3大小即可;

标定分为单摄像头标定和双摄像头标定,前者使用Matlab上的APP→图像处理和计算机视觉→Camera Calibration,后者则使用Stereo Camera Calibration,二者操作流程相近,这里只表述后者;

将两个摄像头根据使用需求放置,之后二者的相对位置和朝向将无法改变,否则则将重新标定,无特别需求的情况下推荐平行放置以便于标定;

使用Intel RealSense Viewer或自己写的程序(推荐后者,前者用起来很麻烦)拍摄30组棋盘格的照片,拍摄过程中不同角度地倾斜棋盘格(这里理论上3组即可,为了精确最好是30-50组,甚至有些博文要求100组),左右(主从)摄像头照片按拍摄顺序分别排列在两个文件夹内;

打开Stereo Camera Calibration,选择Add Images,分别选择左右摄像头照片存储的文件夹,并输入棋盘格中每个格子的大小(注意单位,Matlab提供的棋盘格在A4打印的情况下应该是2cm);

在上方的OPTIONS选项卡中Radial Distortion(径向畸变)选择3 Coefficients(系数),Compute中将Skew(扭曲)和Tangential Distortion(切向畸变)都勾上,点击Calibrate开始标定;

在标定输出的柱状图中找到误差较大的照片组将之删除,然后进行重新标定;

选择Export Camera Parameters将摄像头参数进行输出;

到此为止双摄像头的标定就结束了;

三、录像

接下来我们需要一组视频,即左右(主从)摄像头对目标物体同时进行拍摄,这里同样有很多方法,我给出两种:

1.Intel RealSense Viewer自带的录制功能(不推荐)

开启两个摄像头的RGB输出模式,同时点击两个Record,获得.bag文件,然后使用Intel自带的转换工具(前面下载的SDK中自带,可以看这篇,windows同操作:https://github.com/IntelRealSense/librealsense/issues/10623)将bag文件转化为N张视频帧,再用PR等工具将视频帧合成视频;

2.自己写一个录制视频的程序

需要两个摄像头同时录制,以下给出代码,其中Python版有一点点小问题,C++版配置OpenCV相对python复杂了那么“一点点”;

C++版:

#include<opencv.hpp>  
using namespace cv;
int main()
{
	VideoCapture cap(2);
	VideoCapture capcap(1);
	Mat frame;
	Mat frame2;
	if (!capcap.isOpened())return 0;
	if (!cap.isOpened())return 0;
	VideoWriter writerleft("E:/left.mp4", cv::VideoWriter::fourcc('m', 'p','4','v'),30.0, Size(640, 480));
	VideoWriter writerright("E:/right.mp4", cv::VideoWriter::fourcc('m', 'p', '4', 'v'), 30.0, Size(640, 480));
	while (1)
	{
		capcap >> frame2;
		cap >> frame;
		writerright << frame;
		writerleft << frame2;
		if (!frame2.empty() && !frame.empty())
		{
			imshow("摄像头右", frame);
			imshow("摄像头左", frame2);
			if (waitKey(30) == 27)
			{
				destroyAllWindows();
				break;
			}
		}
		else
			break;
	}
	capcap.release();
	cap.release();
	return 0;
}

其中需要注意的是VideoCapture不一定是0、1或者1、2,需要根据自己电脑USB摄像头进行调整,一开始0、1一直return非0发现不是0;

Python版:

import cv2

capl = cv2.VideoCapture(1,cv2.CAP_DSHOW)
capr = cv2.VideoCapture(2,cv2.CAP_DSHOW)
width = 640
height = 480

fourcc = cv2.VideoWriter_fourcc(*'mp4v')

outl = cv2.VideoWriter('leftx.mp4', fourcc, 30.0, (width, height))
outr = cv2.VideoWriter('rightx.mp4', fourcc, 30.0, (width, height))
while capl.isOpened() and capr.isOpened():
    retl, framel = capl.read()
    retr, framer = capr.read()
    if retl is True and retr is True:
        outl.write(framel)
        outr.write(framer)
        cv2.imshow('framel', framel)
        cv2.imshow('framer', framer)
    else:
        break

    key = cv2.waitKey(1)
    if key == ord('q'):
        break

capl.release()
outl.release()
capr.release()
outr.release()
cv2.destroyAllWindows()

同样地要根据自己摄像头更变VideoCapture参数,对比C++版很奇怪的一点是录出来的视频会被慢放(如果只开单个摄像头是正常速度),而将帧数从30改为60后又正常了,没想通为啥帧数会影响速度;

四、Deeplabcut提取特征点

打开DLC,在Manage Project处选择视频,点击Edit config file在bodyparts处输入各特征点的名称;

这里要注意的是文件名以及里面的文本内容不要出现中文或中文符号,否则后面会报奇奇怪怪的错;

Extract Frames处点OK即可(如果没有什么特别要设置的话),之后即和上一篇文章一样在Label Data中进行标记,这里就不赘述了;

之后很长的一段步骤都是在DLC进行,同样地,下文相关部分只写标题不进行具体的阐述,具体可见另一篇DeepLabCut使用记录

五、创建训练数据集

六、训练

七、评估

八、分析视频

OK,到这一步为止我们就已经在videos文件夹里得到训练后的csv以及标记视频了;

九、pose3d配置

最恶心的一步来的。首先我对开源代码提供者表示崇高的敬意,其次这代码确实有一些BUG或者说注释有点误导人。代码部分需要根据自己的实际使用情况做一些微调,很多问题都是因为配置文件不够全面以及注释有误导致适应性不是很好;

接下来对需要变更的注释项进行逐一讲解:

exp_path:可以理解为matlab工作文件夹下的总工程文件夹所在位置,填文件夹名字或绝对路径,同一组标定数据的情况下使用同一个exp_path;

exp_name:即exp_path文件夹下工程文件夹位置,只需要填文件夹名字即可;

此外配置文件里说的不是很清晰的一点是,exp_path文件夹下应当有1+N个文件夹,1指的是CalibSessionFiles文件夹下,里面含PrimarySecondary1至PrimarySecondaryX文件夹,其中X表示摄像头个数,每个文件夹里应当有个calibrationSession.mat标定文件,分别是各个摄像头的标定参数,但是如果你拿到的不是你直接标定的数据,则可能标定文件里面的参数格式和pose3d要求的不一样,则需要对pose3d的代码做修改以适应,或者修改mat文件以适应;N指的即是exp_name文件夹,他们共享CalibSessionFiles里的标定数据(即同一组摄像头拍摄的不同实验);

举个例子,pose3d代码里要求的是各个摄像头参数分别用一个标定文件表示,而我现在拿到的mat标定文件是所有摄像头组合在一起的,则我们需要进行归约。我们可以在pose3d代码中看到其中有一大串代码就是在合成各个摄像头标定数据,所以方法一就是将这串代码注释掉,然后将我们已有的标定参数赋值给目标变量,方法二则是把calibrationSession.mat里的3维数组(我不清楚matlab如何形容这个概念)中的第三维拆分成X个二维数据并分别保存在PrimarySecondary1至PrimarySecondaryX文件夹里;

因为这里每个人情况不同,所以很难以统一化的语言阐述清楚,只能视情况修改;

usingdlc:顾名思义,使用dlc生成csv文件的为1,否则为0,这里主要是对csv文件内格式进行规范;

modes_3drecon:没有特殊要求的话直接all就行;

nfeatures:特征点个数,就是DLC标记时的标记点数;

ncams:摄像头个数;

primary2D_datafullpath:主摄像头拍摄的视频经过DLC视频分析后生成的CSV文件所在位置,填写相对路径,其上一级路径为exp_name;

secondary2D_datafullpath:所有副摄像头拍摄的视频经过DLC视频分析后生成的CSV文件所在位置,如有多个则写成数组形式,填写相对路径,其上一级路径为exp_name;

接下来的一串参数都是和使用pose3d来获取标定参数有关,对于已经有标定文件的人而言可以直接注释,相对应的,需要注释下面用到过这些参数的函数;

nframes:标记视频(即分析视频后生成的视频)的总帧数,通常为fps*秒数,同时也是训练后生成的标记CSV文件里去掉表头的数据行数,当需要输出3D动画时不需要填写此项(即plotresults=1时),因为之后需要填写标记视频位置然后自动读取帧数;

have2Dtrackedvideos or have2Dtrackedimages:当plotresults为1时二者必须其一为1,否则皆为0,即训练后分析生成的视频/图片;

path_to_2Dtracked_video or path2Dtrackedimages_folder:即训练后分析生成的视频/图片所在位置,二者根据上述前二者参数相应填写即可;

nskip:即后续处理中每nskip帧处理一次数据,通常为1,当视频特别大时可以根据情况放大;

接下来的三个参数通常不用管,根据实际参数调整即可;

drawline:生成3D动画时点与点之间的连线,从1开始计数,每个值表示DLC配置文件里各特征点按序排列,格式注释中有参照;

十、完结运行与后言

到这里为止配置文件部分就可以结束了,之后根据标定文件的格式以及有否需要对代码做出一定的修改,这份开源代码的最大问题就在于它把标定部分整合进代码里了,而不同人对标定有不同的需要,这里它又没有对标定部分在配置文件中做一个比较好的设定,所以可能会导致一系列的BUG发生;

十一、旋转校正

没想到吧,在BeA之前还有一步哈哈哈哈,等搞完/搞到这代码在完善这部分内容;

上一篇
下一篇