Kinect:从色彩空间移动到相机空间

时间:2014-11-12 21:35:10

标签: c# visual-studio sdk kinect

我刚刚开始使用Kinect v2,我正在运行一些问题。

所以我试图找到彩色图像中物体的x,y,z距离。

我进行了搜索,结果发现我需要使用坐标映射器功能,更具体地说是以下内容:

MapColorFrameToCameraSpace

我不太确定如何使用上述方法。

这是我到目前为止的代码:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    /// <summary>
    /// Size of the RGB pixel in the bitmap
    /// </summary>
    private readonly int bytesPerPixel = (PixelFormats.Bgr32.BitsPerPixel + 7) / 8;

    /// <summary>
    /// Active Kinect sensor
    /// </summary>
    private KinectSensor kinectSensor = null;

    /// <summary>
    /// Coordinate mapper to map one type of point to another
    /// </summary>
    private CoordinateMapper coordinateMapper = null;

    /// <summary>
    /// Reader for depth/color/body index frames
    /// </summary>
    private MultiSourceFrameReader multiFrameSourceReader = null;

    /// <summary>
    /// Bitmap to display
    /// </summary>
    private WriteableBitmap bitmap = null;

    /// <summary>
    /// The size in bytes of the bitmap back buffer
    /// </summary>
    private uint bitmapBackBufferSize = 0;

    /// <summary>
    /// Intermediate storage for the color to depth mapping
    /// </summary>
    private DepthSpacePoint[] colorMappedToDepthPoints = null;

    /// Intermediate storage for color to camera mapping
    /// 
    private CameraSpacePoint[] cameraPoints = null;

    /// <summary>
    /// Current status text to display
    /// </summary>
    private string statusText = null;

    /// <summary>
    /// Initializes a new instance of the MainWindow class.
    /// </summary>
    public MainWindow()
    {
        this.kinectSensor = KinectSensor.GetDefault();

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

        this.multiFrameSourceReader.MultiSourceFrameArrived += this.Reader_MultiSourceFrameArrived;

        this.coordinateMapper = this.kinectSensor.CoordinateMapper;

        FrameDescription depthFrameDescription = this.kinectSensor.DepthFrameSource.FrameDescription;

        int depthWidth = depthFrameDescription.Width;
        int depthHeight = depthFrameDescription.Height;

        FrameDescription colorFrameDescription = this.kinectSensor.ColorFrameSource.FrameDescription;

        int colorWidth = colorFrameDescription.Width;
        int colorHeight = colorFrameDescription.Height;

        this.colorMappedToDepthPoints = new DepthSpacePoint[colorWidth * colorHeight];

        this.cameraPoints = new CameraSpacePoint[depthWidth * depthHeight];

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

        // Calculate the WriteableBitmap back buffer size
        this.bitmapBackBufferSize = (uint)((this.bitmap.BackBufferStride * (this.bitmap.PixelHeight - 1)) + (this.bitmap.PixelWidth * this.bytesPerPixel));

        this.kinectSensor.IsAvailableChanged += this.Sensor_IsAvailableChanged;

        this.kinectSensor.Open();

        this.StatusText = this.kinectSensor.IsAvailable ? Properties.Resources.RunningStatusText
                                                        : Properties.Resources.NoSensorStatusText;

        this.DataContext = this;

        this.InitializeComponent();
    }

    /// <summary>
    /// INotifyPropertyChangedPropertyChanged event to allow window controls to bind to changeable data
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Gets the bitmap to display
    /// </summary>
    public ImageSource ImageSource
    {
        get
        {
            return this.bitmap;
        }
    }

    /// <summary>
    /// Gets or sets the current status text to display
    /// </summary>
    public string StatusText
    {
        get
        {
            return this.statusText;
        }

        set
        {
            if (this.statusText != value)
            {
                this.statusText = value;

                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged(this, new PropertyChangedEventArgs("StatusText"));
                }
            }
        }
    }

    /// <summary>
    /// Execute shutdown tasks
    /// </summary>
    /// <param name="sender">object sending the event</param>
    /// <param name="e">event arguments</param>
    private void MainWindow_Closing(object sender, 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;
        }
    }

    /// <summary>
    /// Handles the user clicking on the screenshot button
    /// </summary>
    /// <param name="sender">object sending the event</param>
    /// <param name="e">event arguments</param>
    private void ScreenshotButton_Click(object sender, RoutedEventArgs e)
    {
        // Create a render target to which we'll render our composite image
        RenderTargetBitmap renderBitmap = new RenderTargetBitmap((int)CompositeImage.ActualWidth, (int)CompositeImage.ActualHeight, 96.0, 96.0, PixelFormats.Pbgra32);

        DrawingVisual dv = new DrawingVisual();
        using (DrawingContext dc = dv.RenderOpen())
        {
            VisualBrush brush = new VisualBrush(CompositeImage);
            dc.DrawRectangle(brush, null, new Rect(new Point(), new Size(CompositeImage.ActualWidth, CompositeImage.ActualHeight)));
        }

        renderBitmap.Render(dv);

        BitmapEncoder encoder = new PngBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(renderBitmap));

        string time = System.DateTime.Now.ToString("hh'-'mm'-'ss", CultureInfo.CurrentUICulture.DateTimeFormat);

        string myPhotos = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);

        string path = Path.Combine(myPhotos, "KinectScreenshot-CoordinateMapping-" + time + ".png");

        // Write the new file to disk
        try
        {
            using (FileStream fs = new FileStream(path, FileMode.Create))
            {
                encoder.Save(fs);
            }

            this.StatusText = string.Format(Properties.Resources.SavedScreenshotStatusTextFormat, path);
        }
        catch (IOException)
        {
            this.StatusText = string.Format(Properties.Resources.FailedScreenshotStatusTextFormat, path);
        }
    }

    /// <summary>
    /// Handles the depth/color/body index frame data arriving from the sensor
    /// </summary>
    /// <param name="sender">object sending the event</param>
    /// <param name="e">event arguments</param>
    private void Reader_MultiSourceFrameArrived(object sender, MultiSourceFrameArrivedEventArgs e)
    {
        int depthWidth = 0;
        int depthHeight = 0;

        DepthFrame depthFrame = null;
        ColorFrame colorFrame = 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;
        }

        // We use a try/finally to ensure that we clean up before we exit the function.  
        // This includes calling Dispose on any Frame objects that we may have and unlocking the bitmap back buffer.
        try
        {                
            depthFrame = multiSourceFrame.DepthFrameReference.AcquireFrame();
            colorFrame = multiSourceFrame.ColorFrameReference.AcquireFrame();


            // If any frame has expired by the time we process this event, return.
            // The "finally" statement will Dispose any that are not null.
            if ((depthFrame == null) || (colorFrame == 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
            using (KinectBuffer depthFrameData = depthFrame.LockImageBuffer())
            {
                this.coordinateMapper.MapColorFrameToCameraSpaceUsingIntPtr(depthFrameData.UnderlyingBuffer,
                    depthFrameData.Size,
                    this.cameraPoints);

                this.coordinateMapper.MapColorFrameToDepthSpaceUsingIntPtr(
                    depthFrameData.UnderlyingBuffer,
                    depthFrameData.Size,
                    this.colorMappedToDepthPoints);
            }

            // We're done with the DepthFrame 
            depthFrame.Dispose();
            depthFrame = null;

            // Process Color

            // Lock the bitmap for writing
            this.bitmap.Lock();
            isBitmapLocked = true;

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

            // We're done with the ColorFrame 
            colorFrame.Dispose();
            colorFrame = null;

            for (int y = 0; y < depthHeight; ++y)
            {
                for (int x = 0; x < depthWidth; ++x)
                {
                    // calculate index into depth array
                    int depthIndex = (y * depthWidth) + x;
                    //retrieve the color to space mapping of the current pixel
                    CameraSpacePoint cameraPoint = this.cameraPoints[depthIndex];
                    Console.WriteLine(cameraPoint);
                }
            }




        }
        finally
        {
            if (isBitmapLocked)
            {
                this.bitmap.Unlock();
            }

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

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

    /// <summary>
    /// Handles the event which the sensor becomes unavailable (E.g. paused, closed, unplugged).
    /// </summary>
    /// <param name="sender">object sending the event</param>
    /// <param name="e">event arguments</param>
    private void Sensor_IsAvailableChanged(object sender, IsAvailableChangedEventArgs e)
    {
        this.StatusText = this.kinectSensor.IsAvailable ? Properties.Resources.RunningStatusText
                                                        : Properties.Resources.SensorNotAvailableStatusText;
    }
}

}

所以我一直在尝试使用SDK中的Kinect坐标映射来解决它,但我没有得到这些值。

我收到以下错误:

未处理的类型&#39; System.ArgumentException&#39;发生在Microsoft.Kinect.dll

其他信息:此API已从HRESULT返回异常:0x80070057

任何帮助都会非常感激。

2 个答案:

答案 0 :(得分:1)

如果已安装KinectSDK-v2.0-PublicPreview1407-Setup SDK,请将其卸载并尝试使用新版本KinectSDK-v2.0_1409-Setup here是链接

答案 1 :(得分:1)

 this.cameraPoints = new CameraSpacePoint[depthWidth * depthHeight];

问题在于上面的行。它应该改为

 this.cameraPoints = new CameraSpacePoint[colorhWidth * colorHeight];