如何通过ADB获取屏幕像素的颜色

13

我需要获取安卓手机屏幕上特定点的颜色信息。

是否可以通过ADB实现?

目前,我正在使用内置命令screencap来捕获整个屏幕,然后读取特定点的颜色。 但是,这样做速度太慢了。

3个回答

18

我会回答自己的问题。答案可能与设备相关(nexus7 2013),您可以根据自己的设备进行调整。

1.首先,我发现命令 screencap screen.png 非常慢,因为它花费大部分时间将图像转换为png文件类型。因此,为了节省时间,第一步是将屏幕转储到原始数据文件中。 adb shell screencap screen.dump

2.检查文件大小。我的屏幕分辨率为1920*1200,文件大小为9216012字节。注意到 9216012 = 1920 * 1200 * 4 +12,我猜测数据文件使用4字节来存储每个像素的信息,并使用另外12字节进行某些神秘的操作。再截取几个屏幕,我发现每个文件的头12个字节都相同。因此,额外的12个字节在数据文件的开头。

3.现在,使用ddhd就很简单了。假设我想获取(x,y)处的颜色: let offset=1200*$y+$x+3 dd if='screen.dump' bs=4 count=1 skip=$offset 2>/dev/null | hd

我得到的输出如下: 00000000: 4b 73 61 ff s 21e sum 21e 其中的4b 73 61 ff就是我的答案。


不错的解决方案,但为什么我在手机上添加“| hd”到结尾时无法执行命令,但在adb.exe控制台中执行时可以执行?“| hd”是什么意思? - Kitze
hdhexdump 用于显示二进制数据。例如,如果您在文本文件中有 "123",则 hd THE-FILE 将得到 31 32 33。请问您的命令是什么? - superweijiafeng
嗨,我不是很了解坐标,为什么 $y 要乘以 1200 而不是 1920 呢? - CSJ
1
4b 73 61 ff 转换成什么?RGB颜色?为什么是4个字节? - jmspaggi
2
回复自己。顺序为红色、绿色、蓝色、透明度。 - jmspaggi
显示剩余3条评论

4

如果您的手机已经获取了root权限,并且您知道它的framebuffer格式,那么您可以使用ddhd(十六进制转储)直接从framebuffer文件中获取像素表示:

adb shell "dd if=/dev/graphics/fb0 bs=<bytes per pixel> count=1 skip=<pixel offset> 2>/dev/null | hd"

通常情况下<每像素字节数>= 4<像素偏移量> = Y *宽度+ X,但在您的手机上可能会有所不同。

我输入了 adb shell "dd if=/dev/graphics/fb0 bs=4 count=1 skip=1000 2>/dev/null | hd",它返回了 Usage: hd [-b base] [-c count] [-r delay] file。看起来 'hd' 是在我的 bash shell 中执行而不是 adb shell。我尝试了以下操作:I - superweijiafeng
1
很可能你没有root权限,所以dd没有产生任何输出供hd处理。 - Alex P.
我尝试了以下命令: adb shell su dd if=/dev/graphics/fb0 bs=4 count=1 skip=1000 2>/dev/null | hd 它返回类似于 00000000: 00 00 00 00 s 0 sum 0的内容。 - superweijiafeng
你要找的数据是那四个字节的 00 00 00 00 - Alex P.
1
我得到了 C6 7A 25 62,如何将其转换为RGB值? - CSJ
显示剩余4条评论

0

基于之前被接受的答案,我编写了一个 SH 函数,能够计算缓冲区等内容,以便在我的手机上即开即用。

用法:

GetColorAtPixel X Y

GIST:https://gist.github.com/ThomazPom/d5a6d74acdec5889fabcb0effe67a160

widthheight=$(wm size | sed "s/.* //")
width=$(($(echo $widthheight | sed "s/x.*//g" )+0))
height=$(($(echo $widthheight | sed "s/.*x//g" )+0))
GetColorAtPixel () {
    x=$1;y=$2;
    rm ./screen.dump 2> /dev/null
    screencap screen.dump
    screenshot_size=$(($(wc -c < ./screen.dump)+0));
    buffer_size=$(($screenshot_size/($width*height)))
    let offset=$width*$y+$x+3
    color=$(dd if="screen.dump" bs=$buffer_size count=1 skip=$offset 2>/dev/null | hd | grep -Eo "([0-9A-F]{2} )" |sed "s/[^0-9A-F]*\$//g" | sed ':a;N;$!ba;s/\n//g' |cut -c3-8)
    echo $color;
}

还有一种替代版本(当我将其嵌入sh文件中时,第一个版本对我来说无法正常工作,原因是某些未知的默认hexdump行为问题)

widthheight=$(wm size | sed "s/.* //")
width=$(($(echo $widthheight | sed "s/x.*//g" )+0))
height=$(($(echo $widthheight | sed "s/.*x//g" )+0))
GetColorAtPixel () {
        x=$1;y=$2;
        rm ./screen.dump 2> /dev/null
        screencap screen.dump
        screenshot_size=$(($(wc -c < ./screen.dump)+0));
        buffer_size=$(($screenshot_size/($width*height)))
        let offset=$width*$y+$x+3

        color=$(dd if="screen.dump" bs=$buffer_size count=1 skip=$offset 2>/dev/null | /system/xbin/hd | awk '{ print toupper($0) }' | grep -Eo "([0-9A-F]{2})+" | sed ':a;N;$!ba;s/\n//g' | cut -c9-14 )
        echo $color;
}

你尝试过在第一个示例中使用 hexdump -C 而不是 hd 吗?也许这可以解决嵌入问题。 - Zebiano

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