Zoom Imageview using matrix - android

Hi I am trying to zoom in on a specific point on the image in my imageview with this code:
private void calculateAndZoom() {
matrix.set(getImageMatrix());
printMatrixValues(getImageMatrix());
float startpointY = (start_y_rel/ template_y_rel) * getHeight() * scale;
float startpointX = (start_x_rel / template_x_rel)* getWidth() * scale;
PrintDevMessage.print("Width: " + getWidth() + " Height: " + getHeight());
matrix.setScale(1,1,0,0);
matrix.postScale(scale, scale, startpointX, startpointY);
this.setScaleType(ImageView.ScaleType.MATRIX);
this.setImageMatrix(matrix);
printMatrixValues(getImageMatrix());
}
start_y_rel and start_x_rel is points relative to the template_y_rel and template_x_rel
I am using matrix.setScale(1,1,0,0) to remove any previous zooming and move to the first position.
This code works with scale 3 but when I try another scale it zooms in on the wrong position.

Ok so after 3 days of head-scratching i found the solution:
private void calculateAndZoom() {
float cScale=getMatrixValue(getImageMatrix(),Matrix.MSCALE_X);
float newScale = ((float)1.0/cScale)*scale;
matrix.set(getImageMatrix());
printMatrixValues(matrix);
float startpointY = ((start_y_rel / template_y_rel) * getHeight());
float startpointX = ((start_x_rel / template_x_rel) * getWidth());
PrintDevMessage.print("Width: " + getWidth() + " Height: " + getHeight());
matrix.postScale(newScale, newScale, startpointX, startpointY);
this.setScaleType(ImageView.ScaleType.MATRIX);
this.setImageMatrix(matrix);
printMatrixValues(getImageMatrix());
}
I did not account for the image being larger than the screen and when placed in the imageview the scale is changed. So i had to recalculate the scale i wanted with the old scale like this:
float newScale = ((float)1.0/cScale)*scale;

Related

How to capture detected face image using MLKit firebase FaceDetection

I want to only capture detected face image not whole image on camerasource.
I am drowing box like this
public void draw(Canvas canvas) {
Face face = mFace;
if (face == null) {
return;
}
// Draws a circle at the position of the detected face, with the face's track id below.
float x = translateX(face.getPosition().x + face.getWidth() / 2);
float y = translateY(face.getPosition().y + face.getHeight() / 2);
canvas.drawCircle(x, y, FACE_POSITION_RADIUS, mFacePositionPaint);
canvas.drawText("id: " + mFaceId, x + ID_X_OFFSET, y + ID_Y_OFFSET, mIdPaint);
canvas.drawText("happiness: " + String.format("%.2f", face.getIsSmilingProbability()), x - ID_X_OFFSET, y - ID_Y_OFFSET, mIdPaint);
canvas.drawText("right eye: " + String.format("%.2f", face.getIsRightEyeOpenProbability()), x + ID_X_OFFSET * 2, y + ID_Y_OFFSET * 2, mIdPaint);
canvas.drawText("left eye: " + String.format("%.2f", face.getIsLeftEyeOpenProbability()), x - ID_X_OFFSET*2, y - ID_Y_OFFSET*2, mIdPaint);
// Draws a bounding box around the face.
float xOffset = scaleX(face.getWidth() / 2.0f);
float yOffset = scaleY(face.getHeight() / 2.0f);
float left = x - xOffset;
float top = y - yOffset;
float right = x + xOffset;
float bottom = y + yOffset;
this.faceTrackingCords.y = top;
this.faceTrackingCords.width = right;
this.faceTrackingCords.x = left-right;
this.faceTrackingCords.height = bottom;
canvas.drawRect(left, top, right, bottom, mBoxPaint);
}
and trying to capture image like this but cropped image is not as expected.
mCameraSource.takePicture(null, new CameraSource.PictureCallback() {
#Override
public void onPictureTaken(byte[] bytes) {
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
Bitmap bitmapCropped = Bitmap.createBitmap(bitmap,(int)faceTrackingCords.x, (int)faceTrackingCords.y,
(int)faceTrackingCords.width, (int)faceTrackingCords.height);
screenImage.setImageBitmap(bitmapCropped);
}
});
Kindly please help

