Kinect体感机器人(二)—— 体感识别

article/2025/10/21 17:58:42

Kinect体感机器人(二)—— 体感识别

By 马冬亮(凝霜  Loki)

一个人的战争(http://blog.csdn.net/MDL13412)

背景知识

        体感技术属于NUI(自然人机界面)的范畴,可以让用户通过肢体语言与周边设备或环境互动,其实现手段主要包括:惯性感测、光学感测以及惯性及光学联合感测。市场上比较成熟的产品主要有:微软的Kinect、索尼的PS Move、任天堂的Vii以及来自华硕的Xtion。由于没有华硕Xtion的实物,我不对其进行评测,下表是对其余三种体感设别的评测:


        通过上图的对比,来自微软的Kinect具有压倒性的优势,所以Kinect方案最终被我们采纳。

亲身体验过的成功应用

        首先是我们制作的体感机器人,实现了对人体动作的模仿,可以应用到灾后搜救领域;

        接下来是香港中文大学的“Improving Communication Ability of the Disabled -Chinese Sign Language Recognition and Translation System”;其实就是手语翻译;

        还有来自上海大学的3D影院,其通过Kinect追踪用户的头部,让画面主动适应用户。

操作系统的选择

        关于操作系统的选择肯定是Linux了,参加嵌入式的比赛用Windows没有好下场,笑:-)

        下表是对常见Linux发行版的评测:


        限于开发板的处理速度与图形性能,最终方案为Fedora 16发行版。

体感驱动库的选择

        体感驱动库我只找到了两个选择:OpenNI和Kinect SDK,后者只能用在Windows上,果断放弃,其评测如下表所示:


代码——初始化体感设备

// 初始化体感设备XnStatus result;xn::Context context;xn::ScriptNode scriptNode;xn::EnumerationErrors errors;// 使用XML文件配置OpenNI库result = context.InitFromXmlFile(CONFIG_XML_PATH, scriptNode, &errors);if (XN_STATUS_NO_NODE_PRESENT == result){XnChar strError[1024];errors.ToString(strError, 1024);NsLog()->error(strError);return 1;}else if (!NsLib::CheckOpenNIError(result, "Open config XML fialed"))return 1;NsLib::TrackerViewer::createInstance(context, scriptNode);NsLib::TrackerViewer &trackerViewer = NsLib::TrackerViewer::getInstance();if (!trackerViewer.init())return 1;trackerViewer.run();
        上述代码中的TrackerViewer是使用OpenGL进行绘制的人体骨骼图像,整个程序的同步操作也在此处理,下面给出上述代码引用到的关键代码:

// 单例模式,只允许一个实例
TrackerViewer *TrackerViewer::pInstance_ = 0;void TrackerViewer::createInstance(xn::Context &context,xn::ScriptNode &scriptNode)
{assert(!pInstance_);pInstance_ = new TrackerViewer(context, scriptNode);
}
// 初始化TrackerViewer
bool TrackerViewer::init()
{if (!initDepthGenerator())return false;if (!initUserGenerator())return false;inited_ = true;return true;
}// 初始化深度传感器
bool TrackerViewer::initDepthGenerator()
{XnStatus result;result = Context.FindExistingNode(XN_NODE_TYPE_DEPTH, DepthGenerator);if (!CheckOpenNIError(result, "No depth generator found. Check your XML"))return false;  return true;
}// 初始化骨骼识别引擎
bool TrackerViewer::initUserGenerator()
{XnStatus result;// DepthGenerator.GetMapOutputMode(ImageInfo);result = Context.FindExistingNode(XN_NODE_TYPE_USER, UserGenerator);if (!CheckOpenNIError(result, "Use mock user generator")){result = UserGenerator.Create(Context);if (!CheckOpenNIError(result, "Create mock user generator failed"))return false;}result = UserGenerator.RegisterUserCallbacks(User_NewUser, User_LostUser, NULL, hUserCallbacks_);if (!CheckOpenNIError(result, "Register to user callbacks"))return false;result = UserGenerator.GetSkeletonCap().RegisterToCalibrationStart(UserCalibration_CalibrationStart, NULL, hCalibrationStart_);if (!CheckOpenNIError(result, "Register to calibration start"))return false;result = UserGenerator.GetSkeletonCap().RegisterToCalibrationComplete(UserCalibration_CalibrationComplete, NULL, hCalibrationComplete_);if (!CheckOpenNIError(result, "Register to calibration complete"))return false;if (UserGenerator.GetSkeletonCap().NeedPoseForCalibration()){NeedPose = true;if (!UserGenerator.IsCapabilitySupported(XN_CAPABILITY_POSE_DETECTION)){NsLog()->error("Pose required, but not supported");return false;}result = UserGenerator.GetPoseDetectionCap().RegisterToPoseDetected(UserPose_PoseDetected, NULL, hPoseDetected_);if (!CheckOpenNIError(result, "Register to Pose Detected"))return false;UserGenerator.GetSkeletonCap().GetCalibrationPose(StrPose);}UserGenerator.GetSkeletonCap().SetSkeletonProfile(XN_SKEL_PROFILE_ALL);result = UserGenerator.GetSkeletonCap().RegisterToCalibrationInProgress(MyCalibrationInProgress, NULL, hCalibrationInProgress_);if (!CheckOpenNIError(result, "Register to calibration in progress"))return false;result = UserGenerator.GetPoseDetectionCap().RegisterToPoseInProgress(MyPoseInProgress, NULL, hPoseInProgress_);if (!CheckOpenNIError(result, "Register to pose in progress"))return false;return true;
}

