Here is my problem:
I have an Android application that displays an image. The image itself is resized to 480 x 640 regardless of size.
The user can click on multiple points of the image. Based on where the user clicks on the image, the bitmap itself has some warping applied to it.
So let's say the original image is 1000 x 2000 (using whole numbers to make it simpler).
Once the image is loaded into the ImageView, it scales to display properly in the imageview.
This is obviously different for different phones with different resolutions.
Now when the user clicks on different points, I ultimately want to pass those points to my WCF Service along with the bitmap data to perform some image manipulation.
So the problem for me is how to take the points where the user touched on the phone and convert those to points that are relative to the normal unscaled bitmap.
Summary:
Bitmap is scaled to fit. User Clicks at 100,100. 100,100 is the point relative to the scaled image...not the actual bitmap itself. I'm looking for guidance on how to convert that 100,100 to the point on the actual bitmap.
Thanks in advance for any help you can give.
ok, so the Android ImageView has a default ScaleType of FIT_CENTER, so that means:
public static final Matrix.ScaleToFit CENTER
Compute a scale that will maintain the original src aspect ratio, but
will also ensure that src fits entirely inside dst. At least one axis
(X or Y) will fit exactly. The result is centered inside dst.
so if you're whole image view has 480x640 to show the image, and for example your image is 1000x2000, then:
2000/640 = scaleFactor = 3.125/1
so width will scale down to 320 leaving 80 pixels on either side empty, so it can maintain the aspect ratio.
//this one will be 80.
int xBuffer= (imageViewWidth - (realImageWidth*scaleFactor))/2;
//this one will be zero in your example
int yBuffer = (imageViewHeight - (realImageHeight*scaleFactor))/2;
int imageViewX = 0;//x coord where on the image view it was clicked
int imageViewY = 0;//y coord where on the image view it was clicked
if (imageViewX < xBuffer || imageViewX > imageViewWidth-xBuffer)
{
//ignore the click, outside of your image.
}
else if (imageViewY < yBuffer || imageViewY > imageViewHeight-yBuffer)
{
//ignore the click, outside of your image.
}
else
{
realImageY = imageViewY * scaleFactor;
realImageX = (imageViewY - 80) * scaleFactor;
//save click somehow..
saveClick(realImageX,realImageY);
}
Related
I have an Image View which displays an image (e.g 2000x1000 pixels) and I have a coordinate (X,Y) on that image (not the image view). The canvas of my Image View is 600x800 for example. How can I convert the point (X,Y) to screen coordinate so that I can draw a path with them on the OnDraw(...) method of Image View. Any help is appreciated! Thank you.
Update: If I use matrix to draw the path between coordinates, it works but the path and objects i draw become really small. Here is the code i used.
final Matrix matrix = canvas.getMatrix();
matrix.preConcat( _view.getImageMatrix() );
matrix.preScale( 1.0f /_inSampleSize, 1.0f / _inSampleSize);
canvas.setMatrix( matrix );
//I draw the path here
Update: I add a picture to show the effect when using matrix to draw the path. I would like to have the 4 line and the 4 corner balls to be in normal size. The red color is the boundary of the Image View which holds the picture.
I think that might depend on how exactly you are displaying your image. Your ImageView (600x800) is not the same aspect ratio as your bitmap (2000x1000).
You are keeping the bitmap's aspect ratio stable as you scale it down? If so, which part (height or width) takes up the full screen and which has black (or whatever else) as padding? This will help you determine your scale factor.
scale_factor = goal_height/height1; //if height is what you are scaling by
scale_factor = goal_width/width1; //if width is what you are scaling by.
I would try:
x_goal = x1 * scale_factor;
y_goal = y1 * scale_factor;
That is, if you have a point (1333, 900) in your image, and your image takes up the full width, you would multiply both x and y by 600/2000 to get (399.9, 270). (you might want to round that decimal).
If you are NOT keeping the bitmaps aspect ratio stable (that is, you're squeezing it to fit), then you'd have a height_scale_factor and a width_scale factor. So you'd take (1333,900) and multiply x by 600/2000 and y by 800/1000 to get (399.9,720).
This more of a conceptual Android question
Say I have this static image that I want to load into an ImageView -
Say the image is 600px by 200px.(width by height)
Say my image view I try fitting it into is 300 px by 200px(width by height)
I just want to scale by height and cut off the left end of the image so that the image can fit into the imageview. Also if no cuts need to take place(fits already), I don't want to cut any of it off.
So in the end the ImageView(if it was 300 px by 200px) would hold this image
(basically so the F doesn't get distorted)
I've looked Scale To Fit but none of the scale types seems to achieve this custom effect. Does anyone know of how I would go about this? In my case, I wouldn't want to maintain the original aspect ratio.
You should crop the Bitmap so that it always fits into your ImageView. If you want the bottom-right corner cropped, you could do something similar to this:
if (needsCropping()) {
int startWidth = originalImage.getWidth() - 300;
int startHeight = originalImage.getHeight() - 200;
Bitmap croppedBitmap = Bitmap.createBitmap(originalImage, startWidth, startHeight, width, height);
// TODO set imageview
}
FIT_END would do this:
Compute a scale that will maintain the original src aspect ratio, but will also ensure that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. END aligns the result to the right and bottom edges of dst.
You can use ScaleType.CENTER_CROP BUT this will not rescale the image in any way.
Any combinations of those is impossible, for that you must have your own scale method (subclassing ImageView).
Or, the easy way would have .9PNGs as the source of the image, it would fit any space without distorcing.
I have floor plan image and draw it into UI with bitmap in scaled example 500 x 500 pixel. The actual image is 700x700 pixel.
With normal size (700px x 700px) floorplan i could draw circle in direct position example (50px , 75px) and it give the corect result in normal size of floorplan.
This circle is for show current location of user.
The question is how to position that circle if the image is scaled into 500x500 pixel with correct position same as (50px ,75px) in (700px x 700px) floorplan ?
Dosn't this come down to a simple math problem?
The coordinates 50,75 in a 700*700 image would correspond to the coordinates 35(,71..), 53(,57..) in a 500*500 image. Fraction can be omitted, since, well, they're pixels.
The scaling factor would be 500/700 which is roughly 0,714. IE
ScalingFactor = NewDimension / OriginalDimension
ScaledPosition = OriginalPosition * ScalingFactor
This is obviously simplified because it is a square image, and scaling is the same among both sides.
I have a custom View class which displays a map with few flags located at some positions.
It should look like this :
(Images are taken from Google)
I draw those flags with Canvas's drawBitmap method.
Unfortunately it doesn't display the same exact position in different screen sizes.
I have tried using these :
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inScaled = false;
Bitmap img = BitmapFactory.decodeFile(myFile.getAbsolutePath(), opt);
But it will result exactly same images on all screens (will display a small image in large screen), which is not good.
So the image should be scaled too.
How can I achieve this ?
I've never done this my self but you probably need to account for the density of the screen.
int multiplier = getResources().getDisplayMetrics().density;
I.e this will return 0.75 for LDPI. Then you'll have to use the MDPI as a base line and account for the other types of displays with the multiplier.
E.g
int top = y * multiplier;
int left = x * multiplier;
If I'm totally wrong I'll delete this answer, but this was what came to my mind.
I'm trying to make a custom view with clickeable areas for my app. Those areas are relative to the image pixel coords that will fill that view. I've placed those images at drawable-nodpi to avoid system scaling.
My custom view takes one of those images, resizes it keeping the aspect ratio to fit its parent and then resizes the view to the size of the resulting image. So at this point I have a view that maintains the ratio of the source, so the resulting view click (onTouch event.getX and event.getY) coordinates are relative to the original image pixel coords.
From the other hand I have all the coordinates of the shapes that define the clickeable areas in a xml file wich I load when my activity starts. Those areas are defined by a type: circle or rect.
circle: center x-y and radius in px according to the original image
rect: center x-y, width and height in px according to the original image
Now I need to detect if my touch x-y is inside of the coordinates of any of those areas, but keeping in mind the scaling that my original image suffered.
How could I detect the "collitions" between my touch coordinates and the clickeable areas coords? I mean how do I calculate that even without resizing my original image?
I have made a View like this myself,
i added objects containing an image and x/y coords.
Now u need to have a list of those Objects, and in case you get an ontouchEvent, you iterate over that list do something like objectHit()
public boolean objectHit(int x, int y){
int touchdistance = Math.sqrt((double)(this.getX()-x)*(double)(this.getX()-x)) + ((double)(this.getY()-y)*(double)(this.getY()-y));
return touchdistance <= this.getTouchableArea();
}
And you implement getTouchableArea for the Object basicly the same way.
public double getTouchAbleArea() {
return Math.sqrt(Math.pow(getBitmap().getHeight(),2)+Math.pow(getBitmap().getWidth(),2))/2;
}
So what you are doing with this code is, you determine if the touch is within the size of the Image representing the object.
This is what I ended up doing
for(i=0;i<level.getDiffs();i++){
DifferencesData diff = level.getDifference(i);
if(!diff.getFinded()){
x = diff.getX();
y = diff.getY();
if(diff.getType() == 0){
double d = Math.sqrt(Math.pow(x - event.getX(),2) + Math.pow(y - event.getY(),2));
if(d <= diff.getRadius()){
hit = true;
break;
}
}else{
double dx = Math.sqrt(Math.pow(x - event.getX(),2));
double dy = Math.sqrt(Math.pow(y - event.getY(),2));
if(dx <= (diff.getWidth() / 2) && dy <= (diff.getHeight() / 2)){
hit = true;
break;
}
}
}
}
First I scaled the original coordinates by the same scale that my image was scaled by. Then, inside an OnTouchListener I calculated the distance of my touch to the ratio of the circle, or to the half width and half height of my rectangles.
Thank you Daniel for your help!