How to capture exactly the image inside the rectangular overlay in Camera?

I successfully made the auto crop to some extent for small devices so far. I am facing two issues:
1) the auto crop in big devices lets say 6.5 inches is not working properly
2) i want to take picture inside the rectangle frame
Below is my code:
public static Bitmap crop(Bitmap originalBitmap)
{
double originalWidth = originalBitmap.getWidth();
double originalHeight =
originalBitmap.getHeight();
double scaleX = originalWidth / 1280;
int navBarHeightPxIn1280x720Ui
CommonUtils.px2dp(CommonUtils.get
NavigationBarHeightInPx()) * 5 ;
double scaleXMultiplier = ((double) 1280) /
((double) (1280 - navBarHeightPxIn1280x720Ui));
scaleX = scaleX * scaleXMultiplier;
double scaleY = originalHeight / 720;
int x = (int) (52 * scaleX + 0.5);
int y = (int) (80 * scaleY + 0.5);
int width = (int) (896 * scaleX + 0.5);
int height = (int) (588 * scaleY + 0.5);
return Bitmap.createBitmap(originalBitmap, x, y,
width, height);
}

Rendering Bitmap based on Views position in parent

I'm trying to make a simple image editor. At the beginning I've thought that it'll be a good idea to simply save view state as Bitmap but, as it turned out, there is a wide range of screen resolutions and that leads to huge quality (and memory usage) fluctuations.
Now I'm trying to make a module that renders views state translated to desired resolution.
In the code below I'm trying to recreate current state of the views in canvas:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.id.test_1_1);
bitmap = Bitmap.createScaledBitmap(bitmap, parentView.getMeasuredWidth(), parentView.getMeasuredHeight(), true);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
for (View rootView : addedViews) {
ImageView imageView = rootView.findViewById(R.id.sticker);
float[] viewPosition = new float[2];
transformToAncestor(viewPosition, parentView, imageView);
Bitmap originalBitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
Matrix adjustMatrix = new Matrix();
adjustMatrix.postTranslate(viewPosition[0], viewPosition[1]);
adjustMatrix.postScale(
rootView.getScaleX(),
rootView.getScaleY(),
rootView.getWidth() / 2,
rootView.getHeight() / 2);
adjustMatrix.postRotate(rootView.getRotation(),
rootView.getWidth() / 2,
rootView.getHeight() / 2);
canvas.drawBitmap(originalBitmap, adjustMatrix, paint);
}
transformToAncestor function is from here.
public static void transformToAncestor(float[] point, final View ancestor, final View descendant) {
final float scrollX = descendant.getScrollX();
final float scrollY = descendant.getScrollY();
final float left = descendant.getLeft();
final float top = descendant.getTop();
final float px = descendant.getPivotX();
final float py = descendant.getPivotY();
final float tx = descendant.getTranslationX();
final float ty = descendant.getTranslationY();
final float sx = descendant.getScaleX();
final float sy = descendant.getScaleY();
point[0] = left + px + (point[0] - px) * sx + tx - scrollX;
point[1] = top + py + (point[1] - py) * sy + ty - scrollY;
ViewParent parent = descendant.getParent();
if (descendant != ancestor && parent != ancestor && parent instanceof View) {
transformToAncestor(point, ancestor, (View) parent);
}
}
(author wrote a note that his function does not support rotation, but there's not much rotation in my example so I don't think that important for now).
My problem is:
First image is generated via saving the parent view state. Second one is generated by translating views position, rotation and scale onto canvas.
As you can see, on the canvas, not scaled stickers are positioned properly, but scaled are incorrectly positioned.
How to position those scaled views properly?
I've managed to fix the issue myself.
It turned out my solution was nearly OK but I did not took into consideration that my manipulation of a matrix does change the arrangement of the original points, so my
rootView.getWidth() / 2,
rootView.getHeight() / 2
is no longer applicable as a center of the view after calling Matrix.postScale or Matrix.postRotation.
I wanted to:
apply scale with pivot on top left corner,
apply rotation with pivot on the center of the view.
Given the assumptions, here's the working code:
// setup variables for sizing and transformation
float position[] = new float[2];
transformToAncestor(position, rootView, imageView);
float desiredRotation = imageView.getRotation();
float sizeDeltaX = imageView.getMeasuredWidth() / (float) imageBitmap.getWidth();
float sizeDeltaY = imageView.getMeasuredHeight() / (float) imageBitmap.getHeight();
float desiredScaleX = imageView.getScaleX() * sizeDeltaX * scaleX;
float desiredScaleY = imageView.getScaleY() * sizeDeltaY * scaleY;
float imageViewWidth = imageView.getMeasuredWidth() * imageView.getScaleX();
float imageViewHeight = imageView.getMeasuredHeight() * imageView.getScaleY();
float rootViewWidth = rootView.getMeasuredWidth();
float rootViewHeight = rootView.getMeasuredHeight();
float percentXPos = position[0] / rootViewWidth;
float percentYPos = position[1] / rootViewHeight;
float percentXCenterPos = (position[0] + imageViewWidth/2)
/ rootViewWidth;
float percentYCenterPos = (position[1] + imageViewHeight/2)
/ rootViewHeight;
float desiredPositionX = background.getWidth() * percentXPos;
float desiredPositionY = background.getHeight() * percentYPos;
float desiredCenterX = background.getWidth() * percentXCenterPos;
float desiredCenterY = background.getHeight() * percentYCenterPos;
// apply above variables to matrix
Matrix matrix = new Matrix();
float[] points = new float[2];
matrix.postTranslate(
desiredPositionX,
desiredPositionY);
matrix.mapPoints(points);
matrix.postScale(
desiredScaleX,
desiredScaleY,
points[0],
points[1]);
matrix.postRotate(
desiredRotation,
desiredCenterX,
desiredCenterY);
// apply matrix to bitmap, then draw it on canvas
canvas.drawBitmap(imageBitmap, matrix, paint);
As you can see, the mapPoints method was the answer for my question - it simply returns points after tranformation.

