ImageView 坐标与 Bitmap Pixels 的对应关系 - Android

Posted

技术标签:

【中文标题】ImageView 坐标与 Bitmap Pixels 的对应关系 - Android【英文标题】:Correspondence between ImageView coordinates and Bitmap Pixels - Android 【发布时间】:2012-07-05 07:20:26 【问题描述】:

在我的应用程序中,我希望用户能够选择 ImageView 中包含的图像的某些内容。

为了选择内容,我对ImageView 类进行了子类化,使其实现OnTouchListener,以便在其上绘制一个边框由用户决定的矩形。

以下是绘图结果的示例(要了解它的工作原理,您可以将其想象为在桌面上单击鼠标并拖动鼠标):

现在我需要确定Bitmap 图像的哪些像素 对应于所选部分。很容易确定ImageView 的哪些点属于矩形,但我不知道如何获取对应的像素,因为ImageView 的纵横比与原始图像不同。

我遵循especially here、but also here 描述的方法,但我并不完全满意,因为在我看来,ImageView 上的像素和点之间的对应关系是 1 对 1,并且没有给我所有对应的像素在原始图像上到所选区域。

调用hoveredRectImageView上的矩形,其中的点是:

class Point 
    float x, y;
    @Override
    public String toString() 
        return x + ", " + y;
    


Vector<Point> pointsInRect = new Vector<Point>();

for( int x = hoveredRect.left; x <= hoveredRect.right; x++ )
    for( int y = hoveredRect.top; y <= hoveredRect.bottom; y++ )

        Point pointInRect = new Point();
        pointInRect.x = x;
        pointInRect.y = y;
        pointsInRect.add(pointInRect);
       

如何获得包含Bitmap 图像对应像素的Vector&lt;Pixels&gt; pixelsInImage


补充说明

我将更好地解释我的问题的背景:

我需要对选定的部分进行一些图像处理,并且想要 确保矩形中的所有像素都得到处理。

图像处理将在服务器上完成,但它需要确切知道哪个 要处理的像素。服务器使用具有真实尺寸的图像, android 应用程序只是通过传递一个向量来告诉服务器要处理哪些像素 包含像素坐标

以及为什么我不喜欢上面链接中提出的解决方案:

以 1 对 1 的方式给出变换坐标的答案。这种方法显然是 对我的任务无效,因为某个区域的 ImageView 中有 50 个点 屏幕上的大小不能对应真实像素数相同的区域 图像,但应考虑不同的纵横比。

例如,如果图像小于应用程序上显示的ImageView,则应选择该区域:

【问题讨论】:

我不确定您在第一个链接中不使用该方法的原因。即使假设像素多于点,它也会为您提供最近的像素。我想您可以将它们更改为浮点数以获取子像素值,但我看不出它如何变得更接近。也许我不明白这个问题? 我需要对选定的部分进行一些图像处理,并希望确保矩形中的所有像素都得到处理。图像处理将在服务器上进行,但它需要确切知道要处理哪些像素。服务器处理具有真实尺寸的图像,android 应用程序只告诉处理哪些像素。 好吧,为了确保你抓取全包像素,我会使用缩放方法和 floor() 左侧/顶部值,ceil() 右侧/底部,所以最多你将在每一侧处理一个额外的像素。它为您提供最近的像素,您如何舍入它将决定当您最终得到浮点值时它会走哪条路。 @Geobits - 我是一个新手,你介意更具体一点来帮助我理解吗?如果你能发布一个答案,它真的会对我有很大帮助!无论如何.. . 我想说,如果你想让所有像素都包含在内,你只计算点,然后像 Geobits 所说的那样使用 floor 或 ceil 进行舍入。而且您只将 4 个点发送到服务器。然后服务器可以循环并生成像素数组,这是您不应该在客户端上执行的操作,除非您必须在客户端中使用它。 【参考方案1】:

马特奥,

这似乎更像是一个问题,即您可以(主观地)容忍您发送到服务器的像素有多少。事实仍然是,对于任何不能得出一个很好的整数的纵横比,您必须决定“推动”选择框的哪个方向。

您链接到的解决方案是非常好的解决方案。您必须问自己:如果我处理的图像与屏幕上显示的选择框相差一个像素,用户会注意到吗?我的猜测可能不是。我无法想象用户在触摸屏上用他们的大手指选择一个矩形时会有那种像素精度:D

既然是这种情况,我只会让在转换为整数时发生的floor()-ing 处理您最终将哪些像素传递给服务器。

让我们看一个例子。

让我们将 ImageView 和 Bitmap 的宽度和高度定义为:

ImageViewWidth = 400, ImageViewHeight = 150
BitmapWidth = 176, BitmapHeight = 65

那么您将用于在它们之间转换选择框的纵横比将是:

WidthRatio = BitmapWidth / ImageViewWidth = 175 / 400 = 0.44
HeightRatio = BitmapHeight / ImageViewHeight = 65 / 150 = 0.44

