TI-Tintin-OPT8241二次开发和应用系列--Software Level

TI-Tintin-OPT8241二次开发和应用系列–Software Level

1.了解 VOXEL SDK 软件工程框架

详情参考:https://github.com/3dtof/voxelsdk/wiki/Voxel-SDK-Architecture

主要的三个模块

  1. Voxel Libraries

    主要作用是,一个处理对不同的深度相机系统获取的深度数据的上位机程序(有点拗口)包括数据交换、下载和上传,深度数据处理与现实等等。简而言之,这部分就是处理深度数据的上位机程序。TI主要是对自己生产的不同深度相机开发板定制的一个软件库。例如tintinOPT8241,OPT8320、haddockCamera、CalculusCamera等等深度相机。

  2. Configuration Files 主要作用是,文件中包含了深度相机系统的参数信息,深度相机链接上位机的时候,可以读取这个文件,让深度相机可以获取合适的参数配置。其中包括相机肚子的参数,相机共有的内参外参等标定系数等。

  3. Firmware Files 主要作用是,Firmware(固件)是烧写在深度相机开发板芯片上的文件。就像智能手机,它有它自己的固件。固件类似于,将程序编写好之后下载到单片机上,而这里的程序就是固件,往往这部分功能是作为系统的驱动层。不过,非常遗憾的是,除了1,2部分,这部分TI他们是不开源的。

了解 Voxel Libraries 架构

如上图所示,Voxel Libraries 主要有两个库组成:Voxel library、TI3DToF library,封装为libvoxel.so on Linux; libti3dtof.so on Linux 。 他们各自都有自己的namespace, Voxel:: 与 Voxel::TI:: ,TI3DToF library 继承 Voxel library 。

实线箭头表示继承关系;虚线箭头表示引用或者使用关系;虚框表示的是抽象类;实框表示的是实体类。抽象类只能被继承不能实体化,实体类可以继承也可以实体化。

因为文章的目的侧重是做应用开发,所以关于Voxel Libraries介绍,我讲个大概。

在Voxel library中,CameraSystem 是最主要的,许多其他类都要依赖他。主要作用是相机(不一定指深度相机)一些通用的参数配置。在这个基础上才会有DepthCamera类等一系列的深度相机设置。

继承Voxel library的TI3DToF library更加有针对性,虽然可以看到这个TI3DToF library里的类都是抽象类,没有实体类,但是这部分都是作为TI一系列DepthCamera所用的抽象公共类,将来要被具体tintinDepthCamera-CDK实体类继承。

关于Voxle Device Library 看到在这个Voxel Libraries构架图中,你会发现没有tintinDepthCamera-CDK的继承框图,这个图上没有画出它的继承关系。实际上,TintinCamera–OPT8241继承的是TOFtintinCamera与TOFCameraFactoryBase。

2.了解&安装 VOXEL SDK

安装教程详见:https://github.com/3dtof/voxelsdk/wiki#installation Linux or Windows ,建议选择linux - ubuntu 14.04 作为开发环境,因为后续一些应用只能在linux上展开。

下载 SDK Open-Source 包含以下主要的文件夹

  1. Voxel - the Core Voxel-SDK library
  2. TI3DToF - For TI’s depth camera support
  3. VoxelPCL - For Voxel-PCL integration
  4. App - For VoxelCLI and other apps
  5. Test - For individual test programs

文件夹的名称和关系基本与之前所介绍的Voxel Libraries对应。其他的,VoxelPCL这个整合了PCL的一个应用,主要用于PCL的三维点云显示。APP文件夹中主要包含两个应用程序,SimpleVoxelViewer and Voxel CLI 。SimpleVoxelViewer只是一个PCL显示;而Voxel CLI 即可以显示还可以做其他交互操作。

关于Voxel CLI 详见:https://github.com/3dtof/voxelsdk/wiki/Voxel-CLI

关于文件夹Test