OpenNI用于用户追踪的回调函数
        OpenNI采用的是事件回调的方式通知用户进行操作,本人的回调函数命名基本上可以“望文生意”,如果还有疑问,请查阅OpenNI文档,代码如下:

//------------------------------------------------------------------------------
// OpenNI Callbacks
//------------------------------------------------------------------------------
void XN_CALLBACK_TYPE TrackerViewer::User_NewUser(xn::UserGenerator& generator, XnUserID nId, void* pCookie)
{std::cout << "New user: " << nId << std::endl;if (TrackerViewer::getInstance().NeedPose){TrackerViewer::getInstance().UserGenerator.GetPoseDetectionCap().StartPoseDetection(TrackerViewer::getInstance().StrPose, nId);}else{TrackerViewer::getInstance().UserGenerator.GetSkeletonCap().RequestCalibration(nId, TRUE);}
}void XN_CALLBACK_TYPE TrackerViewer::User_LostUser(xn::UserGenerator& generator, XnUserID nId, void* pCookie)
{std::cout << "Lost user: " << nId << std::endl;
}void XN_CALLBACK_TYPE TrackerViewer::UserPose_PoseDetected(xn::PoseDetectionCapability& capability, const XnChar* strPose, XnUserID nId, void* pCookie)
{std::cout << "Pose " << TrackerViewer::getInstance().StrPose<< " detected for user " << nId << std::endl;TrackerViewer::getInstance().UserGenerator.GetPoseDetectionCap().StopPoseDetection(nId);TrackerViewer::getInstance().UserGenerator.GetSkeletonCap().RequestCalibration(nId, TRUE);
}void XN_CALLBACK_TYPE TrackerViewer::UserCalibration_CalibrationStart(xn::SkeletonCapability& capability, XnUserID nId, void* pCookie)
{std::cout << "Calibration started for user " << nId << std::endl;
}void XN_CALLBACK_TYPE TrackerViewer::UserCalibration_CalibrationComplete(xn::SkeletonCapability& capability, XnUserID nId, XnCalibrationStatus eStatus,void* pCookie)
{if (eStatus == XN_CALIBRATION_STATUS_OK){std::cout << "Calibration complete, start tracking user " << nId << std::endl;TrackerViewer::getInstance().UserGenerator.GetSkeletonCap().StartTracking(nId);}else{if (TrackerViewer::getInstance().NeedPose){TrackerViewer::getInstance().UserGenerator.GetPoseDetectionCap().StartPoseDetection(TrackerViewer::getInstance().StrPose, nId);}else{TrackerViewer::getInstance().UserGenerator.GetSkeletonCap().RequestCalibration(nId, TRUE);}}
}

追踪用户并显示骨骼图

