我正在做一个项目,在这个项目中,我必须用CreateCompatibleBitmap和Bitblt读取屏幕上像素的颜色。不幸的是,这个方法非常慢,我在一个循环中得到了大约60到100 ms的次数。我使用以下代码:
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
有什么建议可以让我加速这个计划吗?
发布于 2022-10-24 19:55:03
您可以使用CreateDIBSection创建一种位图,它允许您访问像素数据,而不是创建一个常规的“兼容”位图,然后使用GetDIBits将像素数据复制到缓冲区中,但是我运行了这样做的基准,这样可以节省时间,但并不是很大。我得到了大约10%的速度改善,这不是很多。
下面的代码,我写得这么快,所以可能犯了个错误。下面的变量dummy的要点是,由于没有输出,所以不会对所有内容进行优化。
#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";
}https://stackoverflow.com/questions/74184601
复制相似问题