【问题标题】:C - how to read color of a screen pixel (FAST)? (in Windows)C - 如何读取屏幕像素的颜色(FAST)? (在 Windows 中)
【发布时间】:2015-05-19 23:02:50
【问题描述】:

所以我正在寻找一种在 C 代码中读取屏幕像素颜色的方法。
我已经在 C 中找到了 *nix 的实现(它使用 X11/Xlib 库,据我所知,它仅适用于 *nix 系统),我在 linux 机器上尝试了代码,它运行得非常快(它读取 8K 像素大约 1 秒)。
这是我找到并分叉的 C 代码:

#include <X11/Xlib.h>
void get_pixel_color (Display *d, int x, int y, XColor *color)
{
   XImage *image;
   image = XGetImage (d, RootWindow (d, DefaultScreen (d)), x, y, 1, 1,        AllPlanes, XYPixmap);
  color->pixel = XGetPixel (image, 0, 0);
  XFree (image);
  XQueryColor (d, DefaultColormap(d, DefaultScreen (d)), color);
 }

 // Your code
 XColor c;
  get_pixel_color (display, 30, 40, &c);
  printf ("%d %d %d\n", c.red, c.green, c.blue);

我也在寻找适用于 Windows 的等效解决方案。
我遇到了这段代码(我已将有关读取屏幕像素的代码放在“for”循环中):

FARPROC pGetPixel;

HINSTANCE _hGDI = LoadLibrary("gdi32.dll");
if(_hGDI)
{
    pGetPixel = GetProcAddress(_hGDI, "GetPixel");

    HDC _hdc = GetDC(NULL);
if(_hdc)
{
    int i;
    int _red;
    int _green;
    int _blue;
    COLORREF _color;
    ReleaseDC(NULL, _hdc);
    for (i=0;i<8000;i++)
    {
        _color = (*pGetPixel) (_hdc, 30 ,40);

        _red = GetRValue(_color);
        _green = GetGValue(_color);
        _blue = GetBValue(_color);


    }
    ReleaseDC(NULL, _hdc);    
    printf("Red: %d, Green: %d, Blue: %d", _red, _green, _blue);
}
FreeLibrary(_hGDI);

(使用 gdi32.dll 和 windows.h...)
并且代码的“for”部分(我们读取 8K 像素)的运行速度比 C 中的解决方案慢很多。 与 X11/Xlib.h 库 1 秒相比,完成需要 15 秒!

那么,我怎样才能让它变得更好呢?还是有其他更好更快的实现来在 Windows 机器中使用 C 代码读取像素颜色?

先谢谢了!

【问题讨论】:

  • 嗯,32KB/秒的带宽并不值得吹嘘。 Windows 要求程序员成为更聪明的读者,Petzold 的书很好地解释了 BitBlt()。
  • 您要在这里读取多少像素?只有 1 个,还是要检查一大堆?如果是一大堆,getPixel 可能不是这样做的方法,而是一次将整个屏幕捕获到纹理的方法。
  • 是的,我正在尝试阅读一堆...正如我所展示的,*nix 解决方案可以在 1 秒内读取很多像素,而 Windows 解决方案非常慢...任何建议、其他解决方案或资源?我已经在 Windows 中寻找更好的解决方案一段时间了,但我找不到。
  • @HansPassaant - 你能详细说明你的答案吗?你什么意思?它是什么 BitBlt()?如何有效快速地读取屏幕像素?提前谢谢

标签: c colors pixel xlib


【解决方案1】:

我建议使用loop unwinding。基本上,它的作用是在一次迭代中执行循环的多个循环:

// Loop the equivalent of `n` cycles, ignoring the least significant bit
for (unsigned int i = 0; i < (n & ~0x01); i += 2)
{
    do_some_operation(i);
    do_some_operation(i + 1);
}

// Perform the last cycle manually, if one needs to be completed
if (n & 0x01)
{
    do_some_operation(n - 1);
}

在这段代码中,循环忽略了n 的最低有效位(它决定了n 的奇偶性),因此我们可以安全地将i 递增2,并在1 内执行相当于2 个周期循环,这意味着该循环比传统的 for (unsigned int i = 0; i &lt; n; i++) 循环快约 2 倍。最后的if 语句检查n 的奇偶性。如果n 为奇数,则执行循环的最后一个循环。

当然,这可以重新实现以将i 增加 2 以上,但这会变得越来越复杂。还有一个替代方法,Duff's Device。基本上是相同的想法,但是使用了switch/case 块。

【讨论】:

  • 我不认为这是一个循环级别的问题。相反,这是一种驱动程序级别的低效检索信息的方式。如果 OP 要从屏幕上检索许多像素,他最好将屏幕捕获到纹理然后再查看它。
  • 我考虑过拍照然后分析,但整个过程也很慢……只是拍照大约3~4秒左右。 @Levi - “pGetPixel”函数是一个需要大量时间才能完成的函数......我正在寻找全新的实现或读取一堆屏幕像素颜色的方法。为什么 X11/Xlib 解决方案比 Window 的解决方案快?
  • 为什么 X11/Xlib 更快?
  • 是的,我同意我也更喜欢 Linux。但是就没有办法了吗?差异很荒谬......有什么建议吗?
  • 对不起,我不能帮你。我不熟悉 WinAPI。但是我看到@HansPassant 在 BitBlt() 上提到了一些东西?祝你好运;)
【解决方案2】:

经过多次测试,我发现无论是读取单个像素,还是读取什至一个带有BitBlt的小区域。似乎没有任何明确的解决方案。我将尝试使用媒体库,看看我是否可以到达任何地方,但互联网很确定在 Windows 中做这样的事情只是一团糟,而且必须做一些非常糟糕的事情才能做 VNC 或 Fraps 之类的事情。

【讨论】:

    猜你喜欢
    • 2017-08-17
    • 1970-01-01
    • 2013-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多