Android Getting coordinates of an image - android

I have a custom ImageView that re positions a an image on a web page. The image that is seen on the phone screen should represent the image on the web page.
I am using Matrix.mapPoints(float[] dst, float[] src) to try and get the how much the image is off-set when scaled to correctly frame the image. I am also taking into account the how much the image is scaled, and the size if the image view on the phone compared to the image tag width on the web page.
UpdateImage() in Image view class
public void updateImage() {
final float phoneDisplayScale = (float) getWidth() / (float) getDrawable().getIntrinsicWidth();
float[] m = new float[9];
matrix.getValues(m);
float scale = m[Matrix.MSCALE_X];
float[] arr = {0, 0};
matrix.mapPoints(arr, arr);
//holder.rect = {image_x, image_y, imageWidth, imageHeight}
if (holder != null) {
holder.getRect()[0] = arr[0] / phoneDisplayScale;
holder.getRect()[1] = arr[1] / phoneDisplayScale;
holder.getRect()[2] = scale * (getImageWidth() / phoneDisplayScale);
holder.getRect()[3] = scale * (getImageHeight() / phoneDisplayScale);
Log.i(TAG, "doInBackground: " + Arrays.toString(holder.getRect()));
Log.i(TAG, "doInBackground: " + Arrays.toString(holder.getRect()));
Log.i(TAG, "doInBackground: " + Arrays.toString(holder.getRect()));
}
//
//
// Socket io code
//
//
}
this works when the image is scaled and aligned to so that the top left of the image is in the top left of the ImageView, but you can never zoom in on the bottom right of the image. I also noticed that if I zoom in to the max that the map points method returns the width and height (minus values) of the image.

Ok my logic was a bit off I have changed the position calculation to the following and it now works.
holder.getRect()[0] = (arr[0] / scale) * phoneDisplayScale;
holder.getRect()[1] = (arr[1] / scale) * phoneDisplayScale;

Related

Calculate position of an Image in Absolutelayout when zooming

I have a Page which contains an AbsoluteLayout with a PinchZoomContainer (like the one from microsoft docs). In this Container is an image that fills the entire screen. When the user tapes on the image, another image (a pin) is positioned at the tappostion. So far this works. My problem is, that i couldn't figure out, how to calculate the position of the added image (user tapped) when the user zooms in and out.
I want the added image to stay at the tapped position, no matter if the user zooms in or out.
When i put the image in a grid the calculation gets done automatically.
Is there a better way to achieve that? I've chosen AbsoluteLayout because i need to put the image at the tapped position.
The following code is used for zooming. Here I can't figure out how to do the calculation for the added image. The image gets added to the AbsoluteLayout on runtime.
Normal scale
Zoomed in
void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
{
if (e.Status == GestureStatus.Started)
{
// Store the current scale factor applied to the wrapped user interface element,
// and zero the components for the center point of the translate transform.
startScale = Content.Scale;
Content.AnchorX = 0;
Content.AnchorY = 0;
startTransX = pin.TranslationX;
startTranxY = pin.TranslationY;
}
if (e.Status == GestureStatus.Running)
{
// Calculate the scale factor to be applied.
currentScale = currentScale + (e.Scale - 1) * startScale;
currentScale = Math.Max(1, currentScale);
// The ScaleOrigin is in relative coordinates to the wrapped user interface element,
// so get the X pixel coordinate.
double renderedX = Content.X + xOffset;
double deltaX = renderedX / Width;
double deltaWidth = Width / (Content.Width * startScale);
double originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;
// The ScaleOrigin is in relative coordinates to the wrapped user interface element,
// so get the Y pixel coordinate.
double renderedY = Content.Y + yOffset;
double deltaY = renderedY / Height;
double deltaHeight = Height / (Content.Height * startScale);
double originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;
// Calculate the transformed element pixel coordinates.
double targetX = xOffset - (originX * Content.Width) * (currentScale - startScale);
double targetY = yOffset - (originY * Content.Height) * (currentScale - startScale);
// Apply translation based on the change in origin.
// needs to use Xamarin.Forms.Internals or Extension
Content.TranslationX = targetX.Clamp(-Content.Width * (currentScale - 1), 0);
Content.TranslationY = targetY.Clamp(-Content.Width * (currentScale - 1), 0);
x = Content.TranslationX;
y = Content.TranslationY;
// Apply scale factor
Content.Scale = currentScale;
}
if (e.Status == GestureStatus.Completed)
{
// Store the translation delta's of the wrapped user interface element.
xOffset = Content.TranslationX;
yOffset = Content.TranslationY;
x = Content.TranslationX;
y = Content.TranslationY;
}
}

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.

