谁能跟我说说这段代码到底是在干啥?

Forwarding
Forwarding 2017-04-24 字数 1859

看得我晕头转向的,谁能给加些注释吗?

来源:https://github.com/RaiMan/SikuliX-2014/blob/develop/API/src/main/java/org/sikuli/android/ADBDevice.java

public Mat captureDeviceScreenMat(int x, int y, int w, int h) {

byte[] imagePrefix = new byte[12];

byte[] image = new byte[0];

int actW = w;

if (x + w > devW) {

actW = devW - x;

}

int actH = h;

if (y + h > devH) {

actH = devH - y;

}

Debug timer = Debug.startTimer();

try {

InputStream stdout = device.executeShell("screencap");

stdout.read(imagePrefix);

if (imagePrefix[8] != 0x01) {

log(-1, "captureDeviceScreenMat: image type not RGBA");

return null;

}

if (byte2int(imagePrefix, 0, 4) != devW || byte2int(imagePrefix, 4, 4) != devH) {

//TODO check orientation might have changed

log(-1, "captureDeviceScreenMat: width or height differ from device values");

return null;

}

image = new byte[actW * actH * 4];

int lenRow = devW * 4;

byte[] row = new byte[lenRow];

for (int count = 0; count < y; count++) {

stdout.read(row);

}

boolean shortRow = x + actW < devW;

for (int count = 0; count < actH; count++) {

if (shortRow) {

stdout.read(row);

System.arraycopy(row, x * 4, image, count * actW * 4, actW * 4);

} else {

stdout.read(image, count * actW * 4, actW * 4);

}

}

long duration = timer.end();

log(lvl, "captureDeviceScreenMat:[%d,%d %dx%d] %d", x, y, actW, actH, duration);

} catch (IOException | JadbException e) {

log(-1, "captureDeviceScreenMat: [%d,%d %dx%d] %s", x, y, actW, actH, e);

}

Mat matOrg = new Mat(actH, actW, CvType.CV_8UC4);

matOrg.put(0, 0, image);

Mat matImage = new Mat();

Imgproc.cvtColor(matOrg, matImage, Imgproc.COLOR_RGBA2BGR, 3);

return matImage;

}

Java Java技术
6 个回复
zms
小美 2017-04-24

就是包装了adb 命令做一些事情,如截屏

screencap 是android上的一个截屏命令

【 在 Forwarding (Forwarding) 的大作中提到: 】

: 标  题: 谁能跟我说说这段代码到底是在干啥?

: 发信站: 水木社区 (Mon Apr 24 20:59:42 2017), 站内

: 看得我晕头转向的,谁能给加些注释吗?

: 来源:https://github.com/RaiMan/SikuliX-2014/blob/develop/API/src/main/java/org/sikuli/android/ADBDevice.java

:  public Mat captureDeviceScreenMat(int x, int y, int w, int h) {

:     byte[] imagePrefix = new byte[12];

:     byte[] image = new byte[0];

:     int actW = w;

:     if (x + w > devW) {

:       actW = devW - x;

:     }

:     int actH = h;

:     if (y + h > devH) {

:       actH = devH - y;

:     }

:     Debug timer = Debug.startTimer();

:     try {

:       InputStream stdout = device.executeShell("screencap");

:       stdout.read(imagePrefix);

:       if (imagePrefix[8] != 0x01) {

:         log(-1, "captureDeviceScreenMat: image type not RGBA");

:         return null;

:       }

:       if (byte2int(imagePrefix, 0, 4) != devW || byte2int(imagePrefix, 4, 4) != devH) {

:         //TODO check orientation might have changed

:         log(-1, "captureDeviceScreenMat: width or height differ from device values");

:         return null;

:       }

:       image = new byte[actW * actH * 4];

:       int lenRow = devW * 4;

:       byte[] row = new byte[lenRow];

:       for (int count = 0; count < y; count++) {

:         stdout.read(row);

:       }

:       boolean shortRow = x + actW < devW;

:       for (int count = 0; count < actH; count++) {

:         if (shortRow) {

:           stdout.read(row);

:           System.arraycopy(row, x * 4, image, count * actW * 4, actW * 4);

:         } else {

:           stdout.read(image, count * actW * 4, actW * 4);

:         }

:       }

:       long duration = timer.end();

:       log(lvl, "captureDeviceScreenMat:[%d,%d %dx%d] %d", x, y, actW, actH, duration);

:     } catch (IOException | JadbException e) {

:       log(-1, "captureDeviceScreenMat: [%d,%d %dx%d] %s", x, y, actW, actH, e);

:     }

:     Mat matOrg = new Mat(actH, actW, CvType.CV_8UC4);

:     matOrg.put(0, 0, image);

:     Mat matImage = new Mat();

:     Imgproc.cvtColor(matOrg, matImage, Imgproc.COLOR_RGBA2BGR, 3);

:     return matImage;

:   }

: --

Forwarding
Forwarding 2017-04-24

截屏我知道,但他对图像做的一些处理我看不明白,比如

if (x + w > devW) {

:       actW = devW - x;

:     }

:     int actH = h;

:     if (y + h > devH) {

:       actH = devH - y;

:     }

这是做什么的?

【 在 zms (小美) 的大作中提到: 】

: 就是包装了adb 命令做一些事情,如截屏

