Rotation of coordinate system with rectangle leads to parallelogram - math

In my Flutter app, I have drawn a rectangle in one coordinate system on a Google Map and I want to rotate this coordinate system around the coordinate (0,0). How this can be done is described here: Rotation matrix. I have implemented the rotation of coordinates like this in my app:
class Coordinate {
Coordinate(this.x, this.y);
double x;
double y;
void rotate(double angle) {
// angle is in degrees, convert to radians
final double angleInRadians = angle * (math.pi / 180);
final double oldX = x;
final double oldY = y;
final double newX = oldX * math.cos(angleInRadians) - oldY * math.sin(angleInRadians);
final double newY = oldX * math.sin(angleInRadians) + oldY * math.cos(angleInRadians);
x = newX;
y = newY;
}
}
Using this to rotate four corners of a rectangle works fine for some places in the world, like Australia and a place near (0,0). In this picture, you can see the rotation of the red rectangle on the top around the point (0,0) (bottom left) to the rotated red rectangle on the bottom right:
Please ignore all the markers and non-red lines. The next to images show a rectangle like the one in the picture above which I again rotate around (0,0) using the code above, but as you can see in the second image, the red rectangle is not a rectangle anymore, but a parallelogram instead.
I cannot find an explanation for this. The questions I ask myself are: Why does the code work for some places but not for others? Why does the rectangle transform to a perfect parallelogram instead of whatever other shape with the points possibly all around the world? As it is working for some locations, the problem cannot be that I have mixed up some of the coordinates or something like that, it has to do something with the calculation of the edges of the rotated rectangle. But I cannot find out what I did wrong here.
REMINDER: IGNORE ALL MARKERS AND NON-RED LINES

Related

QPixmap xAxis Rotation

I want to rotate a pixmap from its xAxis, but it just rotates from top left corner.(I want it to be rotated from the center) here is my code:
QTransform *X = new QTransform();
X->translate(pixmap().size().width() / 2, pixmap().size().height() / 2);
X->rotate(rtn, Qt::XAxis); //rtn is an angle
setTransform(*X);
It seems that the translate method does not change the origin point to the center of my pixmap.
Now I want some help to solve this problem.
ok, the problem was that I didn't translate back my transformation after rotate method, this is the appropriate rotation from center on xAxis:
setTransform(QTransform().translate(pixmap().size().width() / 2, pixmap().size().height() / 2).rotate(rtn, Qt::XAxis).translate(-pixmap().size().width() / 2, -pixmap().size().height() / 2));

Zoom chart in mouse focus

I have a custom chart which I scale using the following code:
final double SCALE_DELTA = 1.1;
treePane.setOnScroll(new EventHandler<ScrollEvent>()
{
#Override
public void handle(ScrollEvent event)
{
event.consume();
if (event.getDeltaY() == 0)
{
return;
}
double scaleFactor = (event.getDeltaY() > 0) ? SCALE_DELTA : 1 / SCALE_DELTA;
treePane.setScaleX(treePane.getScaleX() * scaleFactor);
treePane.setScaleY(treePane.getScaleY() * scaleFactor);
}
});
I noticed that when I scroll the chart with mouse wheel I cannot zoom the chart where my mouse points. Instead of this the chart is zoomed to left or right for example.
I would like when I zoom with the mouse wheel to scale the chart where my cursor points. Is there any solution?
I haven't worked with javafx, but I will try to answer anyway. From my experience with Win32Api/GDI and XNA you should definitely be able to read mouse coordinates. Anything you display is displayed at coordinates x,y. When you want to scale and zoom to the cursor's location, you will redraw with this in mind: (assume zoom factor = z, mouseX and mouseY the mouse coordinates X and Y the new coordinates)
your cursor will have to point at the same pixel, so if the image is z times bigger now, so will the mouse coordinates be, relative to the source of the picture. To these coordinates, essentially the distance from the top and left of the image, you have to add the coordinates of the source itself, which should remain unchanged relative to the window's top-left corner. This eventually means that mouseX - X = (mouseX - x)*z, which means X = mouseX - (mouseX - x)*z
Same goes for the Y coordinate. In theory this should work perfectly, i have not tried it with code but it seems right on paper. You will notice X and Y seem to be getting smaller, essentially they might even turn out negative since by scaling and keeping the mouse on the same pixel, you push/stretch the top-left corner further up and left, possibly out of the screen.
You will probably work with the scrollbars though, same philosophy on their displacement.
Play around with the variables a bit to make them fit the drawing mode, I do not know if the libraries you are working with start from the screen's (0,0), or the window's, or the working areas, so you will have to adapt it to the rest of the code, but this is the math/geometry behind it.

What is the gradient orientation and gradient magnitude?

