Find a small scale image into a large scale image - c#

I have images from two camera. Both of them send a picture but the picture of camera 1 is zoomed(Its like that picture of camera 1 is inside of picture of camera 2).
I have the position of a point in picture of camera 1. This position can change in different pictures. Now I want to find that point in picture of camera 2.
Both of cameras images are in 2560X2048 px.
How can I find that x,y in picture 2?

I found the answer. I cropped the unzoomed! picture to be equal to zoomed picture. and save the x,y of cropped picture on unzoomed picture. Than I calculate percent of x,y of that point in zoomed picture. something like this :
double percentXZoom = (I_PLATE_MIN_X * 100) / 2560;
double xCropedImage = xD - xU;
double xDiff = (xCropedImage * percentXZoom) / 100;
double x = xD + Math.Abs(xDiff);
double percentYZoom = (I_PLATE_MIN_Y * 100) / 2560;
double yCropedImage = yD - yU;
double yDiff = (yCropedImage * percentYZoom) / 100;
double y = yD + Math.Abs(yDiff);
"2560" is the size of pixel in pictures.
xD, yD is the start point of cropped picture. and xU, yU is the end point of cropped picture.
Now I have the x,y of that point in unzoomed picture.

Related

Rotating points 90 degrees

I'm building a paint-esque program where the user can draw shapes like rectangles and ellipses on the canvas. These shapes have two coordinates stored, the corner from when the user started to draw it and the corner where the user stopped drawing it. I want to be able to rotate these shapes 90 degrees clockwise around the center of the bitmap they are drawn on, this bitmap is 600 x 600 pixels large. How can I transform the avaliable coordinates of these shapes so that they appear rotated 90 degrees.
This is the code that I have been trying to make work:
foreach (TekeningElement t in getekende_elementen)
{
int x_begin = t.GetBeginPunt.X; //store x coordinate of starting point
int y_begin = t.GetBeginPunt.Y; //store y coordinate of starting point
int x_eind = t.GetEindPunt.X; //store x coordinate of end point
int y_eind = t.GetEindPunt.Y; //store y coordinate of end point
int x_verschil = x_eind - x_begin; //calculate width
int y_verschil = y_eind - y_begin; //calculate height
t.SetBeginPunt = new Point(600 - x_begin - y_verschil, x_begin); //set new starting point
t.SetEindPunt = new Point(600 - x_eind + y_verschil, x_eind); //set new end point
}
Thanks for the help.

Issue with trigonometry using Xamarin.Forms.Map.Position

I am working on a mobile app in C# using the Xamarin framework. I am trying to move a point by a fixed angle on a map like in the first part of the gif below. I believe I am using the right mathematical functions to compute the coordinates of the shifted points since in first part of the GIF, in GeoGebra, everything seems to be fine.
But when it comes to the actual in-app implementation, the results are quite weird : the angle is not consistent and the distance between the center and the points varies by moving the target.
The GIF showing the issue
I don't have a clue about what is wrong with the code. In the code below I use polylineOptions to draw the lines but I've tried with a Polygon and it displays the same results. Maybe it's because customMap.UserPin.Position returns the coordinates in Decimal Degree format (i.g. 34.00462, -4.512221) and the gap between two position is too small for a double.
Here are the two functions used to draw the lines.
// Add a cone's side to the variable coneLines
private void addConePolyline(double angle, CustomMap customMap, LatLng userPos)
{
// The coordinates of the end of the side to be drawn
LatLng conePoint = movePoint(angle, customMap.UserPin.Position, customMap.TargetPin.Position);
var polylineOptions = new PolylineOptions();
polylineOptions.InvokeWidth(10f);
polylineOptions.InvokeColor(Android.Graphics.Color.Argb(240, 255, 20, 147)); // Pink
polylineOptions.Add(userPos);
polylineOptions.Add(conePoint);
// Add the line to coneLines
coneLines.Add(map.AddPolyline(polylineOptions));
}
// Moves a point by the given angle on a circle of center rotationCenter with respect to p
private LatLng movePoint(double angle, Position rotationCenter, Position initialPoint)
{
// Compute the components of the translation vector between rotationCenter and initialPoint
double dx = initialPoint.Latitude - rotationCenter.Latitude;
double dy = initialPoint.Longitude - rotationCenter.Longitude;
// Compute the moved point's position
double x = rotationCenter.Latitude + Math.Cos(angle) * dx - Math.Sin(angle) * dy;
double y = rotationCenter.Longitude + Math.Sin(angle) * dx + Math.Cos(angle) * dy;
LatLng res = new LatLng(x, y);
return res;
}
I hope someone can help me with this!
Thank you.

Calculate how much to Pan/Tilt image

I am currently implementing Pan/Tilt/Zoom support in my application. I pass in an image and then calculate zoom in the following manner
int widthPercent = width / 100;
int heightPercent = height / 100;
int zoomX = width - (widthPercent * (int)Zoom);
int zoomY = height - (heightPercent * (int)Zoom);
where width is width of original image, height is height of original image and Zoom is a value passed in from the UI, ranging from 0 to 100.
I now wish to implement Pan/Tilt support while an image is zoomed in so that the whole image can still be accessed. Again Pan and Tilt will be controlled from the UI(again 0 to 100) but I want it to stay within the boundaries of the image so that the image does not repeat which it is currently doing.
I am current calculating the Pan and Tilt like so:
// Calculate Pan
int panWidthPercent = width / 100;
int finalPan = (int)Pan * panWidthPercent;
// Calculate Tilt
int tiltHeightPercent = height / 100;
int finalTilt = (int)Tilt * tiltHeightPercent;
This works to an extent however it seems to keep repeating the image after panning for a small time(usually when Pan = 10 or more). I wish it to stop after it renders all the image i.e it reaches the width but adding something like the following doesnt seem to stop this
if(finalPan >= width) finalPan = width;
Once the values are calculate I create a source rectangle using these values
mClippingRectangle = new Int32Rect(finalPan, finalTilt, zoomX, zoomY);
which is then used against the base image for rendering only that rectangle
In short how can I calculate how much I should pan/tilt when I already know the zoom of the image
Managed to accomplish it by checking whether the Pan/Tilt Amount added to the zoom width/height is greater than the overall image width/height then stop it from panning/tilting
// Calculate Pan
double finalPan = Pan * widthPercent;
if ((finalPan + zoomX) >= width)
{
finalPan = width - zoomX;
}
// Calculate Tilt
double finalTilt = Tilt * heightPercent;
if ((finalTilt + zoomY) >= height)
{
finalTilt = height - zoomY;
}

