【问题标题】:how to Improve DrawDIB's quality?如何提高DrawDIB的质量?
【发布时间】:2013-11-15 05:32:57
【问题描述】:

我正在用 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 模式绘制一样。 如何提高绘图质量?

【问题讨论】:

  • DrawDib 的东西已经过时了。你能解释一下你说的太慢是什么意思吗?您是否尝试在实时视频中执行此操作?您是否尝试将其应用于非常大的图像?需要多长时间?您需要多快?

标签: c++ performance gdi drawdib


【解决方案1】:

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 );

当然,值得记住的是,您实际上并不需要在每次 blt 时创建兼容的 DC,这将大大加快速度。只需创建兼容的 DC 并在加载图像时为其选择位图对象。然后拿着它直到你需要它。关闭时只需 DeleteObject,如上所示。

【讨论】:

  • 感谢 Goz,当图像不太大时,这是一个很好的解决方案。因为 CompatibleDC 占用了 Videocard 的内存,如果 Videocard 上没有足够的内存。这个方法不行
【解决方案2】:

当您缩小位图图像时,您有几个选择。您可以以缓慢的方式对全尺寸图像进行“模糊和二次采样”,以便在您有一个像素且源图像有 2+ 个像素的地方,新像素成为平均值。如果你不这样做,你会获得更快的性能,但你的图像不会像你想要的那样流畅。

StretchDIBits 可能会平均 2D 像素,这意味着它会从旧图像中查找 4+ 像素块以获取新像素的平均颜色。如果是这种情况,您可以编写自己的 1D 平均,它只是平均旧图像的相同扫描线的像素以获得新像素。 Windows api 大师可能知道 DrawDIBDraw 的一个很酷的选项,它可以做这样的事情。

【讨论】:

    【解决方案3】:

    如果你不想使用 opengl/directx/gdi+ 但被 DIB 卡住了,我发现最快的方法就是自己动手。

    唯一的事情是您需要访问图像的实际字节。此外,目的地需要是一个 DIBbitmap,因为它需要被 blitted(而不是 stretchblitted)到您的 windows 窗体。

    所以假设你有 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和

    为了使缩放看起来更好(因为此缩放是使用“最近邻”完成的),您应该取相邻右像素、相邻底部像素和相邻右下像素之间的平均值。 确保不要使用除法 ('/'),​​而是使用 >>2,这样会快得多。

    附言啊对..代码不在我的脑海中,所以要小心小错别字

    【讨论】:

      【解决方案4】:

      我不知道您在应用中还做了什么,也不知道绘制拉伸位图对您有多重要,但您可能只想使用更现代的 API,例如 GDI+ 或 DirectX 或 OpenGL。

      自 1995 年左右以来,没有人改变过 StretchDIBits 或 DrawDibDraw 的工作方式——您确实需要能够利用 GPU 的东西。 (我原以为即使使用 CPU 绘图也会“足够快”,只是因为处理器比当时快得多,但显然不是。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-06
        • 1970-01-01
        • 2021-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多