Преобразование 12-битного моно chrome изображения в 8-битную шкалу серого - PullRequest
0 голосов
/ 21 января 2020

У меня есть плата датчика изображения для встроенной разработки, для которой мне нужно захватить поток изображений и вывести их в 8-битном моно chrome / оттенках серого. Выходной сигнал тепловизора 12-битный моно chrome (который занимает 2 байта на пиксель).

В коде у меня есть IntPtr в буфер памяти, который содержит данные 12-битного изображения, от который я должен извлечь и преобразовать эти данные в 8-битное изображение. В памяти это выглядит примерно так (при ярком свете, активирующем пиксели):

enter image description here

Как видите, каждый второй байт содержит младший бит что я хочу отбросить, сохраняя тем самым только нечетные байты (иначе говоря). Лучшее решение, которое я могу придумать, - это перебирать память, но в этом-то и проблема. Я не могу заставить это работать. Мне нужна помощь с алгоритмом в C#, чтобы сделать это.

Вот пример изображения, которое представляет прямое создание Bitmap объекта из IntPtr следующим образом:

bitmap = new Bitmap(imageWidth, imageHeight, imageWidth, PixelFormat.Format8bppIndexed, pImage);

Click to expand in order to view correct representation

// Failed Attempt #1
unsafe
{
    IntPtr pImage;  // pointer to buffer containing 12-bit image data from imager
    int i = 0, imageSize = (imageWidth * imageHeight * 2);  // two bytes per pixel
    byte[] imageData = new byte[imageSize];
    do
    {
        // Should I bitwise shift?
        imageData[i] = (byte)(pImage + i) << 8;  // Doesn't compile, need help here!
    } while (i++ < imageSize);
}

// Failed Attempt #2
IntPtr pImage;  // pointer to buffer containing 12-bit image data from imager
imageSize = imageWidth * imageHeight;
byte[] imageData = new byte[imageSize];
Marshal.Copy(pImage, imageData, 0, imageSize);
// I tried with and without this loop. Neither gives me images.
for (int i = 0; i < imageData.Length; i++)
{
    if (0 == i % 2) imageData[i / 2] = imageData[i];
}
Bitmap bitmap;
using (var ms = new MemoryStream(imageData))
{
    bitmap = new Bitmap(ms);
}
// This also introduced a memory leak somewhere.

В качестве альтернативы, если есть способ сделать это с Bitmap, byte[], MemoryStream, et c. это работает, у меня все уши, но все, что я пробовал, провалилось.

1 Ответ

0 голосов
/ 27 января 2020

Вот алгоритм, который мои коллеги помогли сформулировать. Создает два новых (неуправляемых) указателя; один 8-битный, а другой 16-битный.

Шагая по одному слову за раз и сдвигая последние 4 бита источника, мы получаем новое 8-битное изображение только с MSB. В каждом буфере одинаковое количество слов, но поскольку слова имеют разные размеры, они прогрессируют с разной скоростью, пока мы их перебираем.

unsafe
{
    byte* p_bytebuffer = (byte*)pImage;
    short* p_shortbuffer = (short*)pImage;

    for (int i = 0; i < imageWidth * imageHeight; i++)
    {
        *p_bytebuffer++ = (byte)(*p_shortbuffer++ >> 4);
    }
}

С точки зрения производительности это кажется очень быстрым без ощутимая разница в частоте кадров.

Особая благодарность @Herohtar за то, что он потратил много времени на общение со мной, пытаясь помочь мне решить эту проблему.

...