// 开始追踪用户
void TrackerViewer::run()
{assert(inited_);XnStatus result;result = Context.StartGeneratingAll();if (!CheckOpenNIError(result, "Start generating failed"))return;initOpenGL(&NsAppConfig().Argc, NsAppConfig().Argv);glutMainLoop();
}
// 初始化OpenGL
void TrackerViewer::initOpenGL(int *argc, char **argv)
{glutInit(argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);glutInitWindowSize(ImageInfo.nXRes, ImageInfo.nYRes);glutCreateWindow ("User Tracker Viewer");//glutFullScreen();glutSetCursor(GLUT_CURSOR_NONE);glutKeyboardFunc(glutKeyboard);glutDisplayFunc(glutDisplay);glutIdleFunc(glutIdle);glDisable(GL_DEPTH_TEST);glEnable(GL_TEXTURE_2D);glEnableClientState(GL_VERTEX_ARRAY);glDisableClientState(GL_COLOR_ARRAY);
}
//------------------------------------------------------------------------------
// OpenGL Callbacks
//------------------------------------------------------------------------------
void TrackerViewer::glutDisplay()
{if (TrackerViewer::getInstance().SignalExitApp)exit(0);glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Setup the OpenGL viewpointglMatrixMode(GL_PROJECTION);glPushMatrix();glLoadIdentity();static TrackerViewer &trackerViewer = TrackerViewer::getInstance();xn::DepthMetaData depthMD;trackerViewer.DepthGenerator.GetMetaData(depthMD);glOrtho(0, depthMD.XRes(), depthMD.YRes(), 0, -1.0, 1.0);glDisable(GL_TEXTURE_2D);trackerViewer.Context.WaitOneUpdateAll(trackerViewer.UserGenerator);xn::SceneMetaData sceneMD;trackerViewer.DepthGenerator.GetMetaData(depthMD);trackerViewer.UserGenerator.GetUserPixels(0, sceneMD);DrawDepthMap(depthMD, sceneMD);glutSwapBuffers();
}void TrackerViewer::glutIdle()
{if (TrackerViewer::getInstance().SignalExitApp)exit(0);glutPostRedisplay();
}void TrackerViewer::glutKeyboard(unsigned char key, int x, int y)
{switch (key){case 27:TrackerViewer::getInstance().SignalExitApp = true;default:break;}
}
        上述代码完成了GUI的逻辑操作,关键说明如下:

// 将Kinect采集到的深度图像映射到OpenGL使用的2D坐标系中xn::DepthMetaData depthMD;trackerViewer.DepthGenerator.GetMetaData(depthMD);glOrtho(0, depthMD.XRes(), depthMD.YRes(), 0, -1.0, 1.0);glDisable(GL_TEXTURE_2D);
// 等待Kinect更新
trackerViewer.Context.WaitOneUpdateAll(trackerViewer.UserGenerator);
// 获取Kinect采集到的深度图像和用户信息,为绘制骨骼点和计算关节角度做准备xn::SceneMetaData sceneMD;trackerViewer.DepthGenerator.GetMetaData(depthMD);trackerViewer.UserGenerator.GetUserPixels(0, sceneMD);
// 绘制人体骨骼图像并计算关节角度,详见“Kinect体感机器人(三)—— 空间向量法计算关节角度”
DrawDepthMap(depthMD, sceneMD);

OpenNI配置用XML
        本设计采用XML文件+API进行OpenNI的配置工作,用到的XML文件如下:

<OpenNI><Licenses><!-- Add application-specific licenses here <License vendor="vendor" key="key"/>--></Licenses><Log writeToConsole="false" writeToFile="false"><!-- 0 - Verbose, 1 - Info, 2 - Warning, 3 - Error (default) --><LogLevel value="3"/><Masks><Mask name="ALL" on="true"/></Masks><Dumps></Dumps></Log><ProductionNodes><!-- Set global mirror --><GlobalMirror on="true"/><!-- Create a depth node and give it a name alias (useful if referenced ahead in this script) --><Node type="Depth" name="MyDepth"><Query><!-- Uncomment to filter by vendor name, product name, etc.<Vendor>MyVendor inc.</Vendor><Name>MyProduct</Name><MinVersion>1.2.3.4</MinVersion><Capabilities><Capability>Cropping</Capability></Capabilities>--></Query><Configuration><MapOutputMode xRes="640" yRes="480" FPS="30"/> <!-- Uncomment to override global mirror<Mirror on="false" /> --></Configuration></Node></ProductionNodes>
</OpenNI>