I am currently studying a module in computer vision called edge detection.
I am trying to understand the meaning of gradient orientation and gradient magnitude.
As explained by Dima in his answer, you should be familiar with the mathematical concept of gradient in order to better understand the gradient in the field of image processing.
My answer is based on the answer of mevatron to this question.
Here you find a simple initial image of a white disk on a black background:
you can compute an approximation of the gradient of this image. As Dima explained in his answer, you have two component of the gradient, an horizontal and a vertical component.
The following images shows you the horizontal component:
it shows how much the gray levels in your image change in the horizontal direction (it is the direction of positive x, scanning the image from left to right), this change is "encoded" in the grey level of the image of the horizontal component: the mean grey level means no change, the bright levels mean change from a dark value to a bright value, the dark levels mean a change from a bright value to a dark value. So, in the above image you see the brighter value in the left part of the circle because it is in the left part of the initial image that you have the black to white transition that gives you the left edge of the disk; similarly, in the above image you see the darker value in the right part of the circle because it is in the right part of the initial image that you have the white to black transition that gives you the right edge of the disk. In the above image, the inner part of the disk and the background are at a mean grey level because there is no change inside the disk and in the background.
We can make analogous observations for the vertical component, it shows how the image change in the vertical direction, i.e. scanning the image from the top to the bottom:
You can now combine the two components in order to get the magnitude of the gradient and the orientation of the gradient.
The following image is the magnitude of the gradient:
Again, in the above image the change in initial image is encoded in the gray level: here you see that white means an high change in the initial image while black means no change at all.
So, when you look at the image of the magnitude of the gradient you can say "if the image is bright it means a big change in the initial image; if it is dark it means no change or very llittle change".
The following image is the orientation of the gradient:
In the above image the orientation is again encoded as gray levels: you can think at the orientation as the angle of an arrow pointing from the the dark part of the image to the bright part of the image; the angle is referred to an xy frame where the x runs from left to right while the y runs from top to bottom. In the above image you see all the grey level from the black (zero degree) to the white (360 degree). We can encode the information with color:
in the above image the information is encode in this way:
red: the angle is between 0 and 90 degree
cyan: the angle is between 90 and 180 degree
green: the angle is between 180 and 270 degree
yellow: the angle is between 270 and 360 degree
Here it is the C++ OpenCV code for producing the above images.
Pay attention to the fact that, for the computation of the orientation, I use the function cv::phase which, as explained in the doc, gives an angle of 0 when both the vertical component and the horizontal component of the gradient are zero; that may be convenient but from a mathematical point of view is plainly wrong because when both components are zero the orientation is not defined and the only meaningful value for an orientation kept in a floating-point C++ type is a NaN.
It is plainly wrong because a 0 degree orientation, for example, is already related to an horizontal edge and it cannot be used to represent something else like a region with no edges and so a region where orientation is meaningless.
// original code by https://stackoverflow.com/users/951860/mevatron
// see https://stackoverflow.com/a/11157426/15485
// https://stackoverflow.com/users/15485/uvts-cvs added the code for saving x and y gradient component
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <vector>
using namespace cv;
using namespace std;
Mat mat2gray(const cv::Mat& src)
{
Mat dst;
normalize(src, dst, 0.0, 255.0, cv::NORM_MINMAX, CV_8U);
return dst;
}
Mat orientationMap(const cv::Mat& mag, const cv::Mat& ori, double thresh = 1.0)
{
Mat oriMap = Mat::zeros(ori.size(), CV_8UC3);
Vec3b red(0, 0, 255);
Vec3b cyan(255, 255, 0);
Vec3b green(0, 255, 0);
Vec3b yellow(0, 255, 255);
for(int i = 0; i < mag.rows*mag.cols; i++)
{
float* magPixel = reinterpret_cast<float*>(mag.data + i*sizeof(float));
if(*magPixel > thresh)
{
float* oriPixel = reinterpret_cast<float*>(ori.data + i*sizeof(float));
Vec3b* mapPixel = reinterpret_cast<Vec3b*>(oriMap.data + i*3*sizeof(char));
if(*oriPixel < 90.0)
*mapPixel = red;
else if(*oriPixel >= 90.0 && *oriPixel < 180.0)
*mapPixel = cyan;
else if(*oriPixel >= 180.0 && *oriPixel < 270.0)
*mapPixel = green;
else if(*oriPixel >= 270.0 && *oriPixel < 360.0)
*mapPixel = yellow;
}
}
return oriMap;
}
int main(int argc, char* argv[])
{
Mat image = Mat::zeros(Size(320, 240), CV_8UC1);
circle(image, Point(160, 120), 80, Scalar(255, 255, 255), -1, CV_AA);
imshow("original", image);
Mat Sx;
Sobel(image, Sx, CV_32F, 1, 0, 3);
Mat Sy;
Sobel(image, Sy, CV_32F, 0, 1, 3);
Mat mag, ori;
magnitude(Sx, Sy, mag);
phase(Sx, Sy, ori, true);
Mat oriMap = orientationMap(mag, ori, 1.0);
imshow("x", mat2gray(Sx));
imshow("y", mat2gray(Sy));
imwrite("hor.png",mat2gray(Sx));
imwrite("ver.png",mat2gray(Sy));
imshow("magnitude", mat2gray(mag));
imshow("orientation", mat2gray(ori));
imshow("orientation map", oriMap);
waitKey();
return 0;
}
The gradient of a function of two variables x, y is a vector of the partial derivatives in the x and y direction. So if your function is f(x,y), the gradient is the vector (f_x, f_y). An image is a discrete function of (x,y), so you can also talk about the gradient of an image.
The gradient of the image has two components: the x-derivative and the y-derivative. So, you can think of it as vectors (f_x, f_y) defined at each pixel. These vectors have a direction atan(f_y / fx) and a magnitude sqrt(f_x^2 + f_y^2). So, you can represent the gradient of an image either an x-derivative image and a y-derivative image, or as direction image and a magnitude image.

