Преобразовать растровое изображение Format16bppGrayScale в BitmapImage
Я работаю над приложением C# с использованием Intel RealSense SDK. Я использовал этот образец, который может отслеживать людей в цветовой рамке: https://software.intel.com/en-us/articles/diy-pan-tilt-person-tracking-with-intel-realsense-camera
Образец может показать координаты X,Y тела человека, но не его расстояние, если он не видит лицо (координаты Z), вместо этого я хотел бы также записать и отобразить данные глубины (изображение в оттенках серого) людей на экране. Одним из шагов, которые выполняет пример программы, прежде чем она сможет отобразить изображение на экране, является преобразование ImageData из Intel RealSense в растровое изображение Format32bppArgb, а затем преобразование этого позже в BitmapImage.
Вот код, который преобразует ImageData (цвет) в растровое изображение Format32bppArgb, используемое для ImageData из RealSense (из примера):
public Bitmap ToBitmap(Int32 index, Int32 width, Int32 height)
{
Bitmap bitmap = null;
switch (format)
{
case PixelFormat.PIXEL_FORMAT_RGB32:
bitmap = new Bitmap(width, height, pitches[index], System.Drawing.Imaging.PixelFormat.Format32bppArgb, planes[0]);
break;
case PixelFormat.PIXEL_FORMAT_RGB24:
bitmap = new Bitmap(width, height, pitches[index], System.Drawing.Imaging.PixelFormat.Format24bppRgb, planes[0]);
break;
case PixelFormat.PIXEL_FORMAT_DEPTH:
case PixelFormat.PIXEL_FORMAT_DEPTH_RAW:
bitmap = new Bitmap(width, height, pitches[index], System.Drawing.Imaging.PixelFormat.Format16bppGrayScale, planes[index]);
break;
default:
return null;
}
return bitmap;
}
Я создал отдельный метод для преобразования (глубины) ImageData в растровое изображение Format16bppGrayScale, в котором я предварительно установил формат PixelFormat.PIXEL_FORMAT_DEPTH_RAW, я использую его для данных DepthData.
public Bitmap ToDepthBitmap(Int32 index, Int32 width, Int32 height)
{
Bitmap bitmap = null;
format = PixelFormat.PIXEL_FORMAT_DEPTH;
switch (format)
{
case PixelFormat.PIXEL_FORMAT_RGB32:
bitmap = new Bitmap(width, height, pitches[index], System.Drawing.Imaging.PixelFormat.Format32bppArgb, planes[0]);
break;
case PixelFormat.PIXEL_FORMAT_RGB24:
bitmap = new Bitmap(width, height, pitches[index], System.Drawing.Imaging.PixelFormat.Format24bppRgb, planes[0]);
break;
case PixelFormat.PIXEL_FORMAT_DEPTH:
case PixelFormat.PIXEL_FORMAT_DEPTH_RAW:
bitmap = new Bitmap(width, height, pitches[index], System.Drawing.Imaging.PixelFormat.Format16bppGrayScale, planes[index]);
break;
default:
return null;
}
return bitmap;
}
Вот код, который преобразует растровое изображение Format32bppArgb в BitmapImage, а затем показывает его на экране (из примера):
private void Render(Bitmap bitmap, MyTrackedPerson myTrackedPerson)
{
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate ()
{
BitmapImage bitmapImage = ConvertBitmap(bitmap);
if (bitmapImage != null)
{
imgStream.Source = bitmapImage;
}
}));
}
private BitmapImage ConvertBitmap(Bitmap bitmap)
{
BitmapImage bitmapImage = null;
if (bitmap != null)
{
MemoryStream memoryStream = new MemoryStream();
bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Bmp);
memoryStream.Position = 0;
bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memoryStream;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
bitmapImage.Freeze();
}
return bitmapImage;
}
Я снова добавил отдельные методы, чтобы попытаться выполнить те же шаги (Format16bppGrayScale Bitmap to BitmapImage) для потока DepthData:
private void RenderDepth(Bitmap bitmap, MyTrackedPerson myTrackedPerson)
{
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate ()
{
BitmapImage bitmapImage = ConvertDepthBitmap(bitmap);
if (bitmapImage != null)
{
imgStream.Source = bitmapImage;
}
}));
}
private BitmapImage ConvertDepthBitmap(Bitmap bitmap)
{
BitmapImage bitmapImage = null;
if (bitmap != null)
{
MemoryStream memoryStream = new MemoryStream();
var rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
var bitmapCopy = (Bitmap)bitmap.Clone();
var bitmapData = bitmap.LockBits(rect, ImageLockMode.WriteOnly, bitmap.PixelFormat);
var numberOfBytes = bitmapData.Stride * bitmap.Height;
var bitmapBytes = new short[bitmap.Width * bitmap.Height];
var k = 0;
for (int i = 0; i < bitmap.Width; i++)
{
for (int j = 0; j < bitmap.Height; j++)
{
bitmapBytes[k] = (short)bitmapCopy.GetPixel(i, j).ToArgb();
k++;
}
}
var ptr = bitmapData.Scan0;
Marshal.Copy(bitmapBytes, 0, ptr, bitmapBytes.Length);
bitmap.UnlockBits(bitmapData);
bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Bmp);
memoryStream.Position = 0;
bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memoryStream;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
bitmapImage.Freeze();
}
return bitmapImage;
}
Последний пример кода выше основан на ответе на этот вопрос: сгенерируйте 16-битную шкалу полутоновых данных BitmapData и сохраните в файл
К сожалению, приведенный выше код дает исключение аргумента, в котором говорится, что параметр недопустим в этой строке:
bitmapBytes[k] = (short)bitmapCopy.GetPixel(i, j).ToArgb();
Кто-нибудь может указать, если я что-то здесь упускаю? Я делаю это неправильно?