Kinect for windows 开发入门 七:景深数据获取和使用 上

2024-06-12 18:32

本文主要是介绍Kinect for windows 开发入门 七:景深数据获取和使用 上,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景知识

1.      景深数据通过Kinect红外传感器(红外发射器和摄像头)获取。

2.       红外摄像机的视场是金字塔形状的。离摄像机远的物体比近的物体拥有更大的视场横截面积。这意味着影像的高度和宽度,比如640X480和摄像机视场的物理位置并不一一对应。但是每个像素的深度值是和视场中物体离摄像机的距离是对应的。

3.      Kinect中深度值最大为4096mm0值通常表示深度值不能确定,一般应该将0值过滤掉。微软建议在开发中使用1220mm~3810mm范围内的值。在进行其他深度图像处理之前,应该使用阈值方法过滤深度数据至1220mm-3810mm这一范围内。下图显示了Kinect Sensor的感知范围,其中的default rangeXbox360Kinect for Windows都适用,而near range仅对后者适用:

4.       深度帧数据中,每个像素占16位,这样BytesPerPixel属性,即每一个像素占2个字节。每一个像素的深度值只占用了16个位中的13个位。如图:

获取每一个像素的距离很容易,但是要直接使用还需要做一些位操作。可能大家在实际编程中很少情况会用到位运算。如上图所示,深度值存储在第315位中,要获取能够直接使用的深度数据需要向右移位,将游戏者索引(Player Index)位移除。后面将会介绍游戏者索引位的重要性。下面的代码简要描述了如何获取像素的深度值。代码中pixelData变量就是从深度帧数据中获取的short数组。PixelIndex基于待计算像素的位置计算出来的。SDKDepthImageFrame类中定义了一个常量PlayerIndexBitmaskWidth,它定义了要获取深度数据值需要向右移动的位数。在编写代码时应该使用这一常量而不是硬编码,因为未来随着软硬件水平的提高,Kinect可能会增加能够同时识别人数的个数,从而改变PlayerIndexBitmaskWidth常量的值。

Int32 pixelIndex = (Int32)(p.X + ((Int32)p.Y *frame.Width));

Int32 depth = this.depthPixelDate[pixelIndex]>> DepthImageFrame.PlayerIndexBitmaskWidth;

5.       色彩的PixeldataByte[]存储,而景深则是用Short[]存储。

6.       示例中演示了如何获取某一点的深度数据,也演示了简单的深度数据处理,如:取反,灰度增强,彩色渲染

 

示例代码

1.      完整代码请到资源块下载

2.  获取景深影像:

        privatevoid kinectSensor_FrameReady(object sender, DepthImageFrameReadyEventArgs e)

        {

            // Clean the last depth framebefore fetching the next frame.

            if (lastDepthFrame != null)

            {

                lastDepthFrame.Dispose();

                lastDepthFrame = null;

            }

 

            lastDepthFrame =e.OpenDepthImageFrame();

 

            if (null != lastDepthFrame)

            {

                // Different with color data,it's not byte[] but short[]

                lastPixelData = newshort[lastDepthFrame.PixelDataLength];

               lastDepthFrame.CopyPixelDataTo(lastPixelData);

                EditDepth_Reverted(lastPixelData,lastDepthFrame);

               EditDepth_Enhance(lastPixelData, lastDepthFrame);

               EditDepth_RandomColor(lastPixelData, lastDepthFrame);

                this.imageBitmap.WritePixels(this.imageBitmapRect,lastPixelData, this.imageStride, 0);

            }

        }

