如何在Linux中进行高帧率的屏幕截图(编程)

5
首先我想说,我已经阅读了很多关于这个问题的内容,并学习了许多方法,但我还没有能够在Linux中完成它。
我的项目是一个带有Arduino的环境灯效果,因此我需要截取桌面的屏幕截图并分析其颜色。
一开始我使用Processing 2.0和'java.awt'中的类'Robot'。最初我每秒可以拍摄5帧,然后我得到了13fps。这很有效,但我想要更好的性能,所以我开始阅读相关资料。
在Windows或Mac中,您可以使用库直接访问'frameBuffer',因此可以轻松快速地截取屏幕截图。
在Ubuntu中,我尝试了python、Gtk、PIL、Qt等等,其中最快的方式是GTK,但我只能获得约15fps。
我的问题是:我希望跨平台实现,但我更喜欢我的程序首先在Linux上运行,然后在Windows上(我不太喜欢Windows:P)。
所以,第一个问题是:Python能提供这种性能吗?因为我认为C++可能是更好的选择。
第二个问题是:我需要做什么?我已经阅读了关于Xlib(X11)的内容,但找不到让我截取屏幕截图的文档。此外,我知道例如FFmpeg这样的强大工具,但不知道如何实现它。
希望您能帮助我(如果我犯了任何错误,请原谅)。

2
你尝试过使用fbgrab吗?也许这会对你有所帮助,只是一个想法。 - cerkiewny
@pirobtumen,你可以通过直接读取/dev/fb1来访问它,但是在用户空间中进行任何活动都需要从帧缓冲区复制大量内核空间数据。我同意你可以做得比保存到文件更好。 - cerkiewny
@cerkiewny 不,我不这么认为。我将那个问题标记为重复,因为问题的提问者更喜欢使用C而不是Python(出于性能考虑),而事实上StackOverflow上已经有一个答案展示了如何在Linux中使用Xlib用C进行截屏。但你的问题被归类为一个新的(非常好的)问题。 - Raydel Miranda
@RaydelMiranda 哦,我不是指那个,我只是好奇是否存在重新映射的方法。 - cerkiewny
@cerkiewny,正如我在之前的评论中所说,这是一个非常好的问题,我建议你在这里发布它。 :D - Raydel Miranda
显示剩余6条评论
1个回答

2
这在跨平台上的实现可能需要大量的工作。如果你最终目标是 Windows,为什么不使用 amblone 项目,它似乎可以完全满足你的需求?
无论如何,以下是一个使用 ffmpeg 和 graphicsmagick 的解决方案,速度非常快(在我的 i7 8GB 笔记本电脑上)。ffmpeg 捕捉确切的一个屏幕,将其缩小到最小的正方形大小,将输出传输到 graphicsmagick convert,将其调整为 1x1 像素,然后报告图像的 RGB 值。 http://amblone.com/guide
#!/bin/bash

mkfifo /tmp/screencap.fifo

while true
    do
        # this version will send the info to a fifo
        # ffmpeg -y -loglevel error -f x11grab -s 1920x1080 -i :0.0 -s 32x32 \
        # -vframes 1 -f image2 -threads 2 - |  gm convert - -resize 1x1 \
        # txt:- > /tmp/screencap.fifo

        # this version will write out the info to the command line
        # and will show you what is going on.
        ffmpeg -y -loglevel error -f x11grab -s 1920x1080 -i :0.0 -s 32x32 \
         -vframes 1 -f image2 -threads 2 - |  gm convert - -resize 1x1 txt:-
    done
exit

这将会给你类似下面的结果:
0,0: ( 62, 63, 63) #3E3F3F
0,0: (204,205,203) #CCCDCB
0,0: ( 77, 78, 76) #4D4E4C

0,0是正在读取的像素位置。括号中的数字是相应的R、G、B值,末尾的数字是典型的html十六进制值。在上面的情况下只有1个像素,但如果你想把基本方向作为广义RGB值,你只需将上述-resize 1x1更改为-resize 3x3,你会得到类似以下的结果:

0,0: ( 62, 63, 65) #3E3F41
1,0: ( 90, 90, 91) #5A5A5B
2,0: (104,105,106) #68696A
0,1: ( 52, 51, 52) #343334
1,1: ( 60, 60, 59) #3C3C3B
2,1: ( 64, 64, 64) #404040
0,2: ( 49, 49, 50) #313132
1,2: ( 60, 60, 60) #3C3C3C
2,2: ( 65, 65, 65) #414141

我会把这些信息传递给你的Arduino。
FFmpeg非常好用,但你需要记住将屏幕捕获位(在我的例子中是-f x11grab)替换为您的Windows系统所使用的。这里有一个更详细的SO链接
如果你真的坚持要制作跨平台应用程序,那么我建议你深入研究具有Python绑定的OpenCV,并使用帧缓冲设备作为视频输入,将结果缩小到1x1像素,并使用结果颜色的平均值通过某种类型的UDP广播来驱动你的PWM。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接