2009-07-13 2 views
1

Я кодирую в C++, gdi Я использую stretchDIBits для рисования изображений в постоянном токе.Как улучшить качество DrawDIB?

 ::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.

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

+2

Материал 'DrawDib' в значительной степени устарел. Можете ли вы объяснить, что вы подразумеваете слишком медленно? Вы пытаетесь сделать это в режиме реального времени? Вы пытаетесь применить его к очень крупным изображениям? Сколько времени это занимает, и как быстро вам это нужно? –

ответ

0

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

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

2

Well DrawDibDraw устарел.

Считаете ли вы попытку ускорить StretchDIBits? Есть хороший ответ here

Вы можете, конечно, сделать это, не используя 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 каждый раз, когда вы BLT, которая позволит ускорить процесс значительно. Просто создайте совместимый DC и выберите для него растровый объект при загрузке изображения. Затем держите его, пока оно вам не понадобится. При выключении просто DeleteObject, как показано выше.

+0

Спасибо Goz, Это хорошее решение, когда изображение не слишком велико. потому что CompatibleDC занимает память Videocard, если на Videocard недостаточно памяти. этот метод не будет работать – user25749

-2

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

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

-1

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

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

так что у вас есть 2 байт указателя, 1 src и 1 dest.И указывая на rawbytes (каждый пиксель состоит из 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, который вы видите, рассеянные по коду является использование " фиксированная точка'.

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

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

Смежные вопросы