как улучшить качество DrawDIB? - PullRequest
1 голос
/ 13 июля 2009

Я кодирую в C ++, GDI Я использую stretchDIBits для рисования изображений в DC.

        ::SetStretchBltMode(hDC, HALFTONE);
        ::StretchDIBits(
            hDC,
            des.left,des.top,des.right - des.left,des.bottom - des.top,
            0, 0,
            img.getWidth(),
            img.getHeight(),
            (img.accessPixels()), 
            (img.getInfo()),
            DIB_RGB_COLORS,
            SRCCOPY
            );

Однако это медленно. Поэтому я перешел на функцию DrawDib.

::SetStretchBltMode(hDC, HALFTONE);
DrawDibDraw(
                        hdd,
                        hDC,
                        des.left,des.top,des.right - des.left,des.bottom - des.top,
                        (LPBITMAPINFOHEADER)(img.getInfo()),
                        (img.accessPixels()), 
                        0, 0,
                        img.getWidth(),
                        img.getHeight(),
                        DDF_HALFTONE
                        );

Однако результат похож на рисование в режиме COLORONCOLOR. Как улучшить качество рисования?

Ответы [ 4 ]

2 голосов
/ 17 июля 2009

Хорошо DrawDibDraw устарел.

Рассматривали ли вы попытку ускорить StretchDIBits? Здесь хороший ответ здесь

Конечно, вы можете сделать это без использования StretchDIBits.

если вы изначально загрузили свое изображение по

hBitmap = LoadImage( NULL, _T( "c:\\Path\File.bmp" ), IMAGE_BITMAP, LR_DEFAULTSIZE, LR_DEFAULTSIZE, LR_LOADFROMFILE );

SIZE size;
BITMAP bmp;
GetObject( (HGDIOBJ)hBitmap, sizeof( BITMAP ), &bmp );
size.cx = bmp.bmWidth;
size.cy = bmp.bmHeight;

Затем вы можете отобразить растровое изображение следующим образом.

HDC hBitmapDC   = CreateCompatibleDC( hDC );

HGDIOBJ hOld    = SelectObject( hBitmapDC, (HGDIOBJ)hBitmap );

SetStretchBltMode( hDc, HALFTONE );

StretchBlt( hDC, rcItem.left,rcItem.top, rcItem.right,rcItem.bottom, hBitmapDC, 0, 0, size.cx, size.cy, SRCCOPY );

SelectObject( hBitmapDC, hOld );
DeleteObject( hBitmapDC );

Конечно, стоит иметь в виду, что вам на самом деле не нужно создавать совместимый DC каждый раз, когда вы включаете, что значительно ускоряет процесс. Просто создайте совместимый DC и выберите для него растровый объект при загрузке изображения. Затем держите его, пока он вам не понадобится. При выключении просто удалите объект, как показано выше.

0 голосов
/ 23 июля 2009

Если вы не хотите использовать opengl / directx / gdi +, но застряли в DIB, я обнаружил, что быстрее всего просто сделать это самостоятельно.

Единственное, вам нужен доступ к фактическим байтам изображения. Кроме того, местом назначения должна быть карта DIBbitmap, поскольку она должна быть перетянута (не растянута) к форме окон.

так что у вас есть 2 байтовых указателя, 1 src и 1 dest. Оба указывают на необработанные байты (каждый пиксель состоит из 3 байтов (RGB)), тогда ваш алгоритм будет выглядеть следующим образом

 //these need to be filled out by you
 //byte *src;   //points to the first raw byte of your source RGB picture
 //byte *dest;  //points to the first raw byte of your destination RGB picture
 //int srcWidth = 640; //width of original image
 //int srcHeight = 480; //height of original image
 //int destWidth = 200; //width of destination image
 //int destHeight = 100; //height of destination image


 void scaleImage(byte *src, byte*dest, int srcWidth, int srcHeight, int destWidth, int destHeight)
 {
      //these are internal counters
      register int srcx;
      register int srcy;
      register int skipx;
      register int skipy;

      skipx = (destWidth>>8)/srcWidth;
      skipy = (destHeight>>8)/srcHeight;

      for(int y=0; y<destHeight; y++)
      {
           //calc from which y coord we need to copy pixel
           register byte *src2 = src + ((srcy>>8)*srcWidth*3);

           for(int x=0; x<destWidth; x++)
           {
                //calc from which x coord we need to copy pixel
                register byte *src3 = src2 + ((srcx>>8)*3);

                //copy rgb
                *dest++ = *src3++;
                *dest++ = *src3++;
                *dest++ = *src3++;

                //go to next x pixel
                srcx += skipx;
           }

           //go to next y pixel
           srcy += skipy;
      }
 }

>> 8 и << 8, которые вы видите разбросанными по коду, - это использование «фиксированной точки». </p>

Чтобы масштабирование выглядело лучше (поскольку это масштабирование выполняется с использованием «ближайшего соседа»), вы должны взять среднее значение между смежным правым пикселем, смежным нижним пикселем и смежным нижним правым пикселем. Убедитесь, что вы не используете деление ('/'), но используйте >> 2, что намного быстрее.

p.s. ну правильно .. код не в моей голове, так что остерегайтесь мелких опечаток

0 голосов
/ 22 июля 2009

Я не знаю, что еще вы делаете в своем приложении или насколько важно рисовать растянутые растровые изображения, но вы можете просто захотеть использовать более современный API, такой как GDI +, DirectX или OpenGL.

Никто не изменил, как работают StretchDIBits или DrawDibDraw с 1995 года или около того - вы действительно хотите что-то, что будет использовать преимущества GPU. (Я ожидал бы, что отрисовка будет «достаточно быстрой» даже с процессором только потому, что процессоры работают намного быстрее, чем тогда, но, очевидно, нет.)

0 голосов
/ 13 июля 2009

Когда вы уменьшаете свое растровое изображение, у вас есть несколько вариантов. Вы можете сделать это медленным способом, когда вы «размываете и подобразуете» полноразмерное изображение, чтобы в тех местах, где у вас был один пиксель, а исходное изображение имело 2+ пикселя, новый пиксель становится средним. Если вы этого не сделаете, вы получите намного более быстрое исполнение, но ваше изображение будет не таким гладким, как вы хотели бы.

StretchDIBits может быть усредняющим пиксели в 2D, что означает, что он просматривает блок из 4+ пикселей из старого изображения, чтобы получить средний цвет нового пикселя. Если это так, вы можете написать собственное 1D усреднение, которое просто усредняет пиксели по той же линии сканирования старого изображения, чтобы получить новый пиксель. Гуру Windows API может знать классный вариант DrawDIBDraw, который делает что-то вроде этого.

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