Android: How to Zoom, Pan(Scroll) Tic Tac Toe Board View

So, I have a custom BoardView class extends View. I implemented drawing board, lines and drawing "O" drawable when user press on the cell.
But, I could not implement following problems correctly:
1. Zoom BoardView when user doing pinch(multi touch).
2. Scroll BoardView to left, right, top, bottom if BoardView bigger than BoardView initial width or height.
3. Find right cell coordinate when user pressed on the cell after zooming or scrolling.
This is my first game project, please help me if anybody know how to solve this problem.
I tried but did not work properly. BoardView width equal width screen width and BoardView height equal to BoardView width. It is square board view.
I give 200 bounty to implementing this problem.
Here is my project, everyone can download and edit: https://drive.google.com/file/d/0BxNIUTd_m1x8cUQ2NGpSMDBuVVE/view?usp=sharing
Github: https://github.com/boyfox/GameTicTacToe
BoardView code: http://pastie.org/10109253 or http://pastebin.com/TRU8Ybds
I found solution self, but need improving code, you can answer to my question with your solution!
Could you please move your code to github? It would be much easier to download, edit and propose changes.
If you're looking for a generic implementation of two finger zoom/rotate, take a look at my game (https://github.com/ZieIony/Gravity). The most interesting part is the GamePanel view and the dispatchTouchEvent method:
private PointF prevPos = new PointF(), prevPos2 = new PointF();
float scale = 1;
final float MIN_SCALE = 0.2f, MAX_SCALE = 2.0f;
float rotation = 0;
Matrix matrix = new Matrix();
private float prevDist;
public boolean dispatchTouchEvent(android.view.MotionEvent event) {
if (event.getPointerCount() == 2) {
float d = dist(event.getX(0), event.getY(0), event.getX(1),
event.getY(1));
float pivotX = (event.getX(0) + event.getX(1)) / 2;
float pivotY = (event.getY(0) + event.getY(1)) / 2;
float prevPivotX = (prevPos.x + prevPos2.x) / 2;
float prevPivotY = (prevPos.y + prevPos2.y) / 2;
if (event.getAction() == MotionEvent.ACTION_MOVE) {
float newScale = scale * d / prevDist;
newScale = Math.max(MIN_SCALE,
Math.min(newScale, MAX_SCALE));
float scaleFactor = newScale / scale;
scale = newScale;
matrix.postScale(scaleFactor, scaleFactor, pivotX, pivotY);
float prevAngle = (float) Math.atan2(
prevPos.x - prevPos2.x, prevPos.y - prevPos2.y);
float angle = (float) Math.atan2(
event.getX(0) - event.getX(1), event.getY(0)
- event.getY(1));
rotation += prevAngle - angle;
matrix.postRotate(
(float) ((prevAngle - angle) * 180.0f / Math.PI),
pivotX, pivotY);
matrix.postTranslate(-prevPivotX + pivotX, -prevPivotY
+ pivotY);
}
prevPos.x = event.getX(0);
prevPos.y = event.getY(0);
prevPos2.x = event.getX(1);
prevPos2.y = event.getY(1);
prevDist = d;
}
return true;
}
This method produces a transformation matrix, which you should use for drawing.
protected void dispatchDraw(Canvas canvas) {
canvas.save();
canvas.setMatrix(matrix);
// do your drawing here
canvas.restore();
}
Have a look at my answer here. If the answer seems satisfactory have a look at my github code. I think it is not difficult to implement your third point
"3. Find right cell coordinate when user pressed on the cell after zooming or scrolling.",
because the scaleFactor is available in MyView.java and scroll offsets could be obtained by getScrollX() and getScrollY(), by just doing simple math.

