首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Bitblt快速读取像素颜色

用Bitblt快速读取像素颜色
EN

Stack Overflow用户
提问于 2022-10-24 17:14:21
回答 1查看 67关注 0票数 2

我正在做一个项目,在这个项目中,我必须用CreateCompatibleBitmap和Bitblt读取屏幕上像素的颜色。不幸的是,这个方法非常慢,我在一个循环中得到了大约60到100 ms的次数。我使用以下代码:

代码语言:javascript
复制
HDC hdc = GetDC(NULL), hdcMem = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, ScreenX, ScreenY);
BITMAPINFOHEADER bmi = { 0 };
bmi.biSize = sizeof(BITMAPINFOHEADER);
bmi.biPlanes = 1;
bmi.biBitCount = 24;
bmi.biWidth = ScreenX;
bmi.biHeight = -ScreenY;
bmi.biCompression = BI_RGB;
SelectObject(hdcMem, hBitmap);
BitBlt(hdcMem, 0, 0, ScreenX, ScreenY, hdc, 0, 0, SRCCOPY);
GetDIBits(hdc, hBitmap, 0, ScreenY, ScreenData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
DeleteObject(hBitmap);
DeleteDC(hdcMem);
ReleaseDC(NULL, hdc);

大部分时间(95%)用于Bitblt函数。我读到它花了很长时间,因为Bitblt必须转换颜色格式,但我不明白我如何才能避免这种情况。

我使用Windows 11,屏幕res是FHD1920x1080

有什么建议可以让我加速这个计划吗?

EN

回答 1

Stack Overflow用户

发布于 2022-10-24 19:55:03

您可以使用CreateDIBSection创建一种位图,它允许您访问像素数据,而不是创建一个常规的“兼容”位图,然后使用GetDIBits将像素数据复制到缓冲区中,但是我运行了这样做的基准,这样可以节省时间,但并不是很大。我得到了大约10%的速度改善,这不是很多。

下面的代码,我写得这么快,所以可能犯了个错误。下面的变量dummy的要点是,由于没有输出,所以不会对所有内容进行优化。

代码语言:javascript
复制
#include <vector>
#include <iostream>
#include <Windows.h>
#include <chrono>

namespace c = std::chrono;

void get_screen_bytes1(void* ScreenData, int ScreenX, int ScreenY) {
    HDC hdc = GetDC(NULL), hdcMem = CreateCompatibleDC(hdc);
    HBITMAP hBitmap = CreateCompatibleBitmap(hdc, ScreenX, ScreenY);
    BITMAPINFOHEADER bmi = { 0 };
    bmi.biSize = sizeof(BITMAPINFOHEADER);
    bmi.biPlanes = 1;
    bmi.biBitCount = 24;
    bmi.biWidth = ScreenX;
    bmi.biHeight = -ScreenY;
    bmi.biCompression = BI_RGB;
    SelectObject(hdcMem, hBitmap);
    BitBlt(hdcMem, 0, 0, ScreenX, ScreenY, hdc, 0, 0, SRCCOPY);
    GetDIBits(hdc, hBitmap, 0, ScreenY, ScreenData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
    DeleteObject(hBitmap);
    DeleteDC(hdcMem);
    ReleaseDC(NULL, hdc);
}

struct bitmap_info {
    HBITMAP handle;
    uint8_t* data;
};

bitmap_info get_screen_bytes2(int wd, int hgt) {
    HDC hdc_scr = GetDC(NULL);
    BITMAPINFO bmi;
    memset(&bmi, 0, sizeof(BITMAPINFO));
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = wd;
    bmi.bmiHeader.biHeight = -hgt; 
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 24;
    bmi.bmiHeader.biCompression = BI_RGB;

    bitmap_info bi;
    bi.handle = CreateDIBSection(hdc_scr, &bmi, DIB_RGB_COLORS, (void**)bi.data, NULL, NULL);

    HDC hdc = CreateCompatibleDC(hdc_scr);
    auto hbm_old = SelectObject(hdc, bi.handle);
    BitBlt(hdc, 0, 0, wd, hgt, hdc_scr, 0, 0, SRCCOPY);
    SelectObject(hdc, hbm_old);
    DeleteDC(hdc);
    ReleaseDC(NULL, hdc_scr);

    return bi;
}

int main() {
    constexpr auto scr_wd = 2560;
    constexpr auto scr_hgt = 1440;

    std::vector<uint8_t> buffer(scr_wd * scr_hgt * 3);
    std::chrono::high_resolution_clock timer;

    int dummy;
    double sum = 0.0;
    int n = 100;
    for (int i = 0; i < n; ++i) {
        auto start = timer.now();
        get_screen_bytes1(buffer.data(), scr_wd, scr_hgt);
        sum += c::duration_cast<c::microseconds>(timer.now() - start).count();
        dummy += buffer[0];
    }
    double time1 = sum / n;
    std::cout << "get_screen_bytes1 => " << time1 << "\n";

    sum = 0.0;
    for (int i = 0; i < n; ++i) {
        auto start = timer.now();
        auto bmp_info = get_screen_bytes2( scr_wd, scr_hgt);
        sum += c::duration_cast<c::microseconds>(timer.now() - start).count();
        dummy += bmp_info.data[0];
        DeleteObject(bmp_info.handle);
    }
    double time2 = sum / n;
    std::cout << "get_screen_bytes2 => " << time2 << "\n";
    std::cout << dummy << "\n";
    std::cout << "pcnt speed improvement => " << time2 / time1 << "\n";

}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74184601

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档