Kinect学习笔记六CoordinateMapping上

Kinect学习笔记第六篇Coordinate Mapping(坐标映射) 上篇

 

 

简述:

本次学习的是如何利用kinect的人体识别然后分离彩色图像中的人体,将至移植到其他图片上,效果类似于AE键控中的绿幕效果。

 

用到的流有ColorFrame/DepthFrame/BodyIndexFrame.

因此需要打开“MultiSourceFrame”多种数据流源与多种流阅读器“ this.multiFrameSourceReader = this.kinectSensor.OpenMultiSourceFrameReader(FrameSourceTypes.Depth | FrameSourceTypes.Color | FrameSourceTypes.BodyIndex); 

相应的事件是多种流到达事件“multiFrameSourceReader.MultiSourceFrameArrived”。

 

之所以用到深度流,之一是因为索引是对应深度帧的512*424,进而用深度帧对应彩色,最终实现对应1920*1080,在中间转换时明显看见它采用了“周围统一”,即:

 

阴影中心点(深度点)“统治”阴影范围内的点(多个像素点)。

 

 

2073600个彩色映射深度点,对应彩色像素20736001920*1080)个,大约102073600/424*512))个左右像素点对应一个深度点。

 

 

 

 

 

 

知识储备:

(这里可深度学习!)

Coordinate Mapper(坐标映射器):可实现以下

2法一般指访问底层缓存与使用数组)

1所有相机点映射到彩色空间*2

2个别相机点映射到彩色空间(第二实例采用-下篇)

3所有相机点映射到深度空间*2

4个别相机点映射到深度空间

5彩色帧映射到相机空间*2

6彩色帧映射到深度空间*2法(第一个实例采用)

7深度帧映射到相机空间*2

8深度帧映射到彩色空间*2

9所有深度点映射到相机空间*2

10所有深度点映射到彩色空间*2

11个别深度点映射到相机空间

12个别深度点映射到彩色空间

 

Bitmap中每个像素点的值通常是这样表示的:0x80FFFFFF

0x表示是十六进制表示法,80在这是50%透明度(8016进制中是1/2位置)FFFFFF六位表彩色。排列格式ARGBA通道(掌管透明度)。

