Как я могу сохранить / загрузить 16-разрядное изображение в .net x64?

StackOverflow https://stackoverflow.com/questions/2294570

Вопрос

Раньше, когда я использовал win32, я использовал Свободное изображение для того, чтобы загружать и сохранять растровые изображения разрядностью более 8 бит.Это каждое изображение, с которым я работаю, поскольку я занимаюсь медицинской визуализацией, и, прежде чем кто-нибудь что-нибудь скажет, да, я и мои клиенты потратили много денег на мониторы высокой яркости и контрастности с 11 или 12 битами динамического диапазона.На самом деле, если вам интересно, требования ACR к проведению маммографии включите монитор с динамическим диапазоном не менее 10 бит.

Я просто перешел на x64 из-за нехватки памяти и для того, чтобы перенести всю свою разработку на одну платформу и режим компиляции.Я бы предпочел не возвращаться к win32, и мои клиенты прямо здесь со мной (и действительно вынуждают к изменениям).FreeImage не компилируется в 64-разрядной версии Windows;у него есть директива _asm в коде, которую компилятор просто не может обработать.

Я подумал, что попробую встроенную поддержку .NET в классах Microsoft.Короче говоря, длинная история:Они не работают и выходят из строя с очень ограниченным количеством сообщений об ошибках.Я подозреваю, что это потому, что Microsoft по-прежнему не поддерживает класс Format16bppGrayScale.

Возможно, в моем коде есть проблема.Вот мой код для написания:

Bitmap theBitmap = new Bitmap(inImage.XSize, inImage.YSize, PixelFormat.Format16bppGrayScale);

//have to go with lockbits
Rectangle rect = new Rectangle(0, 0, theBitmap.Width, theBitmap.Height);
System.Drawing.Imaging.BitmapData bmpData =
    theBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
    PixelFormat.Format16bppGrayScale);
IntPtr ptr = bmpData.Scan0;
int theByteSize = theBitmap.Width * theBitmap.Height *2;
byte[] theByteBuffer = new byte[theByteSize];
System.Buffer.BlockCopy(inImage.Data, 0, theByteBuffer, 0, theByteSize);
System.Runtime.InteropServices.Marshal.Copy(theByteBuffer, 0, ptr, theByteSize);
theBitmap.UnlockBits(bmpData);

theBitmap.Save(inDirectory + "\\" + inName);
theBitmap.Dispose();

Этот код завершает работу программы с

An unhandled exception of type 
 'System.Runtime.InteropServices.ExternalException' occurred in 
 System.Drawing.dll

Additional information: A generic error occurred in GDI+.

Интересно, тем более что я никогда не хочу выводить это изображение на экран вот так (хотя это было бы неплохо!), а просто хочу использовать функцию сохранения / загрузки.Изображение записывается на диск (даже несмотря на сбой программы), и следующий код чтения также приводит к сбою программы:

Bitmap theBitmap = new Bitmap(theCompleteName, false);
ushort[] theData = new ushort[theBitmap.Width * theBitmap.Height];
int x, y;

switch (theBitmap.PixelFormat)
{
    case PixelFormat.Format16bppGrayScale:
        //have to go with lockbits
        {           
            Rectangle rect = new Rectangle(0, 0, theBitmap.Width, theBitmap.Height);
            System.Drawing.Imaging.BitmapData bmpData = 
                theBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly,
                PixelFormat.Format16bppGrayScale);
            IntPtr ptr = bmpData.Scan0;//scanline approach left over from FreeImage

            for (y = 0; y < theBitmap.Height; ++y){
                byte[] scanline = new byte[theBitmap.Width*2];
                System.Runtime.InteropServices.Marshal.Copy(ptr, scanline, y * theBitmap.Width * 2, theBitmap.Width * 2);
                System.Buffer.BlockCopy(scanline, 0, theData, y * theBitmap.Width * 2, theBitmap.Width * 2);
            }
            theBitmap.UnlockBits(bmpData);
        }
        break;
    //for colors, just take the red and call it a day


    case PixelFormat.Format24bppRgb:
    case PixelFormat.Format32bppArgb://really stupid reading code, always works
        for (y = 0; y < theBitmap.Height; ++y) {
            for (x = 0; x < theBitmap.Width; ++x) {
                theData[y * theBitmap.Width + x] = (byte)(theBitmap.GetPixel(x, y).R);
            }
        }
        break;
}
theNewImage = new ImageContainer(theData, theBitmap.Width, theBitmap.Height, inName, inAssessmentID);
theBitmap.Dispose();//not needed, anymore

Этот код завершает работу программы с ошибкой:

An unhandled exception of type 'System.ArgumentException' occurred in System.Drawing.dll

Additional information: Parameter is not valid.

Эти результаты говорят мне, что Microsoft все еще не исправила часть Format16bppGrayScale в перечислении PixelFormat.Это позор.

Итак, что я могу использовать для загрузки и сохранения 16-разрядных изображений в оттенках серого на x64 с помощью .NET?

(РЕДАКТИРОВАТЬ:Я должен добавить, что, хотя я могу сохранять изображения DICOM, мне нужно проводить эксперименты с данными, не относящимися к пациенту, чтобы убедиться, что алгоритмы работают правильно, и так далее.DICOM требует набора пользовательских идентификаторов и других обязательных полей, которые являются излишними для того, что мне нужно;На данный момент мне просто нужны изображения, а не данные пациента).

Это было полезно?

Решение

Свободное изображение может быть скомпилированным до x64.Следуя инструкциям здесь вы можете обойти _asm директива .В нижней части страницы также есть скомпилированная 64-разрядная библиотека dll.

Последняя версия (3.15.1) уже содержит это исправление.Я взял исходный дистрибутив, чтобы попробовать (мне любопытно использовать FreeImage в моем собственном проекте), и платформа x64 сразу же отлично компилируется.

Другие советы

На самом деле я не отвечаю на ваш вопрос, но ранее использовал компонент ImageDraw, продаваемый Неоднямический и определенно рекомендовал бы (и использовал) его снова.Это не бесплатно, но вполне стоит небольших инвестиций.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top