效果图



http://chatgpt.dhexx.cn/article/IbCr6nig.shtml

相关文章

乐视三合一体感摄像头Astra pro开发记录1(深度图、彩色图及点云简单显示)

在某鱼上淘的乐视三合一体感摄像头&#xff0c;捡漏价九十几块&#xff0c;买来玩玩。 网上已经有一些关于此款摄像头的开发资料。 官方的开发资料&#xff1a;[官网链接]&#xff08;https://orbbec3d.com/index/download.html) 按官方网站以及其他帖子&#xff0c;下载并安装…

百来块钱的乐视体感三合一体感摄像头拆解

乐视体感三合一体感摄像头基本参数 乐视体感三合一的体感摄像头前世今生 乐视体感三合一体感摄像头和奥比中光的Astra Pro是同门师兄弟&#xff0c;也就是当年乐视辉煌的时候向奥比中光定制的外观&#xff0c;富士康代工生产&#xff0c;当时生产的时候对标微软 kinect&#x…

3D深度体感摄像头 自有算法的深度立体视觉传感器

rgbdsense基于结构光结合自有算法的深度立体视觉传感器&#xff0c;通过USB将深度数据与RGB数据传输至PC的免驱动设备。通过此次众筹为大家提供开放易用的3D深度摄像头&#xff0c;开发人员可借助PC用于3D成像&#xff0c;图像匹配。三维扫描&#xff0c;动感游戏&#xff0c;u…

乐视三合一体感摄像头--基本信息及windows下部分开发

乐视三合一体感摄像头--基本信息及windows下部分开发 Introduction基本信息Windows下使用安装驱动使用openNI使用imageJ调用RGB图像Q&#xff1a; 参考资料 Introduction 乐视三合一体感摄像头是乐视对标kinect&#xff0c;做的一款3D体感摄像头&#xff1b;设计目的为用于电视…

体感摄像头 realsense 系列硬件资料

一、体感摄像头 Intel的体感摄像机是具有深度图像采集能力的摄像机&#xff0c;目前已经出到了400系列。与kinect 2&#xff0c;ZED&#xff0c;leap motion比较&#xff0c;属于比较中庸。 手势识别方面不如leap motion&#xff0c;leap motion的视角是120度&#xff0c;精度和…

大学计算机专业课程体系参考

#参考一 对于跨专业小白来说&#xff0c;熟悉大学本科计算机专业课程体系设置对于把握计算机知识体系具有重大意义。特此&#xff0c;结合笔者学习过程&#xff0c;分享一下本人认为比较有价值的体系层次图&#xff0c;以便于初学者和跨专业者更好的构建自己脑中的计算机网络和…

同济大学计算机系的课程,同济大学计算机系本科生培养方案

附件一&#xff1a;教学安排 课程性质课程编号课程名称考试学期学分学时上机时数实验时数公共基础课必修002016形势与政策(1)10.517 公共基础课必修070373中国近现代史纲要1 2.034 公共基础课必修070374思想道德修养和法律基础1 3.034 公共基础课必修100383计算机科学导论1 3.0…

斯坦福 计算机 学什么,斯坦福大学本科计算机专业学习哪些课程?

斯坦福大学本科计算机专业学习哪些课程&#xff1f;据小编了解&#xff0c;高质量的课程和自由的选课制度是斯坦福大学本科教育的特点。学校是根据课程的深度给课程排号的。如计算机系的课号是CS0到CS599&#xff0c;其中&#xff1a;0~99号是服务性课程&#xff0c;适合非技术…

计算机应用 主修,计算机应用主修课程

海量优秀的免费计算机应用主修课程范文供您参考与下载&#xff0c;关于计算机应用主修课程的免费论文范文参考资料是由2016年最新的相关论文题目按照标准论文格式模板写作的,适合不知道怎么写计算机应用主修课程的大学毕业生,对相关的本科论文和硕士毕业论文及职称论文发表写作…