一些漂亮丑陋的数字。我在 ImageView 中的任何像素都将对应于 Bitmap 中的像素,如下所示:

BitmapPixelX = ImageViewPixelX * WidthRatio
BitmapPixelY = ImageViewPixelY * HeightRatio

现在,我将这个 Bitmap 放在我的 ImageView 中的屏幕上,供用户选择一个矩形,用户在 ImageView 中选择一个具有左上角和右下角坐标的矩形,如下所示:

RectTopLeftX = 271, RectTopLeftY = 19
RectBottomRightX = 313, RectBottomRightY = 42

如何确定这些对应于位图中的哪些像素?简单。我们之前确定的比率。我们现在只看左上角的坐标。

RectTopLeftX * WidthRatio = 271 * .44 = 119.24
RectTopLeftY * HeightRatio = 19 * .44 = 8.36

对于 RectTopLeftX,我们发现自己的 BitmapPixelX 值为 119,然后进入像素的四分之一左右。好吧,如果我们 floor() 这个值和对应的 BitmapPixelY 值 8.36,我们会将像素 (119, 8) 发送到服务器进行处理。如果我们要ceil() 这些值,我们会将像素 (120, 9) 发送到服务器进行处理。 这完全取决于您。

您将(几乎)总是落在像素的某个小数部分。无论您发送您登陆的像素,还是它旁边的像素都是您的电话。我想说这将完全不会被您的用户注意到,因此重申一下,只需让在转换为整数时发生的 floor()-ing 处理它。

希望有帮助!

[编辑]

在更慢地再次阅读问题后,我想我更好地理解了您的问题/困惑。我会用我上面的例子来说明。

您是说 Bitmap 中有 176 个像素,ImageView 中有 400 个像素。因此,从一个到另一个的映射不是 1:1,这会导致在确定要提取哪些像素进行处理时出现问题。

但事实并非如此!当您将 ImageView 中矩形边界的坐标转换为位图中的坐标时,您只是在位图中提供 像素范围 以迭代 这里没有描述 ImageView 中的每个像素如何映射到 Bitmap 中的相应像素。

我希望这能消除我对您的困惑的困惑。

【讨论】:

我真的很喜欢你的回答!它非常有用,尤其是关于我们的困惑的最后评论...... ;) 非常感谢你花一些时间来理解我的观点!你应该得到赏金 ;D 【参考方案2】:

这可以通过非常简单的数学来解决,您的矩形有 4 个点 p1、p2、p3、p4,坐标为 x、y,相对于 ImageView。

您还知道原始图像的尺寸。

例如,如果 p1.x 为 50,则在 200 px 宽的 ImageView 中,您会得到 50 / 200 = 0.25 的关系

如果您的原始图像是 100 像素宽,您的点 p1.x 将位于 100 * 0.25 = 25 像素

可以表达:

50 -> 200

? -> 100

并计算:

? = 100 * 50 / 200

您对每个点、每个维度 x、y 执行此操作,然后您会得到原始图像中矩形的 4 个点。

现在,如果您使用这些计算点进行迭代,您应该得到原始图像中矩形的像素。

【讨论】:

感谢回答,但这或多或少已经在我链接的问题中说明了。恐怕这些解决方案有两个问题:1)当像素除法不给出整数结果时(例如像素 100 * 0.33 = 像素??如果纵横比为 1/3)2)较小的 50 像素的矩形选择其中一部分以包含较大图像中相同部分的图像必须在大图像中具有超过 50 个像素,因此对应 1 对 1 是不正确的。如果我需要更好地解释,请告诉我 第一个问题:使用float和double计算一切,并将原图中的坐标四舍五入到最接近的整数(这会有点不准确,但看起来你的应用可以容忍这个?) .第二个问题:这不是像素之间的 1:1,如果是这种情况,您将在原始图像和 ImageView 中获得相同大小的矩形,这没有意义。 检查我的问题中的更新!我会考虑你所说的......thks ;D【参考方案3】:

这里我假设您在图像视图中放置了一些东西。在 onCreate 中执行此操作:

ImageView image=(ImageView) findViewById(R.id.imageView1);
TextView coordinates=(TextView) findViewById(R.id.textView1);
bitmap = ((BitmapDrawable)Map.getDrawable()).getBitmap();

还有这个在onTouch里面:

coordinates.setText("Touch coordinates:"+String.valueOf(event.getX())+"x"+String.valueOf(event.getY()));
int pixel = bitmap.getPixel((int)event.getX(), (int)event.getY());

现在你有了你想要的特定像素。

【讨论】:

以上是关于ImageView 坐标与 Bitmap Pixels 的对应关系 - Android的主要内容,如果未能解决你的问题,请参考以下文章

回收 ImageView 的 Bitmap

Android 怎么把imageview 转为Bitmap

Android 怎么把imageview 转为Bitmap

Android开发中ImageView里的Bitmap很模糊,怎么解决?

自定义圆形ImageView(解决Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();报错问题)

Android 从imageview中获得bitmap的方法