How to horizontal/Vertical scroll a panoramic image in Android?

I'm looking for to some way for make a scroll, or scan of a panoramic image in Android. With this I mean show a part of my image adjusting the height of the image (or width in vertical) and automatically moving slowly the view scrolling all the image. For example:
this image its so big to try to see it in a 16:9 device(with a bit of detail i mean), so i want to do something like:
Just show that part in the screen and move it slowly to the right till the end of the image. Achieving a "scroll" effect across the image.
I have been looking in the website and internet last days and I just found the library of PanoramicGL or some ways to watch 360ยบ images.
This Is For Scroll Click Here
You must use PanoramaClient (which is part of Google Play Services) to open PhotoSphere photos.
An example of how to do this can be found on this Android developer blog post:
// This listener will be called with information about the given panorama.
OnPanoramaInfoLoadedListener infoLoadedListener =
new OnPanoramaInfoLoadedListener() {
#Override
public void onPanoramaInfoLoaded(ConnectionResult result,
Intent viewerIntent) {
if (result.isSuccess()) {
// If the intent is not null, the image can be shown as a
// panorama.
if (viewerIntent != null) {
// Use the given intent to start the panorama viewer.
startActivity(viewerIntent);
}
}
// If viewerIntent is null, the image is not a viewable panorama.
}
};
// Create client instance and connect to it.
PanoramaClient client = ...
...
// Once connected to the client, initiate the asynchronous check on whether
//the image is a viewable panorama.
client.loadPanoramaInfo(infoLoadedListener, panoramaUri);
Thanks to kishu, I made my own method to animate a panoramic image dynamically depending if its in landscape or portrait mode.
You can ignore the orientation value of the method, I only use it to change the animation of the video from X to Y if I want to see the image in landscape.
public void animatePanorama(int orientation) {
int duration;
// The milisecons that we will use dinamically for the animation, been this is 1,31milisecons for pixel
float miliseconsPixel = 1.31f;
float imageWidth;
//Delta X and Y values for the animation
float deltaX = 0f;
float deltaY = 0f;
float aspectRatio;
//We get the drawable from the container to calcule his real Width and Height
final Drawable d = mImageContainer.getDrawable();
final int origWidth = d.getIntrinsicWidth();
final int origHeight = d.getIntrinsicHeight();
//With that we get the real aspect ratio and a duration
if (origWidth > origHeight) {
aspectRatio = (float) origWidth / (float) origHeight;
duration = (int) (miliseconsPixel * origWidth);
imageWidth = mImageContainer.getMeasuredHeight() * aspectRatio;
} else {
aspectRatio = (float) origHeight / (float) origWidth;
duration = (int) (miliseconsPixel * origHeight);
imageWidth = mImageContainer.getMeasuredWidth() * aspectRatio;
}
//Set if the animation will be horizontal(Portrait) or Vertical(landscape)
if (orientation == 0 || orientation == 180)
deltaX = imageWidth / 2f - mImageContainer.getMeasuredWidth() / 2;
else
deltaY = imageWidth / 2f - mImageContainer.getMeasuredHeight() / 2;
//New Animation
Animation animation = new TranslateAnimation(deltaX, -deltaX, deltaY, -deltaY);
//Add Duration
animation.setDuration(duration);
animation.setFillAfter(true);
//Add cycle for repeating mode
animation.setRepeatCount(-1);
animation.setRepeatMode(Animation.REVERSE);
mImageContainer.startAnimation(animation);
}

android-gpuimage - image straightening with GPUImageView