: screencap 是android上的一个截屏命令

CKevin
2017-04-25

你是真不明白?看你以前发的帖子感觉你不像。。。

【 在 Forwarding (Forwarding) 的大作中提到: 】

: 截屏我知道,但他对图像做的一些处理我看不明白,比如

: if (x + w > devW) {

: 这是做什么的?

: ...................

CKevin
2017-04-25

捕捉屏幕上的部分区域,得到描述该区域的opencv mat矩阵

x/y指定了区域的起始坐标,w/h指定了区域宽高

:  public Mat captureDeviceScreenMat(int x, int y, int w, int h) {

:     byte[] imagePrefix = new byte[12];

:     byte[] image = new byte[0];

合法性校验。当指定的x+w或者y+h超出了屏幕边界时,强制缩小w/h,最多捕捉到屏幕边界

:     int actW = w;

:     if (x + w > devW) {

:       actW = devW - x;

:     }

:     int actH = h;

:     if (y + h > devH) {

:       actH = devH - y;

:     }

此后,实际图像复制将使用actW/actH而不是w/h,act应该是actually

启动性能计时器

:     Debug timer = Debug.startTimer();

:     try {

调用外部命令截屏

:       InputStream stdout = device.executeShell("screencap");

:       stdout.read(imagePrefix);

screencap会返回指定封装的图片文件,该文件有一些特征,比如第八字节应该是0x01。后面还会用到其他特征。

:       if (imagePrefix[8] != 0x01) {

:         log(-1, "captureDeviceScreenMat: image type not RGBA");

:         return null;

:       }

比如前8个字节(第0-第7)指定了图片宽高。使用byte2int,将每四个字节转换为一个java中的int。

:       if (byte2int(imagePrefix, 0, 4) != devW || byte2int(imagePrefix, 4, 4) != devH) {

:         //TODO check orientation might have changed

:         log(-1, "captureDeviceScreenMat: width or height differ from device values");

:         return null;

:       }

建立目标(待输出)图片缓冲区。前面提到,该区域大小由actW/actH决定。由于图片时rgba格式8位深度,该区域实际占用内存为actW*actH像素*rgba四通道*8位也就是1字节深度。

:       image = new byte[actW * actH * 4];

临时变量,记录每行数据的内存占用。

:       int lenRow = devW * 4;

分配行缓冲

:       byte[] row = new byte[lenRow];

因为不是捕捉全屏,而是从x/y位置开始捕捉,所以先跳过前面y行。

:       for (int count = 0; count < y; count++) {

:         stdout.read(row);

:       }

有两种可能,如果捕捉到边界了,那么直接每行数据直接从x位置复制到末尾即可。否则,应该复制到x+actW这个指定位置,之后的数据都不要。

:       boolean shortRow = x + actW < devW;

:       for (int count = 0; count < actH; count++) {

:         if (shortRow) {

:           stdout.read(row);

复制行缓冲,只复制中间部分。

:           System.arraycopy(row, x * 4, image, count * actW * 4, actW * 4);

:         } else {

复制行缓冲,从x坐标复制到该行末尾

:           stdout.read(image, count * actW * 4, actW * 4);

:         }

:       }

到此为止,所有待捕捉区域的数据已经全部复制到image,此时image就是等待后处理的图片了。

结束性能计时器

:       long duration = timer.end();

:       log(lvl, "captureDeviceScreenMat:[%d,%d %dx%d] %d", x, y, actW, actH, duration);

:     } catch (IOException | JadbException e) {

:       log(-1, "captureDeviceScreenMat: [%d,%d %dx%d] %s", x, y, actW, actH, e);

:     }

建立8UC4矩阵,也就是8位深度4通道彩色,将刚刚得到的image赋值给该矩阵

:     Mat matOrg = new Mat(actH, actW, CvType.CV_8UC4);

:     matOrg.put(0, 0, image);

建立最终结果矩阵

:     Mat matImage = new Mat();

调用opencv,将原始rgba图片转换为rgb图片

:     Imgproc.cvtColor(matOrg, matImage, Imgproc.COLOR_RGBA2BGR, 3);

:     return matImage;

:   }

:

: --

:

:

Forwarding
Forwarding 2017-04-25

Wow~~~~,写得很详细,非常感谢!我研究一下

【 在 CKevin (  ) 的大作中提到: 】

: 捕捉屏幕上的部分区域,得到描述该区域的opencv mat矩阵

: x/y指定了区域的起始坐标,w/h指定了区域宽高

: 合法性校验。当指定的x+w或者y+h超出了屏幕边界时,强制缩小w/h,最多捕捉到屏幕边界

: ...................

Forwarding
Forwarding 2017-04-26

我实验发现device.executeShell("screencap")所返回的竟然不是一个图片的输入流。本来想试试看能不能解决这程序的一个小问题的,看来难度远远超出我的能力。刚刚又发现其作者已经在更新代码了,估计已经在解决那个问题。

【 在 CKevin (  ) 的大作中提到: 】

: 捕捉屏幕上的部分区域,得到描述该区域的opencv mat矩阵

: x/y指定了区域的起始坐标,w/h指定了区域宽高

: 合法性校验。当指定的x+w或者y+h超出了屏幕边界时,强制缩小w/h,最多捕捉到屏幕边界

: ...................