计算机专业课顺序,计算机专业课程安排顺序 计算机专业课程安排

每年都有很多人选择报考计算机专业&#xff0c;那么&#xff0c;计算机专业主要学哪些课程呢&#xff1f;要掌握什么技能呢&#xff1f;下面小编整理了一些相关信息&#xff0c;供大家参考&#xff01; 计算机专业要学什么 学习计算机&#xff0c;需要有一定的数学及英语基础&a…

计算机应用基础课程学什么,计算机专业本科课程 主要学什么

计算机专业本科课程 主要学什么2021-05-01 17:02:08文/李文源 计算机专业本科课程主要有计算机应用基础、应用文写作、数学、英语、德育、电工与电子技术、计算机网络技术、C语言、计算机组装与维修、企业网安全高级技术、企业网综合管理等。 计算机专业本科课程 一、数学类 主…

计算机专业及课程设置,清华及各大高校公布计算机专业培养方案课程

原标题&#xff1a;清华及各大高校公布计算机专业培养方案课程 计算机科学与技术的基础课程在不同的学校的都不一样。不过基本都有计算机导论、计算机组成原理、操作系统、数据结构、算法分析与设计、编译原理、计算机原理、数据库原理等主干课程。而这些课程的基础就是数学&am…

计算机成人本科学历,计算机专业成人本科

为毕业生写计算机专业成人本科提供计算机专业成人本科范文参考,涵盖硕士、大学本科毕业论文范文和职称论文范文&#xff0c;包括论文选题、开题报告、文献综述、任务书、参考文献等&#xff0c;是优秀免费计算机专业成人本科网站。 基于极限编程的计算机专业本科毕业设计模式 基…

计算机 本科专业 课程

本科专业 第一个&#xff1a; 计算机科学与技术 专业 计算机科学与技术&#xff08;Computer Science and Technology&#xff09;是国家一级学科&#xff0c;下设信息安全、软件工程、计算机软件与理论、计算机系统结构、计算机应用技术、计算机技术等专业 主修大数据技术…

接口测试之关联测试

【概念普及】 接口&#xff08;API&#xff09;&#xff1a;指不同功能层之间的通信规则&#xff0c;用以传输数据或命令控制。 单接口测试&#xff1a;在测试工作中主要用于检查单个业务功能的接口实现&#xff0c;或者调试测试数据。 接口关联&#xff1a;是指将两个及以上…

如何进行接口测试?

如何进行接口测试 1、什么是接口测试2、接口测试设计思路3、接口测试步骤4、接口测试用例模板示例 1、什么是接口测试 接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。其目的是对被测系统各个部件之间的功能…

接口测试详细讲解

转载别人的&#xff0c;Mark一下 超详细——接口测试总结与分享 金字塔模型回顾 金字塔模型 通过之前对金字塔结构的学习&#xff0c;大概了解到了金字塔模型想告诉我们的几个道理&#xff1a; 1.越底层&#xff0c;越稳定。 金字塔主要观点认为单元测试的稳定性高&#xff0c;…

POSTMAN接口测试流程

POSTMAN接口测试流程 一、首先是了解基本的测试步骤 设计测试用例配置PostMan测试环境根据测试用例在PostMan填写接口信息执行并分析结果与需求文档是否一致 二、接下来直接进入POSTMAN的配置 &#xff08;1&#xff09;先创建一个Collection用例集&#xff0c;并且简单配置一…

接口测试流程

接口测试流程 一、编写接口测试计划二、编写、评审接口测试用例三、执行接口测试四、接口自动化持续集成要点 接口测试一般遵循如下流程&#xff0c;细节部分可根据实际项目调整 一、编写接口测试计划 接口测试计划和功能测试计划的目标一致&#xff0c;都是为了确定需求、确定…

简述 Mock 接口测试

在开发过程中经常会有前后端开发进度不统一的时候&#xff0c;为了避免前后端开发进度相互影响&#xff0c;这时候就需要用到 Mock 来协助我们进行对接。 那么什么是 Mock 接口测试&#xff1f;它对我们的开发工作有什么帮助&#xff1f;今天我们就来浅谈一下 Mock 接口测试的…