3.       简单的图像处理:

 

        privatevoid EditDepth_Reverted(short[] pixelData, DepthImageFrame frame)

        {

            short[] revertPixelData = newshort[frame.Width * frame.Height];

            int depth = 0;

            for (int index = 0; index <pixelData.Length; index++)

            {

                depth = (int)(pixelData[index] >> DepthImageFrame.PlayerIndexBitmaskWidth);

                revertPixelData[index] = (short)~pixelData[index];

            }

 

            RevertImageElement.Source = BitmapSource.Create(frame.Width,frame.Height, 96, 96, PixelFormats.Gray16, null, revertPixelData, frame.Width * frame.BytesPerPixel);

        }

 

        privatevoid EditDepth_Enhance(short[] pixelData, DepthImageFrame frame)

        {

            // 4 bytes per pixel

            byte[] enhancedPixelData = newbyte[frame.Width * frame.Height *4];

            int depth = 0;

            int gray = 0;

            for (int index = 0; index <pixelData.Length; index++)

            {

                depth = (int)(pixelData[index] >> DepthImageFrame.PlayerIndexBitmaskWidth);

                // 0xFFF = 4095, show the gray (0~255) according to depth (0 ~ 4095)

                gray = 255 * depth / 0xFFF;

                // R==G==B

                enhancedPixelData[index * 4] =(byte)gray;

                enhancedPixelData[index * 4 +1] = (byte)gray;

                enhancedPixelData[index * 4 +2] = (byte)gray;

            }

 

            EnhanceImageElement.Source = BitmapSource.Create(frame.Width,frame.Height, 96, 96, PixelFormats.Bgr32, null, enhancedPixelData, frame.Width * 4);

        }

 

        privatevoid EditDepth_RandomColor(short[] pixelData, DepthImageFrame frame)

        {

            // 4 bytes per pixel

            byte[] enhancedPixelData = newbyte[frame.Width * frame.Height *4];

            int depth = 0;

            int gray = 0;

            for (int index = 0; index <pixelData.Length; index++)

            {

                depth = (int)(pixelData[index] >> DepthImageFrame.PlayerIndexBitmaskWidth);

                // 0xFFF = 4095, show thegray (0~255) according to depth (0 ~ 4095)

                gray = 767 * depth / 0xFFF;

                if (gray <= 255)

                {

                    enhancedPixelData[index *4] = (byte)gray;

                    enhancedPixelData[index * 4+ 1] = (byte)0;

                    enhancedPixelData[index * 4+ 2] = (byte)0;

                }

                elseif (gray <= 511)

                {

                    enhancedPixelData[index *4] = (byte)255;

                    enhancedPixelData[index * 4+ 1] = (byte)(gray - 256);

                    enhancedPixelData[index * 4+ 2] = (byte)0;

                }

                else

                {

                    enhancedPixelData[index *4] = (byte)255;

                    enhancedPixelData[index * 4 + 1] = (byte)255;

                    enhancedPixelData[index * 4+ 2] = (byte)(gray - 512);

                }

            }

 

            RandomImageElement.Source = BitmapSource.Create(frame.Width,frame.Height, 96, 96, PixelFormats.Bgr32, null, enhancedPixelData, frame.Width * 4);

        }

 

效果演示

范围外的是-1,太近了是0,中间的可以正常显示距离

从椅子腿来看,增强后还是可以显示更多细节的:

这篇关于Kinect for windows 开发入门 七:景深数据获取和使用 上的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1054998

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

Python版本信息获取方法详解与实战

《Python版本信息获取方法详解与实战》在Python开发中,获取Python版本号是调试、兼容性检查和版本控制的重要基础操作,本文详细介绍了如何使用sys和platform模块获取Python的主... 目录1. python版本号获取基础2. 使用sys模块获取版本信息2.1 sys模块概述2.1.1

一文详解Python如何开发游戏

《一文详解Python如何开发游戏》Python是一种非常流行的编程语言,也可以用来开发游戏模组,:本文主要介绍Python如何开发游戏的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、python简介二、Python 开发 2D 游戏的优劣势优势缺点三、Python 开发 3D

Redis 基本数据类型和使用详解

《Redis基本数据类型和使用详解》String是Redis最基本的数据类型,一个键对应一个值,它的功能十分强大,可以存储字符串、整数、浮点数等多种数据格式,本文给大家介绍Redis基本数据类型和... 目录一、Redis 入门介绍二、Redis 的五大基本数据类型2.1 String 类型2.2 Hash