In my android app.I want to make image Straightening edit feature using android-gpuimage library but GPUImageView doesn't give feature of getBitmap() or setMatrix() then how is it possible please let me know? here is the code to review :
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(isStraightenEffectEnabled){
float angle = (progress - 45);
float width = mGPUImageView.getWidth();
float height = mGPUImageView.getHeight();
if (width > height) {
width = mGPUImageView.getHeight();
height = mGPUImageView.getWidth();
}
float a = (float) Math.atan(height/width);
// the length from the center to the corner of the green
float len1 = (width / 2) / (float) Math.cos(a - Math.abs(Math.toRadians(angle)));
// the length from the center to the corner of the black
float len2 = (float) Math.sqrt(Math.pow(width/2,2) + Math.pow(height/2,2));
// compute the scaling factor
float scale = len2 / len1;
Matrix matrix = mGPUImageView.getMatrix();
if (mMatrix == null) {
mMatrix = new Matrix(matrix);
}
matrix = new Matrix(mMatrix);
float newX = (mGPUImageView.getWidth() / 2) * (1 - scale);
float newY = (mGPUImageView.getHeight() / 2) * (1 - scale);
matrix.postScale(scale, scale);
matrix.postTranslate(newX, newY);
matrix.postRotate(angle, mGPUImageView.getWidth() / 2, mGPUImageView.getHeight() / 2);
Is it possible to get mGPUImageView.setMatrix(matrix);
NOW HERE getMatrix() is a method of GPUImageView but setMatrix() or getBitmap() is not method available with GPUImageView class. Any workarounds if possible ?
add getGPUImage in GPUImageView class
public GPUImage getGPUImage() {
return mGPUImage;
}
then get you can get bitmap like this:
mGPUImageView.getGPUImage().getBitmapWithFilterApplied();
You can also get bitmap like this:
Bitmap bitmap = mGPUImageView.capture();
You can get filtered bitmap renderer and Pixelbuffer. This might be helpful for you.
GPUImageLookupFilter amatorka = new GPUImageLookupFilter();
amatorka.setBitmap(BitmapFactory.decodeResource(getResources(), getResources().getIdentifier("fil_" + position, "drawable", getPackageName())));
GPUImageRenderer renderer = new GPUImageRenderer(amatorka);
renderer.setImageBitmap(bitmap, false);
PixelBuffer buffer = new PixelBuffer(80, 80);
buffer.setRenderer(renderer);
buffer.getBitmap();

Android: OpenCV image gets cropped after rotation in between -75 to -105 and 75 to 105

I am trying to put a watermark/Image on another image, we can zoom in, zoom out, drag and rotate the watermark image by fingertouch. I am using Open CV library to rotate the image as suggested in this post
image rotation with opencv in android cuts off the edges of an image
It works fine until the rotation angle gets in between -75 to -105 and 75 to 105. In this range my image get cropped or it changes its position. I have tried several ways to get the right center point for the watermark image to put it in right position after rotating it but failed to do so.
Here is the code to rotate the image
// CALCULATE ROTATED WATERMARK IMAGE
private void CreateRotatedWaterMark()
{
// Means rotation took place
if (waterMarkAngle > 0 || waterMarkAngle < 0) {
// calculation for new width/height of rotated watermark image
newWidthHeight = boundingWaterMarkRect();
// remove when done testing
double pivotX = newWidthHeight[0] / 2; // 0 is width
double pivotY = newWidthHeight[1] / 2; // 1 is height
// rotating water image
org.opencv.core.Point center;
Size targetSize;
Mat targetMat;
// scalar is color/ RGBA , but alpha doesn't seem to work
Scalar colorScalar = new Scalar(255, 190, 190, 0);
double offsetX = (newWidthHeight[0] - scaledImage.width()) / 2;
double offsetY = (newWidthHeight[1] - scaledImage.height()) / 2;
// watermark's rotation lays somewhere in between 75' AND 105' OR
// -75' AND -105'
Log.e(TAG, "check => offsetX/offsetY Before => " + offsetX + " / "
+ offsetY);
if (offsetX < 0 || offsetY < 0) {
//this gets true when angle of rotation gets between -75 to -105 and 75 to 105
// change the offsets, now new newWidth < oldWidth AND newHeight
// > oldHeight (could be vice versa)
offsetX = (newWidthHeight[0] - scaledImage.height()) / 2;
offsetY = (newWidthHeight[1] - scaledImage.width()) / 2;
// Declaring new target size and target Mat, so rotated image is
// placed in new target Mat
targetSize = new Size(newWidthHeight[1], newWidthHeight[0]);
targetMat = new Mat(targetSize, scaledImage.type(), colorScalar);
// Getting the reference of center area from target Mat,
// below we're copying the actual image (scaledImage) to center
// position to target Mat
Mat waterSubmat = targetMat.submat((int) offsetX, (int) offsetX
+ scaledImage.height(), (int) offsetY, (int) offsetY
+ scaledImage.width());
scaledImage.copyTo(waterSubmat);
// Writing target image to sdcard, so we can know if its working
// properly, remove it when done with testing
Highgui.imwrite("mnt/sdcard/scaled90.png", targetMat);
Highgui.imwrite("mnt/sdcard/waterSubmat.png", waterSubmat);
Highgui.imwrite("mnt/sdcard/ScaledImage.png", scaledImage);
// targetSize is reverted again, so that target mat is pasted on
// canvas image
targetSize = new Size(newWidthHeight[0], newWidthHeight[1]);
pivotX = newWidthHeight[0] / 2;
pivotY = newWidthHeight[1] / 2;
Log.e(TAG, "check => pivotX/pivotY => " + pivotX + " / "
+ pivotY);
Log.e(TAG, "check => Angle => " + waterMarkAngle);
center = new org.opencv.core.Point(pivotX, pivotY);
} else {
center = new org.opencv.core.Point(pivotX, pivotY);
targetSize = new Size(newWidthHeight[0], newWidthHeight[1]);
targetMat = new Mat(targetSize, scaledImage.type(), colorScalar);
// Centralizing watermark
Mat waterSubmat = targetMat.submat((int) offsetY, (int) offsetY
+ scaledImage.height(), (int) offsetX, (int) offsetX
+ scaledImage.width());
scaledImage.copyTo(waterSubmat);
Highgui.imwrite("mnt/sdcard/scaled10.png", targetMat);
}
Mat rotImage = Imgproc.getRotationMatrix2D(center, waterMarkAngle,
1.0); // 1.0 means scale 100%
Highgui.imwrite("mnt/sdcard/Rotated90.png", rotImage);
// Mat waterSubmat1 = rotImage.submat(0, scaledImage.height(), 0,
// scaledImage.width());
Mat resultMat = new Mat();
// scalar for color, Imagproc.warAffine actually rotates the final
// watermark on canvas image
colorScalar = new Scalar(122, 22, 22);
Imgproc.warpAffine(targetMat, resultMat, rotImage, targetSize,
Imgproc.INTER_LINEAR, Imgproc.BORDER_CONSTANT, colorScalar);
Log.i(TAG, "check MATRIX = " + resultMat.toString());
Log.i(TAG, "check Result Mat " + resultMat.size().toString());
scaledImage = resultMat.clone();
Highgui.imwrite("mnt/sdcard/Result100.png", targetMat);
// Log.i(TAG, "check Result postion = "+ resultMat.r);
// WRITE SOME TEXT ON CANVAS IMAGE, its not rotated
Core.putText(scaledImage, "angle: " + waterMarkAngle,
new org.opencv.core.Point(0, scaledImage.height() / 2),
Core.FONT_HERSHEY_TRIPLEX, 2, new Scalar(23, 12, 450, 0.5),
2); // CV_BLUR_NO_SCALE
} else {
// CHANGE OPACITY OF WATERMARK IMAGE
// Core.multiply(scaledImage, new Scalar(1, 1, 1, 0.6),
// scaledImage);
// REMOVE THIS WHEN DONE TESTING
// Highgui.imwrite("mnt/sdcard/opacityWatermark.png",scaledImage);
}
}
private double[] boundingWaterMarkRect() {
// -----NEW CALCULATION------
// so we always get positive angle
double tempAngle = ((waterMarkAngle < 0 ? 360 - waterMarkAngle : waterMarkAngle) % 360);
double radians = Math.toRadians(tempAngle);
Log.i(TAG, "check => radian => "+ radians);
double sin = Math.abs(Math.sin(radians));
double cos = Math.abs(Math.cos(radians));
double newWidth = (double) (scaledImage.width() * cos + scaledImage.height() * sin);
double newHeight = (double) (scaledImage.width() * sin + scaledImage.height() * cos);
double[] wh = {newWidth, newHeight};
return wh;
}
Following are two images first one is right and the other is rotated wrong
Anyone have got solution for it?

Categories

Resources