如何将图像视图的坐标转换为位图的坐标?

20

在我的应用程序中,我需要让用户查看一些照片上的眼睛。

在OnTouchListener.onTouch(...)中,我获得了ImageView的坐标。

如何将这些坐标转换为触摸的位于位图上的点?


http://stackoverflow.com/a/3152172/755804 - 18446744073709551615
7个回答

34

至少在API 10及以上版本上,以下方法适用:

final float[] getPointerCoords(ImageView view, MotionEvent e)
{
    final int index = e.getActionIndex();
    final float[] coords = new float[] { e.getX(index), e.getY(index) };
    Matrix matrix = new Matrix();
    view.getImageMatrix().invert(matrix);
    matrix.postTranslate(view.getScrollX(), view.getScrollY());
    matrix.mapPoints(coords);
    return coords;
}


2
这个解决方案优雅而紧凑。 - John
如何重新映射坐标? - Saar Kuriel
这段代码具体是做什么的?你能加一些解释吗? - ruif3r

31

好的,我没有尝试过这个,但经过一番思考,我有一个建议:

ImageView imageView = (ImageView)findViewById(R.id.imageview);
Drawable drawable = imageView.getDrawable();
Rect imageBounds = drawable.getBounds();

//original height and width of the bitmap
int intrinsicHeight = drawable.getIntrinsicHeight();
int intrinsicWidth = drawable.getIntrinsicWidth();

//height and width of the visible (scaled) image
int scaledHeight = imageBounds.height();
int scaledWidth = imageBounds.width();

//Find the ratio of the original image to the scaled image
//Should normally be equal unless a disproportionate scaling
//(e.g. fitXY) is used.
float heightRatio = intrinsicHeight / scaledHeight;
float widthRatio = intrinsicWidth / scaledWidth;

//do whatever magic to get your touch point
//MotionEvent event;

//get the distance from the left and top of the image bounds
int scaledImageOffsetX = event.getX() - imageBounds.left;
int scaledImageOffsetY = event.getY() - imageBounds.top;

//scale these distances according to the ratio of your scaling
//For example, if the original image is 1.5x the size of the scaled
//image, and your offset is (10, 20), your original image offset
//values should be (15, 30). 
int originalImageOffsetX = scaledImageOffsetX * widthRatio;
int originalImageOffsetY = scaledImageOffsetY * heightRatio;

尝试一下这个想法,看看它是否适用于你。


xImageOffsetXyImageOffset 没有定义,使用它们时您指的是 scaledImageOffsetXscaledImageOffsetY 吗?非常感谢您的帮助,对旧问题打扰了,敬请谅解!;) - Matteo
@Matteo 哈哈,看来是这样。似乎你是第一个注意到这个问题的人,已经修复了。 :) - Kevin Coppock
太好了,很高兴能帮忙! ;D 顺便说一句,你的回答很棒。如果您不介意,我还有一个问题:在我的理解中,这种方法将ImageView上的一个点(x,y)与Bitmap的一个像素对应起来。但是,这种解决方案如何考虑到可能存在比ImageView的点更多的像素的事实?难道对应关系不应该是一对多吗?因为像素比点多。如果我的问题不清楚,请告诉我(如果您有时间的话;D),我可以尝试更好地解释自己!无论如何,非常感谢! ;D - Matteo
我不确定它是否考虑到了那一点,哈哈。在这个解决方案中,它处理了ImageView上的特定触摸事件,因此所触摸的点保证是在该ImageView的边界上。因此,即使图像比ImageView大,也不应该在这种特定情况下出现问题。 - Kevin Coppock
我明白了,非常感谢!无论如何,我已经在我的特定问题上发布了一个问题,并且如果你有时间的话,很高兴你能看一下。再次感谢!;) - Matteo

1

除了考虑填充偏移量(边距是布局的一部分,它是视图外的空间,不必考虑),如果图像被缩放,您可以获取图像矩阵 (ImageView.getImageMatrix()) 来缩放坐标。

编辑: 您可以获取值数组并使用相应的索引常量来获取 x/y 缩放因子和平移量:

float[] values;
matrix.getValues(values);

float xScale = values[Matrix.MSCALE_X];

请注意,翻译不包括填充,您仍然需要单独考虑填充。例如,在FIT_CENTER缩放中使用翻译时,存在一些“空白”空间。

谢谢你的回答。 但是在我的情况下,我该如何使用矩阵呢?matrix.mapPoints()将位图点转换为ImageView的点。 目前,我已将ImageView的比例类型设置为“FitXY”,并使用类似于此的代码:xCoord = (xCoord / imagView.getWidth())*bitmap.getWidth(); - Alex
@alekz编辑了答案。我不擅长矩阵代数,所以实际上我不知道转换值是否以缩放单位为单位... - bigstones

0

当我遇到这个问题并尝试自己解决时,这是我的解决方案。 它似乎适用于拉伸和居中的图像。

class MyEditableImageView(context: Context, attrs: AttributeSet) :
    androidx.appcompat.widget.AppCompatImageView(context, attrs) {

    override fun onTouchEvent(event: MotionEvent): Boolean {
        val image = drawable.toBitmap().copy(Bitmap.Config.ARGB_8888, true)
        val xp = (event.x - imageMatrix.values()[Matrix.MTRANS_X]) / imageMatrix.values()[Matrix.MSCALE_X]
        val yp = (event.y - imageMatrix.values()[Matrix.MTRANS_Y]) / imageMatrix.values()[Matrix.MSCALE_Y]
        if (xp >= 0 && xp < image.width && yp >= 0 && yp < image.height) {
            doSomethingOnImage(image, xp, yp)
            setImageBitmap(image)
        }
        return super.onTouchEvent(event)
    }

    ...

}

0
补充kcoppock的回答,我想要补充一点:
//original height and width of the bitmap
int intrinsicHeight = drawable.getIntrinsicHeight();
int intrinsicWidth = drawable.getIntrinsicWidth();

可能会返回意想不到的答案。这些值取决于你从哪个 dpi 的 drawable 文件夹加载图像。例如,如果你从 /drawable vs /drawable-hdpi vs /drawable-ldpi 中加载图像,则可能会得到不同的值。


0
我认为您可能需要将布局中的任何填充或边距与 ImageView 的坐标偏移量相结合,以获取 BitMap 的正确坐标。

主要问题在于位图可能会被缩放。 - Alex
@alekz 你知道缩放值吗?如果知道,你也可以将其考虑在内。 - dbryson

0

获取楼层宽度和高度

float floorWidth = floorImage.getWidth();
float floorHeight = floorImage.getHeight();

计算比例值

float proportionateWidth = bitmapWidth / floorWidth;
float proportionateHeight = bitmapHeight / floorHeight;

你的 X & Y

float x = 315;
float y = 119;

按比例值进行多重计算

x = x * proportionateWidth;
y = y * proportionateHeight;

地板宽度和高度是什么?您能否再解释一下? - ruif3r
一个楼层的真实尺寸:例如:2000 x 1500平方英尺。 - Mohammad nabil

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