我是Kinect和C#的新手。我试图从Kinect获取深度图像,将其转换为位图以执行一些OpenCV操作然后显示它。问题是,我只得到深度图像的三分之一,其余部分是完全黑色的(如图所示)。这不是原始深度图像,而是绘画后我收到的图像。
这是代码 -
image和image1是我要显示的两个图像画布。
void DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
{
DepthImageFrame Image;
Bitmap bm;
using (Image = e.OpenDepthImageFrame())
{
if (Image != null)
{
this.shortpixeldata = new short[Image.PixelDataLength];
this.depthFrame32 = new byte[Image.Width * Image.Height * Bgr32BytesPerPixel];
bmp = new Bitmap(Image.Width, Image.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
Image.CopyPixelDataTo(this.shortpixeldata);
byte[] convertedDepthBits = this.ConvertDepthFrame(this.shortpixeldata, ((KinectSensor)sender).DepthStream);
BitmapData bmapdata = bmp.LockBits(
new System.Drawing.Rectangle(0, 0, Image.Width, Image.Height),
ImageLockMode.WriteOnly,
bmp.PixelFormat);
IntPtr ptr = bmapdata.Scan0;
Marshal.Copy(convertedDepthBits, 0, ptr, Image.PixelDataLength);
bmp.UnlockBits(bmapdata);
MemoryStream ms1 = new MemoryStream();
bmp.Save(ms1, System.Drawing.Imaging.ImageFormat.Jpeg);
System.Windows.Media.Imaging.BitmapImage bImg = new System.Windows.Media.Imaging.BitmapImage();
bImg.BeginInit();
bImg.StreamSource = new MemoryStream(ms1.ToArray());
bImg.EndInit();
image.Source = bImg;
if (bmp != null)
{
Image<Bgr, Byte> currentFrame = new Image<Bgr, Byte>(bmp);
Image<Gray, Byte> grayImage = currentFrame.Convert<Gray, Byte>().PyrDown().PyrUp();
Image<Gray, Byte> Dest = new Image<Gray, Byte>(grayImage.Size);
CvInvoke.cvCanny(grayImage, Dest, 10, 60, 3);
image1.Source = ToBitmapSource(Dest);
CalculateFps();
}
}
else
{
System.Diagnostics.Debug.WriteLine("depth bitmap empty :/");
}
}
}
private byte[] ConvertDepthFrame(short[] depthFrame, DepthImageStream depthStream)
{
System.Diagnostics.Debug.WriteLine("depthframe len :{0}", depthFrame.Length);
for (int i16 = 0, i32 = 0; i16 < depthFrame.Length && i32 < this.depthFrame32.Length; i16++, i32 += 4)
{
int realDepth = depthFrame[i16] >> DepthImageFrame.PlayerIndexBitmaskWidth;
byte Distance = 0;
int MinimumDistance = 800;
int MaximumDistance = 4096;
if (realDepth > MinimumDistance)
{
//White = Close
//Black = Far
Distance = (byte)(255-((realDepth-MinimumDistance)*255/(MaximumDistance-MinimumDistance)));
this.depthFrame32[i32 + RedIndex] = (byte)(Distance);
this.depthFrame32[i32 + GreenIndex] = (byte)(Distance);
this.depthFrame32[i32 + BlueIndex] = (byte)(Distance);
}
else
{
this.depthFrame32[i32 + RedIndex] = 0;
this.depthFrame32[i32 + GreenIndex] = 150;
this.depthFrame32[i32 + BlueIndex] = 0;
}
}
return this.depthFrame32;
}
我尝试了不同的PixelFormats无济于事。我无法弄清楚这个问题。有人知道我做错了什么吗? 感谢
答案 0 :(得分:0)
我建议使用WritableBitmap
将深度图像复制为可视格式。在PixelFormat
的情况下,该信息在深度图像本身中可用,因此您应该使用与正在捕获的WritableBitmap
相同的格式。
您是否查看了Microsoft提供的任何示例?您可以在Kinect for Windows Samples CodePlex页面找到它们。有几个示例演示了如何将深度数据复制到WritableBitmap
然后输出它。例如,以下是“DepthBasics-WPF”示例应用程序的DepthFrameReady
回调函数:
/// <summary>
/// Event handler for Kinect sensor's DepthFrameReady event
/// </summary>
/// <param name="sender">object sending the event</param>
/// <param name="e">event arguments</param>
private void SensorDepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
{
using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
{
if (depthFrame != null)
{
// Copy the pixel data from the image to a temporary array
depthFrame.CopyDepthImagePixelDataTo(this.depthPixels);
// Get the min and max reliable depth for the current frame
int minDepth = depthFrame.MinDepth;
int maxDepth = depthFrame.MaxDepth;
// Convert the depth to RGB
int colorPixelIndex = 0;
for (int i = 0; i < this.depthPixels.Length; ++i)
{
// Get the depth for this pixel
short depth = depthPixels[i].Depth;
// To convert to a byte, we're discarding the most-significant
// rather than least-significant bits.
// We're preserving detail, although the intensity will "wrap."
// Values outside the reliable depth range are mapped to 0 (black).
// Note: Using conditionals in this loop could degrade performance.
// Consider using a lookup table instead when writing production code.
// See the KinectDepthViewer class used by the KinectExplorer sample
// for a lookup table example.
byte intensity = (byte)(depth >= minDepth && depth <= maxDepth ? depth : 0);
// Write out blue byte
this.colorPixels[colorPixelIndex++] = intensity;
// Write out green byte
this.colorPixels[colorPixelIndex++] = intensity;
// Write out red byte
this.colorPixels[colorPixelIndex++] = intensity;
// We're outputting BGR, the last byte in the 32 bits is unused so skip it
// If we were outputting BGRA, we would write alpha here.
++colorPixelIndex;
}
// Write the pixel data into our bitmap
this.colorBitmap.WritePixels(
new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight),
this.colorPixels,
this.colorBitmap.PixelWidth * sizeof(int),
0);
}
}
}
可以在此处找到此特定课程的完整代码:http://kinectforwindows.codeplex.com/SourceControl/changeset/view/861462899ae7#v1.x/ToolkitSamples1.6.0/C#/DepthBasics-WPF/MainWindow.xaml.cs
“Kinect Explorer”示例是另一个值得查看的好例子,因为它会一次检查所有三个流。它需要未包含在CodePlex存储库中的库,但可以在Kinect for Windows Toolkit中找到。
答案 1 :(得分:0)
好的,我自己想出来了。 它一直躲在明显的视线中。
函数ConvertDepthFrame将字节数组返回到convertedDepthBits的不同大小(其4个独立的通道,因此是原始大小的4倍),我需要在方法调用中使用要复制的数据长度为4 * Image.PixelDataLength: Marshal.Copy(...)
现在工作正常。 唷! :)