Optimization 使用位图/GDI的性能较慢

Optimization 使用位图/GDI的性能较慢,optimization,bitmap,gdi+,Optimization,Bitmap,Gdi+,嗯。 我正在尝试这样做: while(1) { CaptureScreenshot (as BMP) Convert screenshot to 24 bit instead of 32 bit Resize screenshot size Get the BMP bits array of the resized screenshot } 我有它的工作,但我可以得到最好的是18次迭代(截图)每秒。 我需要更多,我想请你帮我改进 我就是这么做的: Start(

嗯。 我正在尝试这样做:

while(1)
{
    CaptureScreenshot (as BMP)
    Convert screenshot to 24 bit instead of 32 bit
    Resize screenshot size 
    Get the BMP bits array of the resized screenshot
}
我有它的工作,但我可以得到最好的是18次迭代(截图)每秒。 我需要更多,我想请你帮我改进

我就是这么做的:

Start()
{
    ULONG_PTR gdiplusToken=0;
    HDC mhCompatibleDC;
    HBITMAP mhCompatibleBitmap;
    HWND mhDesktopWnd;
    HDC mhDesktopDC;
    byte*piRGB=new byte[1200*900*3]

    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    mhDesktopDC = GetDC(GetDesktopWindow());
    mhCompatibleDC = CreateCompatibleDC(mhDesktopDC);
    mhCompatibleBitmap = CreateCompatibleBitmap(mhDesktopDC, 1440, 900);
    SelectObject(mhCompatibleDC, mhCompatibleBitmap);
    moResizeImage = new Bitmap(1200, 900, PixelFormat24bppRGB);
    moGraphics = Gdiplus::Graphics::FromImage(moResizeImage);

    //as you can see to optimize the code, i pre allocate the CompatibleDC (which speed things)
    //I also use the same moGraphics and not creating moResizeImage again and again - BUT from my tests
    //that does not speed things so i guess that DrawImage reallocate moResizeImage memory on each call
    While(1)
    {
        BitBlt(mhCompatibleDC, 0, 0, 1440, 900, mhDesktopDC, 0, 0, SRCCOPY)
        Bitmap oOrgDesktopImage(mhCompatibleBitmap, NULL);//here i have the original desktop image 32 bit (as my display)
        moGraphics->DrawImage(&oOrgDesktopImage, 0, 0, 1200, 900);(here it converts it to 24 bit as i need and do the resize)

        //now I take the bits part of the BMP and copy it to piRGB
        Gdiplus::BitmapData bitmapData;
        Gdiplus::Rect rect(0, 0, 1200, 900);

        if (Gdiplus::Ok == moResizeImage->LockBits(&rect, Gdiplus::ImageLockModeRead , moResizeImage->GetPixelFormat(),&bitmapData))
        {
            int len = bitmapData.Height * std::abs(bitmapData.Stride);


            for (int i = 0; i < len; i = i + 1)//18
            {
                *piRGB = ((BYTE*)bitmapData.Scan0)[i++];
                piRGB++;
            }
            moResizeImage->UnlockBits(&bitmapData);

        }
    //here i do things with piRGB but these things are not counted it the timer so you can assume here the code ends 
    //as said as the code looks now, i can fill piRGB ~18 times (18loops) in 1 second. I must improve that/
    //my knowledge in GDI is very poor and i hope you can provide code to your suggestions - THANKS
    }
Start()
{
ULONG_PTR gdiplusToken=0;
HDC-mh相容性;
HBITMAP MH兼容EBITMAP;
HWND mhDesktopWnd;
HDC-mhdc;
字节*piRGB=新字节[1200*900*3]
GdiplusStartup(&gdiplusToken,&gdiplusStartupInput,NULL);
mhDesktopDC=GetDC(GetDesktopWindow());
mhCompatibleDC=CreateCompatibleDC(mhDesktopDC);
mhCompatibleBitmap=CreateCompatibleBitmap(mhDesktopDC,1440900);
选择对象(mhCompatibleDC、mhCompatibleBitmap);
moResizeImage=新位图(1200、900,像素格式24bpprgb);
moGraphics=Gdiplus::Graphics::FromImage(moResizeImage);
//正如您所看到的,为了优化代码,我预先分配了CompatibleDC(这加快了速度)
//我也使用相同的图像,并不是一次又一次地创建moResizeImage,而是通过我的测试
//这并不能加快速度,所以我猜DrawImage会在每次调用时重新分配更多SizeImage内存
而(1)
{
BitBlt(mhCompatibleDC、0、0、1440、900、mhDesktopDC、0、0、SRCCOPY)
位图oOrgDesktopImage(mhCompatibleBitmap,NULL);//这里有原始桌面图像32位(作为我的显示器)
moGraphics->DrawImage(&oOrgDesktopImage,0,0,1200,900);(在这里,它根据需要将其转换为24位并调整大小)
//现在,我将BMP的位部分复制到piRGB
Gdiplus::BitmapData BitmapData;
Gdiplus::Rect Rect(0,0,1200,900);
if(Gdiplus::Ok==moResizeImage->LockBits(&rect,Gdiplus::ImageLockModeRead,moResizeImage->GetPixelFormat(),&bitmapData))
{
int len=bitmapData.Height*std::abs(bitmapData.Stride);
对于(int i=0;i解锁位(&bitmapData);
}
//在这里,我使用piRGB做一些事情,但是这些事情不计入计时器,所以您可以假设代码在这里结束
//正如代码现在看起来所说的,我可以在1秒内填充piRGB~18次(18个循环)。我必须改进这一点/
//我在GDI方面的知识非常贫乏,我希望您能为您的建议提供代码-谢谢
}
如果我们看一下while部分,那么它每秒运行18次。 如果我在while中删除所有代码并只保留 比特呼叫 然后我每秒有300个循环。 如果我加上 位图oOrgDesktopImage(mhCompatibleBitmap,NULL); 我每秒有160圈。 如果我添加moGraphics->DrawImage(&oOrgDesktopImage,0,0,1200,900)调用 我每秒有19个循环。 添加其余代码(for循环)将其减少到18个循环

Start(){
    HDC mhCompatibleDC, mhDesktopDC, hdc;
    HBITMAP hBitmap, hBitmapOld;
    unsigned char *piRGB= NULL;
    int i;

    mhDesktopDC = GetDC(GetDesktopWindow());

    hdc = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
    mhCompatibleDC = CreateCompatibleDC(hdc);
    hBitmap = NewDIBSection(1200, 900, (void **)&piRGB);
    if(hBitmap == NULL){/* Error */}
    hBitmapOld = SelectObject(mhCompatibleDC, hBitmap);
    //Now piRGB points to RGB data of mhCompatibleDC
    DeleteDC(hdc);

    //SetStretchBltMode(mhCompatibleDC, HALFTONE); //for better quality


    for(i = 0; i < 200; i++){
        BitBlt(mhCompatibleDC, 0, 0, 1200, 900, mhDesktopDC, 0, 0, SRCCOPY);
        //StretchBlt(mhCompatibleDC, 0, 0, 1200, 900, mhDesktopDC, 0, 0, 1440, 900, SRCCOPY);
    }

    SelectObject(mhCompatibleDC, hBitmapOld);
    DeleteDC(mhCompatibleDC);
    DeleteObject(hBitmap);
    ReleaseDC(GetDesktopWindow(), mhDesktopDC);
}

HBITMAP NewDIBSection(int cx, int cy, void **ppBits){
    HBITMAP hbitmap = NULL;
    LPBITMAPINFO lpbmi;
    HDC hdc;

    lpbmi = (LPBITMAPINFO)calloc(1, sizeof (BITMAPINFO) + 4 * sizeof(DWORD));
    if(!lpbmi){return NULL;}

    ZeroMemory(&lpbmi->bmiHeader, sizeof(BITMAPINFOHEADER));
    lpbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    lpbmi->bmiHeader.biWidth = cx;
    lpbmi->bmiHeader.biHeight = -cy;
    lpbmi->bmiHeader.biPlanes = 1;
    lpbmi->bmiHeader.biBitCount = 24;
    lpbmi->bmiHeader.biCompression = BI_RGB;

    hdc = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
    hbitmap = CreateDIBSection(hdc, lpbmi, DIB_RGB_COLORS, ppBits, NULL, 0);

    DeleteDC(hdc);
    free(lpbmi);

    return hbitmap;
}

valter

使用档案器,查看时间花在哪里。谢谢Eric,我已经编辑了问题-我在问题的末尾添加了时间使用
bitblt
可以获得300 fps的速度,这真是太奇怪了。通常,一辆桌面休闲车的速度是30-60 fps。无论如何,你在做一些多余的事情,比如你不需要
oOrgDesktop图像
bitmap。您可以直接
stretchblt
mhCompatibleDC(1200x900)
然后从这个兼容的DC中获取位。在现代机器上,将数据从系统内存移到图形内存或移回图形内存通常是瓶颈。每秒可以BitBlt 300次,因为这只是将图形内存复制到图形内存中。当您尝试将所有数据移到系统内存中,以便可以使用G对其进行操作时DI+,你付出了高昂的代价。我会开始尝试减少通过图形总线移动的数据量的方法。尝试先在卡上进行大小调整和32到24位的转换,这样就可以减少数据量。嗨,瓦尔特。非常感谢你的代码。我添加了它,它改进了计时。现在1秒内有24个循环tead的18.i.E基本上StretchBlt()在一秒钟内执行24次,因为这是while循环中唯一的一行。很少有评论:1)如果我删除hdc=CreateIC(TEXT(“DISPLAY”),NULL,NULL,NULL;然后只放置hdc=NULL;那么它在同一时间运行。也就是说,至少在我的计算机上,设置hdc=CreateIC(TEXT(“DISPLAY”)没有提高时间-你知道为什么吗?除了最后一条注释(太长),2)这一行:lpbmi=(LPBITMAPINFO)calloc(1,sizeof(BITMAPINFO)+4*sizeof(DWORD))为什么+4*sizeof(DWORD)?不管怎样,我只是声明它是本地的,即BITMAPINFO obmi;它的工作原理是一样的。3)hbitmap最终需要发布吗?我在MSDN中没有发现任何提到这一点。4)你认为我能做的任何事,在一秒钟内拥有24个以上的屏幕截图-最终结果是将图像转换为YUV格式。也就是说,我真正需要的是尽可能多的以YUV格式(我已经有转换为YUV的功能)@user3547277当您使用
mhCompatibleDC
(请参见编辑)时,必须在一秒钟内释放hBitmap。不幸的是,我知道没有办法使它更快,虽然我的每秒速度不是24帧,而是70帧。出于好奇,你能用
bitblt
而不是
StretchBlt
来测试它吗?用bitblt而不是StretchBlt,我每秒能收到700次呼叫。(我的图形卡中有点慢)例如x30更快。如果你尝试另一个高度,你的结果显示3600/360=X10,你会看到更糟糕的结果。例如,当组织图像和新图像的高度不一样时。如果运行200次代码,我会得到:BitBlt->312毫秒拉伸blt->8.5秒!@user3547277我要做的是:使用
BitBlt
并用assemply a操作位nd
xmm
寄存器。
BitBlt -> 368 msec
StretchBlt -> 2,5 - 3,6 sec!