我在 Android 上使用两种不同的方法进行截图:
/system/bin/screencap -p $path
。MediaProjection
API。即使是完全相同的屏幕,在执行 OCR 时(使用
Tesseract
)我得到不同的结果。
使用
/system/bin/screencap
我得到了预期的结果。
使用 MediaProjection
API 无法正确识别任何或所有文本,因此我需要使用二值化算法对图像进行预处理。
这是为什么呢?我检查了 screencap 源代码,似乎使用 PNG 压缩,配置 ARGB_8888 和质量 100%。 正如您在这里看到的:https://android.googlesource.com/platform/frameworks/base/+/master/cmds/screencap/screencap.cpp
这就是我使用
MediaProjection
API 创建位图的方式:
public class ImageTransmogrifier implements ImageReader.OnImageAvailableListener {
private final int width;
private final int height;
private final ImageReader imageReader;
private final ScreenshotService svc;
private Bitmap latestBitmap=null;
ImageTransmogrifier(ScreenshotService svc) {
this.svc=svc;
Display display=svc.getWindowManager().getDefaultDisplay();
Point size=new Point();
display.getRealSize(size);
int width=size.x;
int height=size.y;
while (width*height > (2<<19)) {
width=width>>1;
height=height>>1;
}
this.width=width;
this.height=height;
imageReader=ImageReader.newInstance(width, height,
PixelFormat.RGBA_8888, 2);
imageReader.setOnImageAvailableListener(this, svc.getHandler());
}
@Override
public void onImageAvailable(ImageReader reader) {
final Image image=imageReader.acquireLatestImage();
if (image!=null) {
Image.Plane[] planes=image.getPlanes();
ByteBuffer buffer=planes[0].getBuffer();
int pixelStride=planes[0].getPixelStride();
int rowStride=planes[0].getRowStride();
int rowPadding=rowStride - pixelStride * width;
int bitmapWidth=width + rowPadding / pixelStride;
if (latestBitmap == null ||
latestBitmap.getWidth() != bitmapWidth ||
latestBitmap.getHeight() != height) {
if (latestBitmap != null) {
latestBitmap.recycle();
}
latestBitmap=Bitmap.createBitmap(bitmapWidth,
height, Bitmap.Config.ARGB_8888);
}
latestBitmap.copyPixelsFromBuffer(buffer);
image.close();
ByteArrayOutputStream baos=new ByteArrayOutputStream();
Bitmap cropped=Bitmap.createBitmap(latestBitmap, 0, 0,
width, height);
cropped.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] newPng=baos.toByteArray();
svc.processImage(newPng);
}
}
Surface getSurface() {
return(imageReader.getSurface());
}
int getWidth() {
return(width);
}
int getHeight() {
return(height);
}
void close() {
imageReader.close();
}
}
有人告诉我,基本上我使用更多的处理器来进行记录,而留给 OCR 的时间更少。 OCR 的周期较少,因此在给定时间内准确性会降低。 这也是我不需要用 screencap 预处理图像的原因。因为一次性的高档产品很可能不如持续不断的流经。
这有什么依据吗?如果是这样,我应该使用其他东西来代替 MediaProjection 还是简单地预处理图像?
这有什么基础吗?
不清楚“这个”是什么。
也许“这个”是:
有人告诉我,基本上我使用更多的处理器来进行记录,而留给 OCR 的时间更少
您需要联系 OCR 引擎的供应商,询问他们是否以某种方式根据可用的 CPU 时间来扩展 OCR 质量。否则,我预计 OCR 需要花费多少时间才能完成您所要求的操作,而
onImageAvailable()
的速度只是决定了端到端过程需要多长时间。
也许“这个”是指:
这是为什么?
...大概“那个”指的是:
使用
我得到了预期的结果。使用 MediaProjection API 无法正确识别任何或所有文本,因此我需要使用二值化算法对图像进行预处理。/system/bin/screencap
我首先将媒体投影 PNG 写入文件,然后将其与
screencap
PNG 的结果进行比较。也许您可以识别两者之间的质量差异或某些东西。不要求两者产生相同的图像,但我不认为差异足以影响 OCR。一个例外是,如果正在进行某种动画,则 screencap
能够比媒体投影 API 更好地与动画同步。另一个有趣的项目是您链接到的 ANDROID_BITMAP_FLAGS_ALPHA_PREMUL
源中的 screencap
,以及 alpha 值是否存在可以解释 OCR 行为的情况。