Scaling image inside custom view with rotation angle in Android - android

Well, this might be a bit hard to explain but here is the deal: I have a custom view which has a background image and some other smaller images drawn above it. The whole view, when the user selects the option to save it, will be scaled to a certain resolution, let's say 900x900px. So if the phone is 720p the image will be scaled up, while if the screen is 1080p will be scaled down.
How is scaling done:
I take the view's layout params and change the width to 900px.
The background stored image is exactly at 900px, so when the view is prepared to be saved, I simply reload the background image at full
quality.
All the other small images, get scaled as well, both their size and their position on screen.
So, if initially if the screen size is 720px width, when the size is changed to 900px, I calculate a scale factor, within onMeasure
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
if (MeasureSpec.getSize(widthMeasureSpec) == 900) {
scale = (900 - viewWidth) * 100.2f / viewWidth;
prepareSaving();
}
}
Then I use this scale number when drawing:
canvas.drawBitmap(myCachedImage, x + addScale(x), y + addScale(y), imagePaint);
where
private float addScale(float value) {
if (scale == 0) {
return 0;
} else {
return (value * scale / 100.2f);
}
}
This allows me to draw the bitmap at scaled coordinates, and this works as expected.
The problem appears when the user rotates the image. On rotate I do:
public void rotateSticker(float degrees) {
imageMatrix.setRotate(degrees, imageCenterX + addScale(imageCenterX), imageCenterY +imageCenterY ));
}
Within onDraw I do:
if (angle!=0{
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.setMatrix(imageMatrix);
canvas.drawBitmap(myCachedImage, x + addScale(x), y + addScale(y), imagePaint);
canvas.retore()
}else
{
canvas.drawBitmap(myCachedImage, x + addScale(x), y + addScale(y), imagePaint);
}
Here is my problem: if the user does not rotate, all scaling is done correctly and the saved image looks good. If there is an angle, on scaling, the image is not drawn in the right coordinates, it is moved, just like in the image bellow
http://i.imgur.com/bFBHVF1.png

All the problems with scaling and rotating was caused by the image's Matrix. When I switched to using only the view's canvas.rotate(), everything is working as expected.

Related

Add animation to drawLine and drawBitmap

I have a custom view that extends relative layout. In the dispatchDraw method I draw lines and images inside a for loop because i have different start and end points for multiple lines.
I would like to know the easiest way to draw lines with animations from point a to point b in a slow way for example, this animation must be set only for a line that I decide and not for all the others.
I would also like to draw images with animations, I don't want to move the image but I would like to draw the image a little bigger first and then reduce it to the right size, or draw the image from top to bottom. Again this animation must be set only for a image that I decide and not for all the others.
#Override
protected void dispatchDraw(Canvas canvas) {
int width = getWidth();
int height = getHeight();
super.dispatchDraw(canvas);
size = width / (lines);
insideMargin = size / margin;
vMargin = (height - lines * size) / 2f;
canvas.translate(0,vMargin);
for(int x=0; x<lines;x++){
for(int y=0;y<lines;y++){
if(/*a condintion is true*/) {
//draw line with animation, how to do it?
}else{
canvas.drawLine(x * size,
y * size,
(x + 1) * size,
y* size,
paint
);
}
if(/*a condition is true*/) {
//draw bitmap with animation, how to do it?
}else
canvas.drawBitmap(image, src, dest, null);
}
}
}
//i have on touch event that will call invalidate
I think you should use ValueAnimator for your purpose. As I understood, you want to animate values once a touch event occurs. The value returned by the animator must be used for all objects so the animated value should be general as possible. I recommend to use 0 to 1 as float value. You can use this value for the animation. For the bitmap animation, you can define target rectangle start and end size then you can find appropriate size by facilitating the animated fraction value. For the line case, you can use the slope for the animation. I think you already have the line's start and end point so you can use slope and fraction to calculate animated end point.

android move image from one place to another place on different screen size and resolutions

I am new in android. I want to make ludo game. and I sets all things related to this game. but I want to move TOKEN from one place to another for different screens like (Nexus 6, Samsung Note 5, Moto G3, etc...). But issue is that for every screen size (Width x Height) are different. that's why I am not set proper x and y position on screen. I referenced screen Height and Width for taking next position (x and y) on screen to move TOKEN on screen. I am taking static image for Ludo Dashboard. That's why i am not getting how to move.
for example:
My Screen is as below,
from origin position to Home position :
In this situation, for every screens translation was changed. because i am taking reference screen Height and Width for move.
for that code is below,
DisplayMetrics displaymetrics = getResources().getDisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
this.constant.Height = displaymetrics.heightPixels;
this.constant.Width = displaymetrics.widthPixels;
private float getheight(float val) {
return (this.constant.Height * val) / 800;
}
private float getwidth(float val) {
return (this.constant.Width * val) / 480;
}
ObjectAnimator animTranslateY = ObjectAnimator.ofFloat(img,
"translationY", blue_1.getY() + getheight(67));
animTranslateY.setDuration(GameConstants.DURATION);
ObjectAnimator animTranslateX = ObjectAnimator.ofFloat(img,
"translationX", blue_1.getX() + getwidth(128));
animTranslateX.setDuration(GameConstants.DURATION);
AnimatorSet anim = new AnimatorSet();
anim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationEnd(Animator animator) {
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
anim.play(animTranslateX);
anim.play(animTranslateY);
anim.start();
from Home to Common Rout :
In this situation, its work fine. bt for different screen its moving differ.
So, my question is that How can i move and what should be reference for move image form one position to another position. I takes too many time for this. Please help me.
So, I tried to come up with a solution that uses simple unitary method to solve your problem. I am not sure if it works, I did not try it by coding it actually!
I am assuming that you have set the background static image to scale its size (width) to 100% of the screen, your static image is a square(usually a ludo board is). Also I am considering here that screenwidth is smaller than screenheight. If it is the other way around then exchange the formulae symbols.
let
screenH = screen height in pixels;
screenW = screen width in pixels;
bgW = width of staticbackgroundimage in pixels;
bgH = height of staticbackgroundimage in pixels;
so now, if you want to move 'p' pixels in the background static ludo image horizontally then let us say you will have to move x pixels on the screen. x can be calculated as follows:
x= p*screenW/bgW;
Also, if you want to move 'q' pixels in the background static ludo image vertically then let us say you will have to move y pixels on the screen. y can be calculated as follows:
image height on the screen will be(in pixels):
screenHimage=bgH*screenW/bgW;
y=q*screenHimage/bgH;
So now move x and y pixels on the screen if you want to move p and q pixels in the original image.
I hope this works.

Coordinate X& Y on Screen different size

I have a view and inside a viewpager with images. When I touch the view I display an image where I'm touching.
In the same time I send X and Y position in Firebase.
In another device, I get back those coordinates and display an image at those coordinates.
But the screen size of the tablets are differents, how can I show my image at the same position ? Because if I touch the middle screen of the first tablet, it showing an image en the right bottom of the other one
UPDATE
For user 1, when he touch the view a pointer/cursor is showing
v.animate()
.x(Math.round(event.getX()))
.y(Math.round(event.getY()))
.setDuration(0)
.start();
In the same time he sends coordinates to Firebase and the width and height of his screen.
Display display = getActivity().getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
Map<String, Object> map = new HashMap<>();
map.put("x", Math.round(event.getX()));
map.put("y", Math.round(event.getY()));
map.put("sizeX", width);
map.put("sizeY", height);
mRefMyPos.updateChildren(map);
The user 2 has a listener and get back those data to display an imageView at the coordinates.
listenerRefCoordonate = mRefCoordonate.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
CoordonateModel coordinateModel = dataSnapshot.getValue(CoordonateModel.class);
if (coordinateModel == null){
//do something
mImageView.setVisibility(View.GONE);
} else {
final Float mScale = Math.min(1.0f * width / coordinateModel.getSizeX(), 1.0f * height / coordinateModel.getSizeY());
if (coordinateModel.getX() != null){
mImageView.setVisibility(View.VISIBLE);
mImageView.animate()
.x(Math.round(coordinateModel.getX() * mScale))
.y(Math.round(coordinateModel.getY() * mScale))
.setDuration(0)
.start();
}
}
}
#Override
public void onCancelled(DatabaseError firebaseError) {
}
});
Seems to be incorrect for example if I have an imageview with ABCDEFGHI.... (match_parent), if I try to show C, it showing E on the other device. Maybe my scale is incorrect ??
I tried to test if the scale is correct. When I touch the screen without displaying imageview where I'm touching but I'm listening what I'm writting on FireBase and displaying imageview with coordinates/with and height of screen device and do the scale and the when I'm displaying the imageview it showing where I'm touching so I guess the scale is correct
I will try to re explain my problem:
Tablet n1, 1024/768
Tablet n2, 1920/1200
Both are on a view full_screen with the same Imageview scale FitXY and match_parent
On the first tablet I'm touching the tail of the pig (Imageview), I'm sending X,Y position of the screen touch (Math.round(event.getX(), Math.round(event.getY()) and the width/height screen size of the tablet. The second tablet displaying (a cursor) around the tail of the pig but not at the exact position....
Can someone help me ?
User tablet 1 touching his screen (RED POINT where he's touching)
User tablet 2 listening X,Y position and draw where the user 1 is touching (RED POINT)
UPDATE 2
I changed and I calculate like this one on this post stackoverflow.com/a/21588683/5845928 I have what you said : tablet 1 the point is (258,230) and tablet 2 (484, 359). the problem seems to be the imageview. How can I solve it ?
** FIXED **
TABLET 2 receive x,y position and width and height of tablet 1.
hisWidth = coordinateModel.getSizeX();
hisHeight = coordinateModel.getSizeY();
float percent_width = Float.valueOf(coordinateModel.getX()) / hisWidth;
float percent_height = Float.valueOf(coordinateModel.getY()) / hisHeight;
float x = percent_width * mWidth;
float y = percent_height * mHeight;
Try to send also device width and height, so you could use them to calculate the exact (X,Y) in other devices

Taking too much time when resizing bitmap using Bi-linear algorithm in android

I am developing an app which is have loading large bitmap into ImageView. here i am using Bi linear algorithm for re-sizing image and it is working fine but it is taking too much time to resize(Bi-linear algorithm). i am adding some code below.
here is the code :
mutableBitmap = biLinear(mutableBitmap, outWidth,outHeight);// Bi-Linear code
mutableBitmap = Bitmap.createBitmap(mutableBitmap, 0, 0, mutableBitmap.getWidth(),
mutableBitmap.getHeight(), m, true);
Bi-Linear algorithm method :
public static Bitmap biLinear(final Bitmap input,int outWidth,int outHeight)
{
final int oldHeight=input.getHeight(),oldWidth=input.getWidth();
final int newHeight=outHeight,newWidth=outWidth;
Bitmap output =Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
// position of the top left pixel of the 4 pixels to use interpolation on
int xTopLeft,yTopLeft;
int x,y,lastTopLefty;
final float xRatio=(float)newWidth/(float)oldWidth,yratio=(float)newHeight/(float)oldHeight;
// Y color ratio to use on left and right pixels for interpolation
float ycRatio2=0,ycRatio1=0;
// pixel target in the src
float xt,yt;
// X color ratio to use on left and right pixels for interpolation
float xcRatio2=0,xcratio1=0;
int rgbTopLeft=0,rgbTopRight=0,rgbBottomLeft=0,rgbBottomRight=0,rgbTopMiddle=0,rgbBottomMiddle=0;
// do the resizing:
for(x=0;x<newWidth;x++)
{
xTopLeft=(int)(xt=x/xRatio);
// when meeting the most right edge, move left a little
if(xTopLeft>=oldWidth-1)
xTopLeft--;
if(xt<=xTopLeft+1)
{
// we are between the left and right pixel
xcratio1=xt-xTopLeft;
// color ratio in favor of the right pixel color
xcRatio2=1-xcratio1;
}
for(y=0,lastTopLefty=Integer.MIN_VALUE;y<newHeight;y++)
{
yTopLeft=(int)(yt=y/yratio);
// when meeting the most bottom edge, move up a little
if(yTopLeft>=oldHeight-1)
yTopLeft--;
// we went down only one rectangle
if(lastTopLefty==yTopLeft-1)
{
rgbTopLeft=rgbBottomLeft;
rgbTopRight=rgbBottomRight;
rgbTopMiddle=rgbBottomMiddle;
rgbBottomLeft=input.getPixel(xTopLeft,yTopLeft+1);
rgbBottomRight=input.getPixel(xTopLeft+1,yTopLeft+1);
rgbBottomMiddle=Color.argb((int)(Color.alpha(rgbBottomLeft)*xcRatio2+Color.alpha(rgbBottomRight)*xcratio1),//
(int)(Color.red(rgbBottomLeft)*xcRatio2+Color.red(rgbBottomRight)*xcratio1),//
(int)(Color.green(rgbBottomLeft)*xcRatio2+Color.green(rgbBottomRight)*xcratio1),//
(int)(Color.blue(rgbBottomLeft)*xcRatio2+Color.blue(rgbBottomRight)*xcratio1));
}
else if(lastTopLefty!=yTopLeft)
{
// we went to a totally different rectangle (happens in every loop start,and might happen more when making the picture smaller)
rgbTopLeft=input.getPixel(xTopLeft,yTopLeft);
rgbTopRight=input.getPixel(xTopLeft+1,yTopLeft);
rgbTopMiddle=Color.argb((int)(Color.alpha(rgbTopLeft)*xcRatio2+Color.alpha(rgbTopRight)*xcratio1),//
(int)(Color.red(rgbTopLeft)*xcRatio2+Color.red(rgbTopRight)*xcratio1),//
(int)(Color.green(rgbTopLeft)*xcRatio2+Color.green(rgbTopRight)*xcratio1),//
(int)(Color.blue(rgbTopLeft)*xcRatio2+Color.blue(rgbTopRight)*xcratio1));
rgbBottomLeft=input.getPixel(xTopLeft,yTopLeft+1);
rgbBottomRight=input.getPixel(xTopLeft+1,yTopLeft+1);
rgbBottomMiddle=Color.argb((int)(Color.alpha(rgbBottomLeft)*xcRatio2+Color.alpha(rgbBottomRight)*xcratio1),//
(int)(Color.red(rgbBottomLeft)*xcRatio2+Color.red(rgbBottomRight)*xcratio1),//
(int)(Color.green(rgbBottomLeft)*xcRatio2+Color.green(rgbBottomRight)*xcratio1),//
(int)(Color.blue(rgbBottomLeft)*xcRatio2+Color.blue(rgbBottomRight)*xcratio1));
}
lastTopLefty=yTopLeft;
if(yt<=yTopLeft+1)
{
// color ratio in favor of the bottom pixel color
ycRatio1=yt-yTopLeft;
ycRatio2=1-ycRatio1;
}
// prepared all pixels to look at, so finally set the new pixel data
output.setPixel(x,y,Color.argb(//
(int)(Color.alpha(rgbTopMiddle)*ycRatio2+Color.alpha(rgbBottomMiddle)*ycRatio1),//
(int)(Color.red(rgbTopMiddle)*ycRatio2+Color.red(rgbBottomMiddle)*ycRatio1),//
(int)(Color.green(rgbTopMiddle)*ycRatio2+Color.green(rgbBottomMiddle)*ycRatio1),//
(int)(Color.blue(rgbTopMiddle)*ycRatio2+Color.blue(rgbBottomRight)*ycRatio1)));
}
}
return output;
}
this algorithm taking nearly 15-20 secs to load the image
is there any possibility to reduce the loading time
if anyone have idea please help me
Thanks in Advance.
Calling getPixel/setPixel methods per pixel may require to much time.
I suggest you to use copyPixelsToBuffer/copyPixelsFromBuffer methods instead.
e.g:
public static Bitmap biLinear(final Bitmap input,int outWidth,int outHeight) {
if(input.getConfig() != Bitmap.Config.ARGB_8888) {
// this example assumes that input bitmap configuration is Bitmap.Config.ARGB_8888
throw new RuntimeException();
}
final int oldHeight=input.getHeight(),oldWidth=input.getWidth();
final int newHeight=outHeight,newWidth=outWidth;
IntBuffer inputBuffer = IntBuffer.allocate(oldWidth * oldHeight);
IntBuffer outputBuffer = IntBuffer.allocate(newWidth * newHeight);
Bitmap output = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
input.copyPixelsToBuffer(inputBuffer);
// position of the top left pixel of the 4 pixels to use interpolation on
int xTopLeft,yTopLeft;
int x,y,lastTopLefty;
final float xRatio=(float)newWidth/(float)oldWidth,yratio=(float)newHeight/(float)oldHeight;
// Y color ratio to use on left and right pixels for interpolation
float ycRatio2=0,ycRatio1=0;
// pixel target in the src
float xt,yt;
// X color ratio to use on left and right pixels for interpolation
float xcRatio2=0,xcratio1=0;
int rgbTopLeft=0,rgbTopRight=0,rgbBottomLeft=0,rgbBottomRight=0,rgbTopMiddle=0,rgbBottomMiddle=0;
// do the resizing:
for(x=0;x<newWidth;x++)
{
xTopLeft=(int)(xt=x/xRatio);
// when meeting the most right edge, move left a little
if(xTopLeft>=oldWidth-1)
xTopLeft--;
if(xt<=xTopLeft+1)
{
// we are between the left and right pixel
xcratio1=xt-xTopLeft;
// color ratio in favor of the right pixel color
xcRatio2=1-xcratio1;
}
for(y=0,lastTopLefty=Integer.MIN_VALUE;y<newHeight;y++)
{
yTopLeft=(int)(yt=y/yratio);
// when meeting the most bottom edge, move up a little
if(yTopLeft>=oldHeight-1)
yTopLeft--;
// we went down only one rectangle
if(lastTopLefty==yTopLeft-1)
{
rgbTopLeft=rgbBottomLeft;
rgbTopRight=rgbBottomRight;
rgbTopMiddle=rgbBottomMiddle;
rgbBottomLeft=inputBuffer.get(xTopLeft + (oldWidth * (yTopLeft+1)));
rgbBottomRight=inputBuffer.get(xTopLeft+1 + (oldWidth * (yTopLeft+1)));
rgbBottomMiddle=Color.argb((int)(Color.alpha(rgbBottomLeft)*xcRatio2+Color.alpha(rgbBottomRight)*xcratio1),//
(int)(Color.red(rgbBottomLeft)*xcRatio2+Color.red(rgbBottomRight)*xcratio1),//
(int)(Color.green(rgbBottomLeft)*xcRatio2+Color.green(rgbBottomRight)*xcratio1),//
(int)(Color.blue(rgbBottomLeft)*xcRatio2+Color.blue(rgbBottomRight)*xcratio1));
}
else if(lastTopLefty!=yTopLeft)
{
// we went to a totally different rectangle (happens in every loop start,and might happen more when making the picture smaller)
rgbTopLeft=inputBuffer.get(xTopLeft + (oldWidth * yTopLeft));
rgbTopRight=inputBuffer.get(xTopLeft+1 + (oldWidth * yTopLeft));
rgbTopMiddle=Color.argb((int)(Color.alpha(rgbTopLeft)*xcRatio2+Color.alpha(rgbTopRight)*xcratio1),//
(int)(Color.red(rgbTopLeft)*xcRatio2+Color.red(rgbTopRight)*xcratio1),//
(int)(Color.green(rgbTopLeft)*xcRatio2+Color.green(rgbTopRight)*xcratio1),//
(int)(Color.blue(rgbTopLeft)*xcRatio2+Color.blue(rgbTopRight)*xcratio1));
rgbBottomLeft=inputBuffer.get(xTopLeft + (oldWidth * (yTopLeft+1)));
rgbBottomRight=inputBuffer.get(xTopLeft+1+(oldWidth * (yTopLeft+1)));
rgbBottomMiddle=Color.argb((int)(Color.alpha(rgbBottomLeft)*xcRatio2+Color.alpha(rgbBottomRight)*xcratio1),//
(int)(Color.red(rgbBottomLeft)*xcRatio2+Color.red(rgbBottomRight)*xcratio1),//
(int)(Color.green(rgbBottomLeft)*xcRatio2+Color.green(rgbBottomRight)*xcratio1),//
(int)(Color.blue(rgbBottomLeft)*xcRatio2+Color.blue(rgbBottomRight)*xcratio1));
}
lastTopLefty=yTopLeft;
if(yt<=yTopLeft+1)
{
// color ratio in favor of the bottom pixel color
ycRatio1=yt-yTopLeft;
ycRatio2=1-ycRatio1;
}
// prepared all pixels to look at, so finally set the new pixel data
outputBuffer.put(x + outWidth * y,Color.argb(//
(int)(Color.alpha(rgbTopMiddle)*ycRatio2+Color.alpha(rgbBottomMiddle)*ycRatio1),//
(int)(Color.red(rgbTopMiddle)*ycRatio2+Color.red(rgbBottomMiddle)*ycRatio1),//
(int)(Color.green(rgbTopMiddle)*ycRatio2+Color.green(rgbBottomMiddle)*ycRatio1),//
(int)(Color.blue(rgbTopMiddle)*ycRatio2+Color.blue(rgbBottomRight)*ycRatio1)));
}
}
output.copyPixelsFromBuffer(outputBuffer);
return output;
}

Converting Camera Coordinates to Custom View Coordinates

I am trying to make a simple face detection app consisting of a SurfaceView (essentially a camera preview) and a custom View (for drawing purposes) stacked on top. The two views are essentially the same size, stacked on one another in a RelativeLayout. When a person's face is detected, I want to draw a white rectangle on the custom View around their face.
The Camera.Face.rect object returns the face bound coordinates using the coordinate system explained here and the custom View uses the coordinate system described in the answer to this question. Some sort of conversion is needed before I can use it to draw on the canvas.
Therefore, I wrote an additional method ScaleFacetoView() in my custom view class (below) I redraw the custom view every time a face is detected by overriding the OnFaceDetection() method. The result is the white box appears correctly when a face is in the center. The problem I noticed is that it does not correct track my face when it moves to other parts of the screen.
Namely, if I move my face:
Up - the box goes left
Down - the box goes right
Right - the box goes upwards
Left - the box goes down
I seem to have incorrectly mapped the values when scaling the coordinates. Android docs provide this method of converting using a matrix, but it is rather confusing and I have no idea what it is doing. Can anyone provide some code on the correct way of converting Camera.Face coordinates to View coordinates?
Here's the code for my ScaleFacetoView() method.
public void ScaleFacetoView(Face[] data, int width, int height, TextView a){
//Extract data from the face object and accounts for the 1000 value offset
mLeft = data[0].rect.left + 1000;
mRight = data[0].rect.right + 1000;
mTop = data[0].rect.top + 1000;
mBottom = data[0].rect.bottom + 1000;
//Compute the scale factors
float xScaleFactor = 1;
float yScaleFactor = 1;
if (height > width){
xScaleFactor = (float) width/2000.0f;
yScaleFactor = (float) height/2000.0f;
}
else if (height < width){
xScaleFactor = (float) height/2000.0f;
yScaleFactor = (float) width/2000.0f;
}
//Scale the face parameters
mLeft = mLeft * xScaleFactor; //X-coordinate
mRight = mRight * xScaleFactor; //X-coordinate
mTop = mTop * yScaleFactor; //Y-coordinate
mBottom = mBottom * yScaleFactor; //Y-coordinate
}
As mentioned above, I call the custom view like so:
#Override
public void onFaceDetection(Face[] arg0, Camera arg1) {
if(arg0.length == 1){
//Get aspect ratio of the screen
View parent = (View) mRectangleView.getParent();
int width = parent.getWidth();
int height = parent.getHeight();
//Modify xy values in the view object
mRectangleView.ScaleFacetoView(arg0, width, height);
mRectangleView.setInvalidate();
//Toast.makeText( cc ,"Redrew the face.", Toast.LENGTH_SHORT).show();
mRectangleView.setVisibility(View.VISIBLE);
//rest of code
Using the explanation Kenny gave I manage to do the following.
This example works using the front facing camera.
RectF rectF = new RectF(face.rect);
Matrix matrix = new Matrix();
matrix.setScale(1, 1);
matrix.postScale(view.getWidth() / 2000f, view.getHeight() / 2000f);
matrix.postTranslate(view.getWidth() / 2f, view.getHeight() / 2f);
matrix.mapRect(rectF);
The returned Rectangle by the matrix has all the right coordinates to draw into the canvas.
If you are using the back camera I think is just a matter of changing the scale to:
matrix.setScale(-1, 1);
But I haven't tried that.
The Camera.Face class returns the face bound coordinates using the image frame that the phone would save into its internal storage, rather than using the image displayed in the Camera Preview. In my case, the images were saved in a different manner from the camera, resulting in a incorrect mapping. I had to manually account for the discrepancy by taking the coordinates, rotating it counter clockwise 90 degrees and flipping it on the y-axis prior to scaling it to the canvas used for the custom view.
EDIT:
It would also appear that you can't change the way the face bound coordinates are returned by modifying the camera capture orientation using the Camera.Parameters.setRotation(int) method either.

Categories

Resources