可能是做开发时、调试时,留下的单独测试程序,我运行测试过,但是没有链接成功过 :_( 。但基本不会影响我的后续应用开发。

以下所openSource 中所有的Test子程序:

3.如何获取 depth data

连接设备之后,以Voxel CLI方式,可以保存的数据有:

  • RAW

  • Phase

  • Depth data

  • Ambient

  • Amplitude

  • Flags

  • PointCloud

  • Vxl

以上数据类型,主要可以分成四类: 对应wiki中的pipeline 详见: https://github.com/3dtof/voxelsdk/wiki/Voxel::DepthCamera

第一类 :Raw data

  • RAW
  • Phase

这里的Raw data 不管是有没有处理过的(processed)都是Raw data

第二类 :depthFrame

  • Depth data
  • Ambient
  • Amplitude
  • Flags

注意这里的depth data 不是depthFrame,一个 depthFrame 中包含以上4个数据类型信息。 depthFrame输出的数据格式已经向前在芯片资料中已经给出。

第三类 :PointCloudFrame

  • PointCloud

PointCloud点云数据,包含xyzi等3D数据信息,是由depthFrame通过像素坐标系转换世界坐标系得到的。

第四类: 用户(TI)自定义类型

  • Vxl

这部分是TI自定义数据类型,一个vxl的数据格式文件,里面可能同时包含depthFrame和PointCloudFrame。用户可以通过更改open source 程序得到自己想要的数据格式。

在open source 中的以下代码中可以更改

使用Tintin深度相机做应用,比较多用到的数据类型是depthFrame和PointCloudFrame,所以深刻认识这两个数据类型是应用开发的基础。在之后的内容中,会进一步介绍depthFrame和PointCloudFrame。

4.Depth data的认识与其应用

先来看一下,下图对于depth与PointCloud的定义:

右边是RGB采集的图像,左边是深度相机采集的深度图,亮度越亮表示距离越近,越暗的表示距离越远。

另外,深度图还可以被渲染成不同的RGB24颜色,颜色越暖越近,颜色越冷越远。 depth 表示的是相机与物体之间的距离,图示:

PointCloud 每个点包含xyz 信息,通常是由depth 数据得到,一个立体的图像是由无数多个点组成并呈现出来的。

depthFrame 的数据格式,用文本打开使用CLI保存的Depth 数据,你会发现,四个字节之间会有一定规律,是符合芯片说明中的4-ByteMode。

而且,在Open source 中也体现了,如图所示 :

所以说,每个DepthFrame其中包含了 amplitude 与 depth .

RGB Image 与 DepthFrame

RGB与Depth data本质区别—-RGB 像素的值代表颜色,depth data像素的值代表深度

RGB图片每个像素都有他自己的坐标,在一个像素坐标系表示,坐标分别用u,v 表示。每一点(u,v)的值表示该点的颜色,范围在0-255(RGB888)。一张有depth data构成的图片也适用于像素坐标系中,深度相机采集到的图像的坐标也是分别用u,v 表示,只不过每一点的值是相机与物体的距离,可以用(u,v,d)表示。同理,RGB图像每一点可以用(u,v,color)表示。

理解了RGB的数据格式,以及depth与RGB数据格式的区别之后,会发现他们的本质区别在于代表的含义不同。RGB与depth他们的数据都是相同的数字,只不过再通过一种规定的数据“格式”编码,并且用“工具”呈现出来罢了,其他两个是相同的,真正的不同在于代表的含义。可以用示意图表示:

(当时,我发现这点的时候,我想到了一个哲学范畴,每个人身上都具备相同“工具”——眼、耳、口、鼻、四肢等,但真正不同的是人的“数据含义”——思想,因为真正的思想不同,当用“工具”呈现时将是完全不同的意义,如果思想越先进,那么这个意义就越举足轻重。)

如何应用depth data做图像处理?

由于深度图像的(u,v,d)每个像素点表示物体与相机的距离,这里的d是一个float类型,打印输出的值就是距离,如下图所示:(某一点被检测物体的距离为:3.27979)。

因为深度图像上每一点上得到的信息是距离,所以在算法上我们可以将保留设置的距离范围内,滤除不必要的距离的物体。所以,处理深度图像相比RGB图像最大的优势在于,能够得到非常清晰的前后景分离的图像。

深度图像的算法处理

对于深度图像的算法处理,通常做法是: 1.前后景分离 2.转换成黑白图像 3.形态学处理 4.形状、形态分析 5.物体识别或跟踪

这里针对GITHUB上TI提供的“Demo-application–handTracking”程序作分析。

S1:前后景分离

1
2
3
4
5
6
7
8
9
10
11
void Jive::update(DepthFrame *frm)
{
DepthFrame hand;
vector< vector<cv::Point> > contours;
vector<Vec4i> hierarchy;
RNG rng(12345);
Mat gray;

// Create silhouette
clipBackground(*frm, hand);

分析:DepthFrame *frm作为clipBackground()的传入参数,得到深度数据帧。函数功能是分离背景,如何分离背景?再看:

关键在于这里for循环,这个函数有两个输出参数,但是第二个当做输出。在这个循环中,遍历深度数据帧frm(一个深度数据帧包括depth&amplitude,所以这里写in.amplitude.sieze()也可以),条件是:如果frm中像素深度值小于depthClip(是一个阈值,可以设置为1.2等,ampClip同理,范围在0-1)并且amplitude大于阈值,那么保留该点的深度值,并且push到新创建的DepthFrame hand的depth数据中,否则该点设置为0;下一个语句条件是:符合条件的,push到DepthFrame hand的amplitude数据中为1,否则该点的amplitude设置为0;

S2:转化成黑白图像,深度数据可视化

1
2
3
4
_binaryMat = Mat(hand.size.height, hand.size.width, CV_32FC1, hand.amplitude.data());  
_binaryMat.convertTo(gray, CV_8U, 255.0);//amplitude date 0~1
threshold(gray, gray, 200, 255, THRESH_BINARY);//to binary

分析:分离前后景之后,就可以通过OpenCV库创建一个Mat矩阵操作与显示(这里创建的Mat以hand中的amplituede的数据,也可以用depth,可以写为hand.depth.data());如果后面加上 imshow(“Binary”, _binaryMat);imshow(“Contours”, drawing); 显示的就是非常分离清晰的前后景图像;相比RGB相机通过帧差法分离前后景效果要好很多的。

S3:形态学处理,形状分析,物体跟踪等应用

程序中的处理方式如下,自行分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 findContours(gray, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0,0));
Mat drawing = Mat::zeros( gray.size(), CV_8UC3 );

int hands = 0;
if (contours.size() > 0) {

vector<int> hull, rhull;
vector<int> defect;
vector<int> tips;
cv::Point center = cv::Point(0,0);
float radius = 0;

for( int i = 0; i < contours.size(); i++ ) {
if (contourArea(contours[i]) > adjPix(1000)) {
hands++;
findPalmCenter(contours[i], center, radius);
float palm_depth = depthAt(*frm, center);
cv::circle(drawing, center, (int)radius, Scalar(0, 0, 255), 1);

findKeyPoints(contours[i], hull, defect, adjPix(15));
distillHullPoints(contours[i], hull, rhull, adjPix(10));
for (int k=0; k < rhull.size(); k++) {
if (k > 0)
cv::line(drawing, contours[i][rhull[k-1]], contours[i][rhull[k]], Scalar(255, 0, 0), 1);
}
#if 1
for (int k=0; k < defect.size(); k++)
cv::circle(drawing, contours[i][defect[k]], adjPix(3), Scalar(255, 0, 255), -1);
#endif
vector<int> temp;
vector<cv::Point> tips;
kCurvature(contours[i], rhull, adjPix(5), adjPix(25), 60.0, temp);
for (int k=0; k < temp.size(); k++) {
// if (depthAt(*frm, contours[i][temp[k]]) < palm_depth)
tips.push_back(contours[i][temp[k]]);
}
for (int k=0; k < tips.size(); k++) {
cv::circle(drawing, tips[k], adjPix(4), Scalar(0, 0, 255), -1);
}

在得到物体清晰的轮廓之后,一些应用便非常容易展开,OpenCV拥有大量的应用处理例程可以付之于上。

handTracking程序连接:

https://github.com/3dtof/DemoApplications/tree/master/TinTin/hand_tracking

关于了解depthFrame的Q&A refrence

  1. https://blog.csdn.net/o_sun_o/article/details/8351037
  2. https://blog.csdn.net/mouse8166/article/details/6195047
  3. https://blog.csdn.net/leixiaohua1020/article/details/12682381
  4. https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/row-wise-binding?view=sql-server-2017
  5. https://e2e.ti.com/support/sensors/f/1023/t/666615?tisearch=e2e-sitesearch&keymatch=OPT8241 MATLAB
  6. http://e2e.ti.com/support/sensors/f/1023/p/721965/2703526#2703526
  7. http://e2e.ti.com/support/sensors/f/1023/t/730122?tisearch=e2e-sitesearch&keymatch=vxl
  8. https://www.ibm.com/support/knowledgecenter/en/SSEPEK_11.0.0/odbc/src/tpc/db2z_rowwisebind.html
  9. https://www.codeproject.com/Tips/819613/Kinect-Version-Depth-Frame-to-mat-File-Exporter
  10. https://social.msdn.microsoft.com/Forums/en-US/4da8c75e-9aad-4dc3-bd83-d77ab4cd2f82/common-nui-problems-and-faq?forum=kinectsdk
  11. https://social.msdn.microsoft.com/Forums/zh-TW/9aaa03b5-d2c1-46ed-80ad-b4d23882c136/depth-frame-data-format-and-ranges?forum=kinectsdk

交流QQ: 365334601


TI-Tintin-OPT8241二次开发和应用系列--Software Level
https://pans0ul.github.io/2019/01/25/TOF-dev-Software-Level/
Author
pans0ul
Posted on
January 25, 2019
Licensed under