Создание 16-битных + полутоновых изображений в WPF - PullRequest
1 голос
/ 06 марта 2012

Я хочу создать 16-битное изображение в градациях серого из значений данных в моей программе WPF. В настоящее время я смотрю на использование WriteableBitmap с набором PixelFormats.Gray16.

Однако я не могу заставить это работать, и страница Microsoft (http://msdn.microsoft.com/en-us/magazine/cc534995.aspx) перечисляет формат Gray16 как недоступный для записи через WriteableBitmap, но не предлагает, как еще сделать его таким образом.

В настоящее время мой код работает в цикле, где i представляет высоту изображения и j ширину, и выглядит примерно так:

short dataValue = GetDataSamplePixelValue(myDataValue);

//the pixel to fill with this data value:
int pixelOffset = ((i * imageWidth) + j) * bytesPerPixel;

//set the pixel colour values:
pixels[pixelOffset] = dataValue;

Я получаю изображение с этим, но это просто набор вертикальных черных и белых линий. У меня нет проблем, если я использую только 8-битные данные в градациях серого (в этом случае в приведенном выше примере short изменяется на byte).

Кто-нибудь знает, как создать 16-битное изображение на пиксель или выше в градациях серого с использованием WPF? В конечном итоге это изображение также необходимо сохранить.

Любой совет очень ценится.

EDIT

В дополнение к этому я провел некоторое редактирование и теперь получаю разумное изображение, используя PixelFormat Gray16. Мне очень сложно определить, действительно ли он 16-битный, поскольку подсчет цветов программой изображения дает 256, и я не уверен, что это потому, что изображение ограничено WPF, или, возможно, программа изображения делает это. не поддерживают его, так как, очевидно, многие графические программы игнорируют младшие 8 бит. А пока я буду придерживаться того, что у меня есть.

Для информации код выглядит так:

myBitmap = new WriteableBitmap((int)visualRect.Width, (int)visualRect.Height, 96, 96, PixelFormats.Gray16, null);

int bytesPerPixel = myBitmap.Format.BitsPerPixel / 8;
ushort[] pixels = new ushort[(int)myBitmap.PixelWidth * (int)myBitmap.PixelHeight];

//if there is a shift factor, set the background colour to white:
if (shiftFactor > 0)
{
    for (int i = 0; i < pixels.Length; i++)
    {
        pixels[i] = 255;
    }
}

//the area to be drawn to:
Int32Rect drawRegionRect = new Int32Rect(0, 0, (int)myBitmap.PixelWidth, (int)myBitmap.PixelHeight);

//the number of samples available at this line (reduced by one so that the picked sample can't lie beyond the array):
double availableSamples = myDataFile.DataSamples.Length - 1;

for (int i = 0; i < numDataLinesOnDisplay; i++)
{
    //the current line to use:
    int currentLine = ((numDataLinesOnDisplay - 1) - i) + startLine < 0 ? 0 : ((numDataLinesOnDisplay- 1) - i) + startLine;

    for (int j = 0; j < myBitmap.PixelWidth; j++)
    {                             
        //data sample to use:
        int sampleToUse = (int)(Math.Floor((availableSamples / myBitmap.PixelWidth) * j));

        //get the data value:
        ushort dataValue = GetDataSamplePixelValue(sampleToUse);

        //the pixel to fill with this data value:
        int pixelOffset = (((i + shiftFactor) * (int)myBitmap.PixelWidth) + j);

        //set the pixel colour values:
        pixels[pixelOffset] = dataValue;
    }
}

//copy the byte array into the image: 
int stride = myBitmap.PixelWidth * bytesPerPixel;
myBitmap.WritePixels(drawRegionRect, pixels, stride, 0);

В этом примере startLine и shiftFactor уже установлены и зависят от того, с какой точки в файле данных просматривает пользователь, с shiftFactor только ненулевым в случае файла данных меньше, чем экран, и в этом случае я центрирую изображение по вертикали, используя это значение.

Ответы [ 2 ]

2 голосов
/ 07 марта 2012

найти ошибку в вашем коде или отобразить ваш полный код

следующий пример с изображением grey16 нормальный

  var width = 300;
  var height = 300;

  var bitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Gray16, null);
  var pixels = new ushort[width * height];
  for (var y = 0; y < height; ++y)
    for (var x = 0; x < width; ++x)
    {
      var v = (0x10000*2 * x/width + 0x10000 * 3 * y / height);
      var isMirror = (v / 0x10000) % 2 == 1;
      v = v % 0xFFFF;
      if (isMirror)
        v = 0xFFFF - v;

      pixels[y * width + x] = (ushort)v;
    }

  bitmap.WritePixels(new Int32Rect(0, 0, width, height), pixels, width *2, 0);

  var encoder = new PngBitmapEncoder();
  encoder.Frames.Add(BitmapFrame.Create(bitmap));
  using (var stream = System.IO.File.Create("gray16.png"))
    encoder.Save(stream);
0 голосов
/ 25 марта 2013

Для справки маловероятно, что на экране может отображаться 16-битное изображение в градациях серого, а также этот формат не очень хорошо поддерживается Windows. Например, Windows XP не может даже отображать 16-битное изображение в градациях серого в программе просмотра фотографий, хотя Windows 7+ может (я не уверен насчет Vista, у меня его нет).

Кроме того, метод .NET с открытым TIF не загружает 16-битное изображение в градациях серого.

Решение для загрузки и сохранения 16-битного изображения в градациях серого, и я бы рекомендовал для TIF в целом LibTIFF . Затем у вас есть возможность загрузить весь TIF или построчно, среди других методов. Я рекомендую загружать его построчно, так как тогда вы можете хранить только те данные, которые будут видны на экране, поскольку некоторые TIF-файлы в наши дни становятся очень большими и не могут удерживаться одним массивом.

Так что, в конечном итоге, не беспокойтесь о отображении 16-битной шкалы серого на экране, это может быть ограничено возможностями системы / монитора, и человеческий глаз все равно не может различить эту и 8-битную разницу. Однако, если вам нужно загрузить или сохранить 16-битную версию, используйте LibTIFF.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...