Bitmap.Config  ARGB_4444 16 每个像素 占四位   
Bitmap.Config  ARGB_8888 32 每个像素 占八位  
Bitmap.Config  RGB_565 16 R5位 G6位 B5位 没有透明度(A

 

骨骼点数据和深度数据或者彩色影像数据的测量方法不同。每一种类的数据(深度数据,影像数据,骨骼数据)都是在特定的集合坐标或空间内定义的。深度数据或者影像数据用像素来表示,X,Y位置从左上角以0开始。深度数据的Z方位数据以毫米为单位。与这些不同的是,骨骼空间是以米为单位来描述的,以深度传感器为中心,其X,Y值为0。骨骼坐空间坐标系是右手坐标系,X正方向朝右,Y周正方向朝上,X轴数据范围为-2.2~2.2,总共范围为4.2米,Y周范围为-1.6~1.6米,Z轴范围为0~4米。

 

 

 

代码后有流程图可看。

CoordinateMapping第一程序代码实例:

其中包含了附加的便于理解的输出,需要手都设为True与取消注释才可。

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

using System.IO;

using Microsoft.Kinect;

namespace myCoordinateMappingViewer

{

    /// <summary>

    /// MainWindow.xaml 的交互逻辑

    /// </summary>

    public partial class MainWindow : Window

    {

        private readonly int bytesPerPixel = (PixelFormats.Bgr32.BitsPerPixel + 7/ 8;

        private KinectSensor kinectSensor = null;

        private CoordinateMapper coordinateMapper = null;//坐标映射器

        private MultiSourceFrameReader multiFrameSourceReader = null;//多源阅读器

        private WriteableBitmap bitmap = null;

        private uint bitmapBackBufferSize = 0;//Bitmap缓冲区大小

        private DepthSpacePoint[] colorMappedToDepthPoints = null;

        bool savejudge1 = false;//设为true可保存一帧的this.colorMappedTodepthPoints查看

        bool savejudge2 =false;//设为true可保存一帧的this.bodyIndexDataPointer查看

        public MainWindow()

        {

            this.kinectSensor = KinectSensor.GetDefault();

            this.multiFrameSourceReader = this.kinectSensor.OpenMultiSourceFrameReader(FrameSourceTypes.Depth | FrameSourceTypes.Color | FrameSourceTypes.BodyIndex);

            this.multiFrameSourceReader.MultiSourceFrameArrived += this.Reader_MultiSourceFrameArrived;

            this.coordinateMapper = this.kinectSensor.CoordinateMapper;

            //DepthFrame

            FrameDescription depthFrameDescription = this.kinectSensor.DepthFrameSource.FrameDescription;

            int depthWidth = depthFrameDescription.Width;

            int depthHeight = depthFrameDescription.Height;

            //ColorFrame

            FrameDescription colorFrameDescription = this.kinectSensor.ColorFrameSource.FrameDescription;

            int colorWidth = colorFrameDescription.Width;

            int colorHeight = colorFrameDescription.Height;

 

            this.colorMappedToDepthPoints = new DepthSpacePoint[colorWidth * colorHeight];//彩色对应深度点数组大小(1920*1080)

            this.bitmap = new WriteableBitmap(colorWidth, colorHeight, 96.096.0PixelFormats.Bgra32, null);

            // Calculate the WriteableBitmap back buffer size 1920*1080*4(以下这么写是让你了解底层数据大小)

            this.bitmapBackBufferSize = (uint)((this.bitmap.BackBufferStride * (this.bitmap.PixelHeight - 1)) + (this.bitmap.PixelWidth * this.bytesPerPixel));

            

            this.kinectSensor.Open();

            this.DataContext = this;

 

 

            InitializeComponent();

        }

 

        private void Reader_MultiSourceFrameArrived(object sender, MultiSourceFrameArrivedEventArgs e)

        {

            int depthWidth = 0;

            int depthHeight = 0;

 

            DepthFrame depthFrame = null;

            ColorFrame colorFrame = null;

            BodyIndexFrame bodyIndexFrame = null;

            bool isBitmapLocked = false;

 

            MultiSourceFrame multiSourceFrame = e.FrameReference.AcquireFrame();

 

            // If the Frame has expired by the time we process this event, return.

            if (multiSourceFrame == null)

            {

                return;

            }

 

 

            //用try/finnally来处理数据,保证用完后释放清空并解锁缓存

            try

            {

                depthFrame = multiSourceFrame.DepthFrameReference.AcquireFrame();

                colorFrame = multiSourceFrame.ColorFrameReference.AcquireFrame();

                bodyIndexFrame = multiSourceFrame.BodyIndexFrameReference.AcquireFrame();

 

                //确保接受到数据,否则返回,以防止finally释放为空

                if ((depthFrame == null|| (colorFrame == null|| (bodyIndexFrame == null))

                {

                    return;

                }

 

                // Process Depth

                FrameDescription depthFrameDescription = depthFrame.FrameDescription;

 

                depthWidth = depthFrameDescription.Width;

                depthHeight = depthFrameDescription.Height;

 

                // Access the depth frame data directly via LockImageBuffer to avoid making a copy

                //深度数据映射到一个与彩色图大小相同的DepthSpacePoints处

                using (KinectBuffer depthFrameData = depthFrame.LockImageBuffer())

                {

                    //1数组,低效

                    //unsafe

                    //{

                    //    //ushort*pointer=(ushort*)depthFrameData.UnderlyingBuffer;

                    //    ushort[] mydepthData = null;

                    //    mydepthData = new ushort[depthFrameData.Size / 2];

                    //    for (int i = 0; i < depthFrameData.Size / 2; i++)

                    //    {

                    //        //mydepthData[i] = pointer[i];

                    //        mydepthData[i] = ((ushort*)depthFrameData.UnderlyingBuffer)[i];

                    //    }

                    //    this.coordinateMapper.MapColorFrameToDepthSpace(mydepthData, this.colorMappedToDepthPoints);

 

                    //}

                    //2底层缓存,高效

                    this.coordinateMapper.MapColorFrameToDepthSpaceUsingIntPtr(

                        depthFrameData.UnderlyingBuffer,

                        depthFrameData.Size,

                        this.colorMappedToDepthPoints);

                }

                //这里配合保存一帧的this.colorMappedToDepthPoints

                /*if(true)

                {

                    FileStream fs = new FileStream("D:\\ColorMappedToDepthPoints.txt", FileMode.OpenOrCreate);

                    StreamWriter sw = new StreamWriter(fs);

                    int numx = 0,num=0;;

                    foreach (var x in this.colorMappedToDepthPoints)

                    {

                        sw.Write("[{0},{1}] ", x.X,x.Y);

                        numx++;

                        num++;

                        if (numx == 10)

                        {

                            sw.Write("\r\n");

                            numx = 0;

                        }

                    }

                    sw.Write("总计{0}",num);

                    sw.Flush();

                    sw.Close();

                    fs.Close();

                    this.savejudge1 = false;

                }*/

               

                // We're done with the DepthFrame 

                depthFrame.Dispose();

                depthFrame = null;

 

                // Process Color

 

                // Lock the bitmap for writing

                this.bitmap.Lock();

                isBitmapLocked = true;

                //彩色数据写入this.bitmap.BackBuffer

                colorFrame.CopyConvertedFrameDataToIntPtr(this.bitmap.BackBuffer, this.bitmapBackBufferSize, ColorImageFormat.Bgra);

 

                // We're done with the ColorFrame 

                colorFrame.Dispose();

                colorFrame = null;

 

                // We'll access the body index data directly to avoid a copy

                using (KinectBuffer bodyIndexData = bodyIndexFrame.LockImageBuffer())

                {

                    // 使用整一帧存在的身体索引

                    unsafe

                    {

                        byte* bodyIndexDataPointer = (byte*)bodyIndexData.UnderlyingBuffer;

 

                        int colorMappedToDepthPointCount = this.colorMappedToDepthPoints.Length;

 

                        fixed (DepthSpacePoint* colorMappedToDepthPointsPointer = this.colorMappedToDepthPoints)

                        {

                            // Treat the color data as 4-byte pixels

                            uint* bitmapPixelsPointer = (uint*)this.bitmap.BackBuffer;

                            

                            // Loop over each row and column of the color image

                            // Zero out any pixels that don't correspond to a body index

                            for (int colorIndex = 0; colorIndex < colorMappedToDepthPointCount; ++colorIndex)

                            {

                                float colorMappedToDepthX = colorMappedToDepthPointsPointer[colorIndex].X;

                                float colorMappedToDepthY = colorMappedToDepthPointsPointer[colorIndex].Y;

 

                                // The sentinel value is -inf, -inf, meaning that no depth pixel corresponds to this color pixel.

                                if (!float.IsNegativeInfinity(colorMappedToDepthX) &&

                                    !float.IsNegativeInfinity(colorMappedToDepthY))

                                {

                                    // Make sure the depth pixel maps to a valid(有效) point in color space

                                    int depthX = (int)(colorMappedToDepthX + 0.5f);//+0.5f For进位

                                    int depthY = (int)(colorMappedToDepthY + 0.5f);

 

                                    // If the point is not valid, there is no body index there.

                                    if ((depthX >= 0&& (depthX < depthWidth) && (depthY >= 0&& (depthY < depthHeight))

                                    {

                                        int depthIndex = (depthY * depthWidth) + depthX;

                                        /*if (this.savejudge2)

                                        {

                                            FileStream fs = new FileStream("D:\\bodyIndexDataPointer.txt", FileMode.OpenOrCreate);

                                            StreamWriter sw = new StreamWriter(fs);

                                            int num = 0;

                                            for (int i = 0; i < depthWidth; i++)

                                            {

 

                                                for (int j = 0; j < depthHeight; ++j)

                                                {

                                                    sw.Write("{0} ", bodyIndexDataPointer[i + j * depthHeight]);

                                                    num++;

                                                }

                                                sw.Write("\r\n");

                                            }

                                            sw.Write("共计{0}", num);

                                            sw.Flush();

                                            sw.Close();

                                            fs.Close();

                                            this.savejudge2 = false;

                                        }*/

                                        // If we are tracking a body for the current pixel, do not zero out the pixel

                                        if (bodyIndexDataPointer[depthIndex] != 0xff)

                                        {

                                            continue;

                                        }

                                    }

                                }

                                bitmapPixelsPointer[colorIndex] = 0;

                                //bitmapPixelsPointer[colorIndex] = 0xFF0000FF;//Ox表十六进制,然后透明度(2位)+彩色值(6位)0透明度蓝色

                            }

                        }

                        //更新位图(覆盖)

                        this.bitmap.AddDirtyRect(new Int32Rect(00this.bitmap.PixelWidth, this.bitmap.PixelHeight));

                    }

                }

            }

            finally

            {

                if (isBitmapLocked) this.bitmap.Unlock();

                if (depthFrame != null) depthFrame.Dispose();

                if (colorFrame != null) colorFrame.Dispose();

                if (bodyIndexFrame != null) bodyIndexFrame.Dispose();

            }

        }

        public ImageSource ImageSource

        {

            get

            {

                return this.bitmap;

            }

        }

 

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)

        {

            if (this.multiFrameSourceReader != null)

            {

                // MultiSourceFrameReder is IDisposable

                this.multiFrameSourceReader.Dispose();

                this.multiFrameSourceReader = null;

            }

 

            if (this.kinectSensor != null)

            {

                this.kinectSensor.Close();

                this.kinectSensor = null;

            }

        }

 

    }

}

 

 

 

 

 

渣手写流程图一张:

好长时间不写字,都.......ORZ 虽然本来字也差。~(@^_^@)~

 

 

 

其中的“无人清零”就是将该点无人体索引像素透明设为100%

 

一些小东西:

 

关于映射后的点为什么有负值?

因为不同的视场和纵横比,两个摄像头没有看到同样的事情。具体地说,在彩色图像的左和右边界,有一个区域的深度相机看不到两边(大约6%)

同样,在顶部和底部的深度图像彩色摄像头看不到的区域。

这就是负值来自:前几排的深度图像映射到值外(上图)彩色图像,导致负面的Y值。同样的,最后几行映射到Y值大于1080,也在彩色图像。

顺便说一句。当使用逆方法(MapColorFrameToDepthSpace()),最左边的和右列映射到无效值,因为它们是在深度图像。

 

 

:

第一程序xaml添加代码:

<Image HorizontalAlignment="Left" VerticalAlignment="Top" Source="Picture\10921221_003010567114_2.jpg" Stretch="UniformToFill" />

        <Image HorizontalAlignment="Left"  VerticalAlignment="Top" Source="{Binding ImageSource}" Stretch="UniformToFill"/>

 

 

 

fixed 语句设置指向托管变量的指针,并在执行该语句期间“固定”此变量。 如果没有 fixed 语句,则指向可移动托管变量的指针的作用很小,因为垃圾回收可能不可预知地重定位变量。 C# 编译器只允许在 fixed 语句中分配指向托管变量的指针。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值