EMGU CV MCvBox2D.GetVertices gives different order of corners

I'm using EMGU CV for my project and I'm facing a weird problem.
I use cannyedges to find some squares in a photo.
This is working correctly. After that i want to take a pixel inside each square and use that to draw the border.
The problem I'm facing is that i need the vertices of each corner in order to generate a random pixel.
To do this I use the code:
PointF[] corners = rectangle.GetVertices();
float x = Math.Max(corners[1].X, corners[0].X);
float y = Math.Max(corners[1].Y, corners[2].Y);
float width = Math.Min(corners[2].X, corners[3].X) - x;
float height = Math.Min(corners[0].Y, corners[3].Y) - y;
The problem with this code is that rectangle.GetVertices(); gives a different order of corners each time.
The first rectangle returns bottomleft as corner 0, top left as corner 1 etc.
How ever the second rectangle returns bottomright as corner 0, bottomleft as corner 1 etc.
I'm wondering if anyone else is having this problem and if anyone knows how to fix this?
If you need more info to answer this problem please tell me.
PointF[] corners = rectangle.GetVertices();
// Maybe this
corners = corners.OrderBy(s => s.X).ThenBy(s => s.Y).ToArray();
float x = Math.Max(corners[1].X, corners[0].X);
float y = Math.Max(corners[1].Y, corners[2].Y);
float width = Math.Min(corners[2].X, corners[3].X) - x;
float height = Math.Min(corners[0].Y, corners[3].Y) - y;

Resize drawn rectangle to fit original image

I'm developing an application to manipulate images scanned on a wide-image scanner. These images are shown as a ImageBrush on a Canvas.
On this Canvas they can a make Rectangle with the mouse, to define an area to be cropped.
My problem here is to resize the Rectangle according to the original image size, so that it crops the exact area on the original image.
I've tried many things so far and it's just sqeezing my brain, to figure out the right solution.
I know that I need to get the percent that the original image is bigger than the image shown on the canvas.
The dimentions of the original image are:
h: 5606
w: 7677
And when I show the image, they are:
h: 1058,04
w: 1910
Which gives these numbers:
float percentWidth = ((originalWidth - resizedWidth) / originalWidth) * 100;
float percentHeight = ((originalHeight - resizedHeight) / originalHeight) * 100;
percentWidth = 75,12049
percentHeight = 81,12665
From here I can't figure how to resize the Rectangle correctly, to fit the original image.
My last approach was this:
int newRectWidth = (int)((originalWidth * percentWidth) / 100);
int newRectHeight = (int)((originalHeight * percentHeight) / 100);
int newRectX = (int)(rectX + ((rectX * percentWidth) / 100));
int newRectY = (int)(rectY + ((rectY * percentHeight) / 100));
Hopefully someone can lead me in the right direction, because i'm off track here and I can't see what i'm missing.
Solution
private System.Drawing.Rectangle FitRectangleToOriginal(
float resizedWidth,
float resizedHeight,
float originalWidth,
float originalHeight,
float rectWidth,
float rectHeight,
double rectX,
double rectY)
{
// Calculate the ratio between original and resized image
float ratioWidth = originalWidth / resizedWidth;
float ratioHeight = originalHeight / resizedHeight;
// create a new rectagle, by resizing the old values
// by the ratio calculated above
int newRectWidth = (int)(rectWidth * ratioWidth);
int newRectHeight = (int)(rectHeight * ratioHeight);
int newRectX = (int)(rectX * ratioWidth);
int newRectY = (int)(rectY * ratioHeight);
return new System.Drawing.Rectangle(newRectX, newRectY, newRectWidth, newRectHeight);
}
I think the only reliable option is to let your users zoom in to the image (100% or higher zoom level) and make a selection on part of the image. This way they can make an exact pixel-based selection. (Assuming that the purpose of your selection rectangle is to select part of an image.)
Your problem now is that you're using floating-point calculations because of the 75% zoom level and rounding errors will make your selection rectangles inaccurate. No matter what you do, when you try to make a selection on a shrinked image, you're not selecting exact pixels - you're selecting parts of pixels as you resize your rectangle. Since a partial pixel cannot be selected, the selection edges will be rounded up or down so you either select one pixel too many or one pixel too few in a given direction.
Another issue that I just noticed is that you distort your image - horizontally it's 75% zoom, vertically it's 81%. This makes it even harder for users because the image will be smoothed differently in the two directions. Horizontally 4 original pixels will be interpolated on 3 output pixels; vertically 5 original pixels will be interpolated on 4 output pixels.
You are actually doing a form of projection. Don't use percentages, just use the ratio between 5606 and 1058,4 = ~5.30. When the user drags the rectangle, reproject it which is selectedWidth * 5606/1058.4.

Categories