Image Rotate 3D in Flex, but display another image on back of this image?

i want to rotate 3D an Image called img1 in Flex. I want to rotate it around y axis 180 degree. I can do this by using 3D effect already built in Flex but i want to do a bit more different.
I want during rotating, there's another image called img2 appear on back of img1 (in default case, the image appear on the back is img1) and when rotating finish, the image will be img2.
How can i do this ?
Thank you.
If you need no perspective effect, it's quite easy to do. A rough implementation (not tested!):
// Event.ENTER_FRAME event listener
void on_enter_frame(event:Event):void
{
// m_angle is a member of the class/flex component where on_enter_frame is declared
// ANGLE_DELTA is just a constant
m_angle += ANGLE_DELTA;
// Angle clamping to the range [0, PI * 2)
m_angle %= Math.PI * 2;
if (m_angle < 0)
m_angle += Math.PI * 2;
// If we currently look at the front side...
if (m_angle < Math.PI)
{
img1.visible = true;
img2.visible = false;
img1.scaleX = Math.cos(m_angle);
}
else
{
img1.visible = false;
img2.visible = true;
// If you omit negation, the back-side image will be mirrored
img2.scaleX = -Math.cos(m_angle);
}
}
So every frame we increase the rotation angle, clamp it to the range [0, PI * 2). Then depending on the value of the rotation angle, we hide/show the pair of your images, and then perform x-scaling of the visible image.
Thank you, now i found a solution. Please check it here, it's very easy to do.
http://forums.adobe.com/thread/921258

QGraphicsItem : emulating an item origin which is not the top left corner

My application is using Qt.
I have a class which is inheriting QGraphicsPixmapItem.
When applying transformations on these items (for instance, rotations), the origin of the item (or the pivot point) is always the top left corner.
I'd like to change this origin, so that, for instance, when setting the position of the item, this would put actually change the center of the pixmap.
Or, if I'm applying a rotation, the rotation's origin would be the center of the pixmap.
I haven't found a way to do it straight out of the box with Qt, so I thougth of reimplementing itemChange() like this :
QVariant JGraphicsPixmapItem::itemChange(GraphicsItemChange Change, const QVariant& rValue)
{
switch (Change)
{
case QGraphicsItem::ItemPositionHasChanged:
// Emulate a pivot point in the center of the image
this->translate(this->boundingRect().width() / 2,
this->boundingRect().height() / 2);
break;
case QGraphicsItem::ItemTransformHasChanged:
break;
}
return QGraphicsItem::itemChange(Change, rValue);
}
I thought this would work, as Qt's doc mentions that the position of an item and its transform matrix are two different concepts.
But it is not working.
Any idea ?
You're overthinking it. QGraphicsPixmapItem already has this functionality built in. See the setOffset method.
So to set the item origin at its centre, just do setOffset( -0.5 * QPointF( width(), height() ) ); every time you set the pixmap.
The Qt-documentation about rotating:
void QGraphicsItem::rotate ( qreal angle )
Rotates the current item
transformation angle degrees clockwise
around its origin. To translate around
an arbitrary point (x, y), you need to
combine translation and rotation with
setTransform().
Example:
// Rotate an item 45 degrees around (0, 0).
item->rotate(45);
// Rotate an item 45 degrees around (x, y).
item->setTransform(QTransform().translate(x, y).rotate(45).translate(-x, -y));
You need to create a rotate function, that translate the object to the parent's (0, 0) corner do the rotation and move the object to the original location.

Resources