Kinect抠出人像并使用视频作为背景

该博客详细介绍了如何利用Kinect传感器进行背景去除,以实现绿幕效果。通过处理深度帧、身体信息和颜色帧数据,使用CoordinateMapper映射深度值到颜色空间,并更新WriteableBitmap来创建带有透明背景的图像。主要涉及的关键步骤包括初始化数组、填充帧数据、映射深度值以及更新位图缓冲区。
        void Reader_MultiSourceFrameArrived(object sender, MultiSourceFrameArrivedEventArgs e)
        {
            var reference = e.FrameReference.AcquireFrame();

            using (var colorFrame = reference.ColorFrameReference.AcquireFrame())
            using (var depthFrame = reference.DepthFrameReference.AcquireFrame())
            using (var bodyIndexFrame = reference.BodyIndexFrameReference.AcquireFrame())
            {
                if (colorFrame != null && depthFrame != null && bodyIndexFrame != null)
                {
                    // 3) Update the image source.
                    camera.Source = _backgroundRemovalTool.GreenScreen(colorFrame, depthFrame, bodyIndexFrame);
                }
            }

        }

MainWindow中主要就是backgroundRemovalTool这个类在起到去除背景的作用。
代码中主要有以下几个类:
WriteableBitmap _bitmap: 带有裁剪背景的最终图像
ushort[] _depthData: 深度帧的深度值
byte[] _bodyData: 有关站在传感器前面的身体的信息
byte[] _colorData: 颜色框的RGB值
byte[] _displayPixels: 映射帧的RGB值
ColorSpacePoint[] _colorPoints: 我们需要映射的color point
还使用图像源(WriteableBitmap)来创建最终的位图图像。 CoordinateMapper作为连接的Kinect传感器的参数传递。
先看GrennScreen函数。
首先,我们需要获得每个框架的尺寸(框架具有不同的宽度和高度):

 			int colorWidth = colorFrame.FrameDescription.Width;
            int colorHeight = colorFrame.FrameDescription.Height;

            int depthWidth = depthFrame.FrameDescription.Width;
            int depthHeight = depthFrame.FrameDescription.Height;

            int bodyIndexWidth = bodyIndexFrame.FrameDescription.Width;
            int bodyIndexHeight = bodyIndexFrame.FrameDescription.Height;

然后,我们需要初始化数组。 初始化只发生一次,因此每次我们有一个新帧时都要避免分配内存。

                _depthData = new ushort[depthWidth * depthHeight];
                _bodyData = new byte[depthWidth * depthHeight];
                _colorData = new byte[colorWidth * colorHeight * BYTES_PER_PIXEL];
                _displayPixels = new byte[depthWidth * depthHeight * BYTES_PER_PIXEL];
                _colorPoints = new ColorSpacePoint[depthWidth * depthHeight];
                _bitmap = new WriteableBitmap(depthWidth, depthHeight, DPI, DPI, FORMAT, null);

我们现在需要用新的帧数据填充数组。 在此之前,我们检查数组长度是否与我们之前找到的维度相对应:

            if (((depthWidth * depthHeight) == _depthData.Length) && ((colorWidth * colorHeight * BYTES_PER_PIXEL) == _colorData.Length) && ((bodyIndexWidth * bodyIndexHeight) == _bodyData.Length))
            {
                depthFrame.CopyFrameDataToArray(_depthData);

                if (colorFrame.RawColorImageFormat == ColorImageFormat.Bgra)
                {
                    colorFrame.CopyRawFrameDataToArray(_colorData);
                }
                else
                {
                    colorFrame.CopyConvertedFrameDataToArray(_colorData, ColorImageFormat.Bgra);
                }

现在使用坐标映射器。 坐标映射器将深度值映射到_colorPoints数组:

_coordinateMapper.MapDepthFrameToColorSpace(_depthData, _colorPoints);

映射已完成。 我们要做的是指定哪些像素属于人体并将它们添加到_displayPixels数组。 因此,我们循环遍历深度值并相应地更新_displayPixels数组。

                for (int y = 0; y < depthHeight; ++y)
                {
                    for (int x = 0; x < depthWidth; ++x)
                    {
                        int depthIndex = (y * depthWidth) + x;

                        byte player = _bodyData[depthIndex];

                        if (player != 0xff)
                        {
                            ColorSpacePoint colorPoint = _colorPoints[depthIndex];

                            int colorX = (int)Math.Floor(colorPoint.X + 0.5);
                            int colorY = (int)Math.Floor(colorPoint.Y + 0.5);

                            if ((colorX >= 0) && (colorX < colorWidth) && (colorY >= 0) && (colorY < colorHeight))
                            {
                                int colorIndex = ((colorY * colorWidth) + colorX) * BYTES_PER_PIXEL;
                                int displayIndex = depthIndex * BYTES_PER_PIXEL;

                                _displayPixels[displayIndex + 0] = _colorData[colorIndex];
                                _displayPixels[displayIndex + 1] = _colorData[colorIndex + 1];
                                _displayPixels[displayIndex + 2] = _colorData[colorIndex + 2];
                                _displayPixels[displayIndex + 3] = 0xff;
                            }
                        }
                    }
                }

这将产生具有透明像素的位图,用于背景和人体的彩色像素。 最后,这是WriteableBitmap的更新方式:
_bitmap.Lock();
Marshal.Copy(_displayPixels, 0, _bitmap.BackBuffer, _displayPixels.Length);
_bitmap.AddDirtyRect(new Int32Rect(0, 0, depthWidth, depthHeight));
_bitmap.Unlock();
背景可更换

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值