Correspondence between ImageView coordinates and Bitmap Pixels - Android

后端 未结 3 1783
心在旅途
心在旅途 2020-12-29 10:20

In my application I want the user to be able to select some content of an Image contained inside an ImageView.

To select the content I subclassed the

相关标签:
3条回答
  • 2020-12-29 10:47

    This is solvable with very simple maths, your rectangle has 4 points p1, p2, p3, p4, with coordinates x, y, relative to the ImageView.

    You also know the dimensions of the original image.

    Now if p1.x, for example, is 50, in an ImageView which is 200 px wide, you get relation of 50 / 200 = 0.25

    If your original image is 100 px wide, your point p1.x would be located at 100 * 0.25 = 25 px

    Can be expressed:

    50 -> 200

    ? -> 100

    And calculated:

    ? = 100 * 50 / 200

    You do this for each point, for each dimension x, y, and then you get the 4 points of the rectangle in the original image.

    Now if you iterate using these calculated points you should get the pixels of the rectangle in the original image.

    0 讨论(0)
  • 2020-12-29 11:01

    Matteo,

    It seems this is more a question of how much error you can (subjectively) tolerate in which pixels you send to the server. The fact remains that for any aspect ratio that does not come out to a nice neat integer, you have to decide which direction to 'push' your selection box.

    The solutions you linked to are perfectly good solutions. You have to ask yourself: Will the user notice if the image I process is one pixel off from the selection box shown on the screen? My guess is probably not. I can't imagine the user will have that sort of pixel precision anyways when selecting a rectangle with their big fat finger on a touchscreen :D

    Since this is the case, I would just let the floor()-ing that occurs when casting to an integer take care of which pixels you end up passing to the server.

    Let's look at an example.

    Let's define the width and height of our ImageView and Bitmap to be:

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

    Then the aspect ratios you will use to convert your selection box between them will be:

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

    Some nice ugly numbers. Whatever pixel I am on in the ImageView will correspond to a pixel in the Bitmap like so:

    BitmapPixelX = ImageViewPixelX * WidthRatio
    BitmapPixelY = ImageViewPixelY * HeightRatio
    

    Now, I put this Bitmap on the screen in my ImageView for the user to select a rectangle, and the user selects a rectangle with top-left and bottom-right coordinates in the ImageView as such:

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

    How do I determine which pixels in the Bitmap these correspond to? Easy. The ratios we determined earlier. Let's look at just the top-left coordinates for now.

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

    For RectTopLeftX, we find ourselves at a BitmapPixelX value of 119, and then about a quarter of a way into the pixel. Well, if we floor() this value and the corresponding BitmapPixelY value of 8.36, we will be sending pixel (119, 8) to the server for processing. If we were to ceil() these values, we will be sending pixel (120, 9) to the server for processing. This is the part that is entirely up to you.

    You will (nearly) always land in some fractional part of a pixel. Whether you send the pixel you land in, or the one next to it is your call. I would say that this is going to be entirely unnoticeable by your user, and so to reiterate, just let the floor()-ing that occurs when casting to an integer take care of it.

    Hope that helps!

    [EDIT]

    Upon reading the question again more slowly, I think I better understand what you are asking/confused about. I will use my example above to illustrate.

    You are saying that there are 176 pixels in the Bitmap, and 400 pixels in the ImageView. Therefore, the mapping from one to the other is not 1:1, and this will cause problems when figuring out what pixels to pull out for processing.

    But it doesn't! When you convert the coordinates of the rectangle bounds in the ImageView to coordinates in the Bitmap, you're simply giving the range of pixels to iterate over in the Bitmap. It's not a description of how each individual pixel in the ImageView maps to a corresponding pixel in the Bitmap.

    I hope that clears up my confusion about your confusion.

    0 讨论(0)
  • 2020-12-29 11:02

    Here I'm assuming that you've placed something inside your image view. Do this inside onCreate:

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

    And this inside onTouch:

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

    Now you have the particular pixel you want.

    0 讨论(0)
提交回复
热议问题