【问题标题】:Blurring a region in an image on Android (in Java)在 Android 上模糊图像中的区域(在 Java 中)
【发布时间】:2020-02-21 07:14:38
【问题描述】:

在我的 Android 应用中,我以编程方式从后台服务捕获屏幕截图。我以Bitmap 的形式获得它。

接下来,我使用以下 Android 框架 API 获取感兴趣区域 (ROI) 的坐标:

Rect ROI = new Rect();
viewNode.getBoundsInScreen(ROI);

这里,getBoundsInScreen() 是 Javascript 函数 getBoundingClientRect() 的 Android 等效项。

Android 中的Rect 具有以下属性:

rect.top
rect.left
rect.right
rect.bottom
rect.height()
rect.width()
rect.centerX()    /* rounded off to integer */
rect.centerY()
rect.exactCenterX()    /* exact value in float */
rect.exactCenterY()

What does top, left, right and bottom mean in Android Rect object

而 OpenCV 中的 Rect 具有以下属性

rect.width
rect.height
rect.x    /* x coordinate of the top-left corner  */
rect.y    /* y coordinate of the top-left corner  */

现在,在我们执行任何与 OpenCV 相关的操作之前,我们需要将 Android Rect 转换为 OpenCV Rect

Understanding how actually drawRect or drawing coordinates work in Android

有两种方法可以将 Android Rect 转换为 OpenCV Rect(正如 Karl Phillip 在他的回答中所建议的那样)。两者都生成相同的值并产生相同的结果:

/* Compute the top-left corner using the center point of the rectangle. */
int x = androidRect.centerX() - (androidRect.width() / 2);
int y = androidRect.centerY() - (androidRect.height() / 2);

// OR simply use the already available member variables:
x = androidRect.left;
y = androidRect.top;

int w = androidRect.width();
int h = androidRect.height();

org.opencv.core.Rect roi = new org.opencv.core.Rect(x, y, w, h);

现在我正在执行的 OpenCV 操作之一是blurring the ROI within the screenshot

Mat originalMat = new Mat();
Bitmap configuredBitmap32 = originalBitmap.copy(Bitmap.Config.ARGB_8888, true);
Utils.bitmapToMat(configuredBitmap32, originalMat);
Mat ROIMat = originalMat.submat(roi).clone();
Imgproc.GaussianBlur(ROIMat, ROIMat, new org.opencv.core.Size(0, 0), 5, 5);
ROIMat.copyTo(originalMat.submat(roi));

Bitmap blurredBitmap = Bitmap.createBitmap(originalMat.cols(), originalMat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(originalMat, blurredBitmap);

这使我们非常接近预期的结果。快到了,但没有 相当。 目标区域正下方的区域模糊了

例如,如果目标感兴趣区域是密码字段,则上述代码会产生以下结果:

左侧是Microsoft Live ROI,右侧是Pinterest ROI

可以看出,ROI 正下方的区域变得模糊。

所以我的问题是,最后,为什么不是确切的感兴趣区域 模糊?

  • 通过 Android API getBoundsInScreen() 获得的坐标似乎是正确的。
  • 将 Android Rect 转换为 OpenCV Rect 似乎也是正确的。是吗?
  • 用于模糊感兴趣区域的代码似乎也是正确的。有没有其他方法可以做同样的事情?

注意:我提供了实际的全尺寸屏幕截图。它们被缩小了 50% 以适应这篇文章,但除此之外,它们与我在 Android 设备上得到的完全一样。

【问题讨论】:

  • 我建议使用标记来调整图像的大小,这样问题会更悦目。
  • @karlphillip:好主意。但是,我在获取它们时提供了实际的全尺寸屏幕截图。它们被缩小了 50% 以适应这篇文章,但除此之外,它们与我在 Android 设备上得到的完全一样。我不想错过任何可能导致此问题的上下文。
  • 在那里,我编辑了问题以改进格式。您仍然可以右键单击图像并在新选项卡中打开它们以查看全分辨率图像。编辑问题并观察用于调整图像大小的标记代码。它极大地提高了问题的可读性。

标签: android opencv


【解决方案1】:

如果我没记错的话,OpenCV 的 Rect 假定 xy 指定矩形的左上角:

/* Compute the top-left corner using the center point of the rectangle
 * TODO: take care of float to int conversion
 */
int x = androidRect.centerX() - (androidRect.width() / 2);
int y = androidRect.centerY() - (androidRect.height() / 2);

// OR simply use the already available member variables:
x = androidRect.left;
y = androidRect.top;

int w = androidRect.width();
int h = androidRect.height();

org.opencv.core.Rect roi = new org.opencv.core.Rect(x, y, w, h);

【讨论】:

  • 感谢 Karl 付出的时间和努力!我还有一个问题:坐标计算似乎很接近,但不是理想的结果。请查看 UPDATED 问题中的屏幕截图。我正在尝试模糊/扭曲屏幕截图中的密码字段。使用上述坐标,实际 ROI 下方的区域始终是模糊的。您给出的两种计算 x, y 的方法的结果都产生了相同的结果。您能否在这方面提供一些指导?谢谢你,很抱歉给你带来麻烦.... :)
  • 如果您在这些坐标处画一个小圆圈,您将能够调试裁剪计算。我不能比这更进一步。祝你好运!
  • 感谢您迄今为止所做的努力,这非常有帮助。我将按照您建议的方式进行调试。我已经修改了问题并添加了赏金,以防您稍后找到时间......再次感谢! :)
  • @Y.S 可能是android图像从左下角开始,而不是从左上角开始,因为它在打开的简历中。尝试用 (10,10, 10,1000) 绘制一个矩形,看看它是在哪里绘制的。如果我的假设是正确的,那么 coord.y = height - coord.y 可能会起作用
  • @hagor 哇,这真是一个令人费解的想法!在考虑您的观点时,我只想提一下,根据this,我们最初的假设似乎是正确的...... :)
【解决方案2】:

根据 ScreenShots,您得到的 fot rect.x 值与 opencv rect 不同。 因为 android rect center x 值来自屏幕的像素密度,而 opencv rect 值反应图像像素行和列。 如果您发现图像的高度和原始垫子的总行数都不同,但是对于完美的位置矩形,它们应该是相同的,因此您必须将距离乘以某个常数值才能获得准确的矩形距离。

【讨论】:

    猜你喜欢
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多