android 3d vertical carousel view

I am using http://www.codeproject.com/Articles/146145/Android-3D-Carousel code to create a vertical carousel view.i can see the vertical carousel using below changes in the code but center item is not properly placed in the screen and if the list items size increased, diameter moves upwards.
private void setUpChild(CarouselImageView child, int index, float angleOffset) {
// Ignore any layout parameters for child, use wrap content
addViewInLayout(child, -1 /*index*/, generateDefaultLayoutParams());
child.setSelected(index == mSelectedPosition);
int h;
int w;
if (mInLayout)
{
h = (getMeasuredHeight() - getPaddingBottom()-getPaddingTop())/3;
w = getMeasuredWidth() - getPaddingLeft() - getPaddingRight()/3;
}
else
{
h = (getMeasuredHeight() - getPaddingBottom()-getPaddingTop())/3;
w = getMeasuredWidth() - getPaddingLeft() - getPaddingRight()/3;
}
child.setCurrentAngle(angleOffset);
// modify the diameter.
Calculate3DPosition(child, w*(getAdapter().getCount()/4), angleOffset);
// Measure child
child.measure(w, h);
int childLeft;
// Position vertically based on gravity setting
int childTop = calculateTop(child, true);
childLeft = 0;
child.layout(childLeft, childTop, w, h);
}
change in calculate3position function as below
float x = (float) (-diameter/2 * Math.cos(angleOffset) * 0.00001);
float z = diameter/2 * (1.0f - (float)Math.cos(angleOffset));
float y = (float) (diameter/2 * Math.sin(angleOffset)) + diameter/2 - child.getWidth();
child.setX(x);
child.setZ(z);
child.setY(y);
I think that this calculation:
float x = (float) (-diameter/2 * Math.cos(angleOffset) * 0.00001);
float z = diameter/2 * (1.0f - (float)Math.cos(angleOffset));
float y = (float) (diameter/2 * Math.sin(angleOffset)) + diameter/2 - child.getWidth();
should be this:
float x = 0.0f
float z = diameter/2.0f * (1.0f - (float)Math.cos(angleOffset));
float y = (diameter/2.0f * Math.sin(angleOffset)) + diameter/2.0f - child.getHeight()/2.0f;
Your x position should always be zero, and your y position should be based on the sin, and should be offset by 1/2 of the height of the child instead of 1/2 of the width.
Hello try this code and replace with this code in your Calculate3DPosition method
angleOffset = angleOffset * (float) (Math.PI / 180.0f);
float y = (float) (((diameter * 60) / 100) * Math.sin(angleOffset)) + ((diameter * 50) / 100);
float z = diameter / 2 * (1.0f - (float) Math.cos(angleOffset));
float x = (float) (((diameter * 5) / 100) * Math.cos(angleOffset) * 0.3);
child.setItemX(x);
child.setItemZ((z * 30) / 100);
child.setItemY(-(y));
its solve my problem please try this one

Categories

Resources