So I'm trying to make a hexagon using the points rsin(theta) and rcos(theta) formulas but seem to have some error in the formula. When writing it out on paper formula works but feel like I'm overlooking something....
public static void drawHexagon(double len, double xc, double yc, int angle)
{
if(angle <= -360)
angle = 0;
double rotAngX = (len*Math.cos(angle));
double rotAngY = (len*Math.sin(angle));
//System.out.println(rotAngX + " " + rotAngY + " " + Math.cos(-30));
/*double [] x = {(xc - len*(Math.sqrt(3)/2.0)), xc,
xc + len*(Math.sqrt(3)/2.0), xc + len*(Math.sqrt(3)/2.0),
xc, xc - len*(Math.sqrt(3)/2.0)};
double [] y = {yc + len/2.0, yc + len, yc + len/2.0,
yc - len/2.0, yc - len, yc - len/2.0};*/
double[] x = new double[6];
double[] y = new double[6];
int[] angles = { 150, 90, 30, 330, 270, 210 };
for(int i = 0; i < 6; i++) {
x[i] = xc + (len*Math.cos(angles[i]));
y[i] = yc + (len*Math.sin(angles[i]));
}
printPoints(x, y);
StdDraw.setPenColor(Color.CYAN);
StdDraw.filledPolygon(x,y);
StdDraw.setPenColor(Color.PINK);
StdDraw.polygon(x,y);
}
The section commented out works but I'm trying to rotate them, so in the for loop will be adding the angle parameter to angles[i]. What am I doing wrong in the for loop?
Here's the result of the code. Hexagon but not really:
The Javadoc of Math.sin says:
public static double sin​(double a)
Returns the trigonometric sine of an angle. [...]
Parameters:
a - an angle, in radians.
Your code passes the angle in degrees rather than radians.
You can either convert the angle first:
Math.sin(Math.toRadians(30))
or directly specify the angle in radians:
Math.sin(Math.PI / 6);
I am not sure what you are trying to do, but is it this?:
public static void drawHexagon(double len, double xc, double yc, int angle)
{
double[] x = new double[6];
double[] y = new double[6];
x[0] = len*Math.cos(3.14*angle/180.0);
y[0] = len*Math.sin(3.14*angle/180.0);
double cos_60;
double sin_60;
cos_60 = 1.0/2.0;
sin_60 = Math.sqrt(3.0)/2.0;
for(int i = 1; i < 6; i++) {
x[i] = xc + cos_60*x[i-1] - sin_60*y[i-1];
y[i] = yc + sin_60*x[i-1] + cos_60*y[i-1];
}
printPoints(x, y);
StdDraw.setPenColor(Color.CYAN);
StdDraw.filledPolygon(x,y);
StdDraw.setPenColor(Color.PINK);
StdDraw.polygon(x,y);
}
Related
I'm trying to perform a Log-polar transform on an image for the purpose of image registration. In other words I'm trying to achieve this:
------>
I need to code this from scratch in Java because I'll be doing this on the GPU side with OpenCL Java bindings and can't use libraries. There are multiple threads on this but none that could really help me, mostly because they're all using in-built MATLAB functions that I cannot replicate.
I've been trying the Polar Transform instead of the Log-Polar Transform for the sake of getting this to work because most info online refers to the first. So far, the best result I've had is with this bit here (pseudocode), based on this thread:
w = input.width; // Width of the input image
h = input.height; // Height of the input image
// Copy input pixels into an array
for(y=0; y<h; y++){
for(x=0; x<w; x++){
input[y*w+x] = getPixel(x, y);
}
}
// Polar transform
maxRadius = sqrt(w*w + h*h);
radiusScale = w / maxRadius;
angleScale = h / (2 * PI);
for(y=0; y<h; y++){
dy = y - h/2; // Distance from the center in the y-axis
for(x=0; x<w; x++){
dx = x - w/2; // Distance from the center in the x-axis
angle = atan2(dy, dx) % (2*PI);
radius = sqrt(dx*dx + dy*dy);
newY = radius * radiusScale;
newX = radius * thetaScale;
output[y*w+x] = input[newY*w+newX];
}
}
What I get resembles some sort of polar transformation, despite not being the result that I'm looking for:
output image
Can someone give me any pointers on this?
Thanks
EDIT:
The log-polar transform goes like .
EDIT:
Implementing #matt suggestions I now have the following code:
w = input.width; // Width of the input image
h = input.height; // Height of the input image
maxRadius = sqrt(w*w/4 + h*h/4);
radiusScale = h / maxRadius;
angleScale = w /PI/2;
offset = PI;
for(y=0; y<h; y++){
dy = y - h/2; // Distance from center in the y-axis
for(x=0; x<w; x++){
dx = x - w/2; // Distance from the center in the x-axis
angle = atan2(dy, dx);
radius = sqrt(dx*dx + dy*dy);
newY = radius * radiusScale;
newX = (angle + offset) * angleScale;
output[newY*w+newX] = input.getPixel(x, y);
}
}
Plotting the new output gives me this, which is still not what I expect to get.
One issue with this transform is that each "pixel" in the transformed space takes up a different amount of space in the x,y space. So here is how I am defining the transform.
Our new image will have the same dimensions
The Y axis will be 0 to Max Rho
The X axis will be -PI to +PI
So we start by iterating over the i,j coordinates of the output image. The resulting rho and theta are as follows.
double rho = j*maxRho / height;
double theta = i*maxTheta / width + offset;
Now we need to grab the input pixels at the respective location.
int x = (int) ( Math.exp(rho)*Math.cos(theta) + width/2);
int y = (int) ( Math.exp(rho)*Math.sin(theta) + height/2);
Now we can get the pixel value.
int pixel = input[y*width + x];
Your input variable is a bit redundante since you could just use your getPixel(x, y)
Then we just set the corresponding output value.
output[j*width + i] = pixel;
Here is a compilable example.
import javax.imageio.ImageIO;
import java.net.URL;
import java.awt.image.BufferedImage;
import java.io.File;
public class ScannerJunk{
public static void main(String[] args) throws Exception{
BufferedImage img = ImageIO.read( new URL("https://i.stack.imgur.com/MvDQT.png") );
BufferedImage out = new BufferedImage( img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB );
double w = img.getWidth();
double h = img.getHeight();
double maxRho = 0.5*Math.log( w*w/4.0 + h*h/4.0 );
double maxTheta = 2 * Math.PI;
double offset = - Math.PI;
for(int i = 0; i< w; i++){
for(int j = 0; j< h; j++){
double rho = j*maxRho / h;
double theta = i*maxTheta / w + offset;
int x = (int) ( Math.exp(rho)*Math.cos(theta) + w/2);
int y = (int) ( Math.exp(rho)*Math.sin(theta) + h/2);
try{
out.setRGB( i, j, img.getRGB( x, y ) );
} catch(Exception e){
System.out.println( i + ", " + j + " :: " + rho + ", " + theta + " :: " + x + ", " + y );
}
}
}
ImageIO.write(out, "PNG", new File("transformed.png") );
}
}
Note that the max radius, does not map to the input image for all of the possible angles.
Also, the radius and theta axis appeat to be transposed from your example image.
I want to program a linear regression with Processing. But I got mixed up which parameters I have to multiply and then add or subtract from my slope.
I have tried to change the parameters (make them negative, change the learning rate). The b does actually work, but I have got some problems to get the slope the right way.
//Data
float[] P1 = {100,100};
float[] P2 = {200,300};
float[] P3 = {300,250};
float[][] allData = {P1,P2,P3};
//random start values
float w1 = random(0,3);
float b = random(-100,100);
float learningRate = 0.01;
int i = 0;
void setup(){
size(1000,1000);
}
void draw(){
background(255);
axes();
//Draw Points
for(int j=0;j<allData.length;j+=1){
float[] point = allData[j];
advancedPoint(point[0],point[1],color(181, 16, 32),10);
}
//Gradient descend, thats the confusing part...
if(i<10000){
i += 1;
float dcost_dreg = 0;
float dcost_dtar = 0;
for(int j=0;j<allData.length;j+=1){
float[] point = allData[j];
float yTarget = point[1];
float yRegression = w1*point[0] + b;
dcost_dreg += -2*(yRegression-yTarget); //I don't understand these lines
dcost_dtar += -2*(yRegression-yTarget)*point[0];
}
w1 += learningRate * (dcost_dtar/allData.length);
b += learningRate * (dcost_dreg/allData.length) ;//until here
}
//Draw Regression
linearPoints(w1, b);
}
void linearPoints (float w1, float b){
float y;
for(float x=-width; x<width; x=x+0.25){
y = w1*x + b;
strokeWeight(3);
stroke(100,100);
point(x+width/2, -y + height/2);
}
}
void axes(){
for(float a=0; a<height; a=a+0.25){
strokeWeight(1);
stroke(255,100,0);
point(width/2,a);
}
for(float b=0; b<width; b=b+0.25){
stroke(255,100,0);
point(b,height/2);
}
}
void advancedPoint(float x,float y, color c, int size){
strokeWeight(size);
stroke(c);
point(x+width/2,-y+height/2);
}
In theory the program should fit a linear regression through my data.
The linear regression is base on the equation of a Line in the form
y = w1 * x + b
The terms
dcost_dreg += -2*(yRegression-yTarget);
dcost_dtar += -2*(yRegression-yTarget)*point[0];
should calculate the error of the line equation in compare to the sample points, but your calculation is wrong.
The constant error (b error) is the difference of the sample y coordinate and the y coordinate which is calculated by the line equation on the sample x coordinate.
The linear error (w1 error) is calculated by the gradient difference. The gradient difference is the quotient of a height and a width (y/x) rather than a product.
This means the calculation has to be:
dcost_dreg += (yTarget-yRegression);
dcost_dtar += (yTarget-yRegression)/point[0];
The expressions
w1 += learningRate * (dcost_dtar/allData.length);
b += learningRate * (dcost_dreg/allData.length);
Calculate the average error of the samples and apply the correction to the line equation by considering the learning rate.
Change the function draw to solve the issue:
void draw(){
background(255);
axes();
//Draw Points
for(int j=0;j<allData.length;j+=1){
float[] point = allData[j];
advancedPoint(point[0],point[1],color(181, 16, 32),10);
}
//Gradient descend, thats the confusing part...
if(i<10000){
i += 1;
float dcost_dreg = 0;
float dcost_dtar = 0;
for(int j=0;j<allData.length;j+=1){
float[] point = allData[j];
float yTarget = point[1];
float yRegression = w1*point[0] + b;
dcost_dreg += (yTarget-yRegression);
dcost_dtar += (yTarget-yRegression)/point[0];
}
w1 += learningRate * (dcost_dtar/allData.length);
b += learningRate * (dcost_dreg/allData.length);
}
//Draw Regression
linearPoints(w1, b);
}
By the way, recommend to use line() for drawing the axis and the current line equation:
void linearPoints (float w1, float b){
strokeWeight(3);
stroke(100,100,255);
float x0 = -width;
float x1 = width;
float y0 = x0 * w1 + b;
float y1 = x1 * w1 + b;
line(x0+width/2, -y0+height/2, x1+width/2, -y1+height/2);
}
void axes(){
strokeWeight(1);
stroke(255,100,0);
line(0,height/2, width, height/2);
line(width/2, 0, width/2, height);
}
I'm getting unexpected results when multiplying two quaternions and applying the resulting rotation to my local right-handed coordinate system. (X pointing forward, Y to the right and Z downward).
(See my Java SCCE below)
So I am trying to first apply a Z rotation by 90 degrees (yaw) and then a rotation of 90 degrees around the local X axis (roll).
I am trying to accomplish this by multiplying two quaternions representing these two rotations, creating a rotation Matrix from the result and applying it to the 3 unit vectors of my coordinate system but the results I am getting do not make sense. (i.e. they do not represent the coordinate system you should get from these two rotations.)
I have tried changing the quaternion multiplication order which did not help (see code lines that were commented out in the main method of the SCCE).
I have also tried creating the quaternion for the second rotation from global Y to simulate that it was created from the resulting local coordinate system after the first rotation.
For reference I am also calculating the result by applying the two individual rotation matrices (which works as expected).
What am I doing wrong?
import java.text.DecimalFormat;
import java.text.NumberFormat;
public class Quaternion {
public static final double NORMALIZATION_LOWER_TOLERANCE = 1 - 1e-4;
public static final double NORMALIZATION_UPPER_TOLERANCE = 1 + 1e-4;
private double w = 1.0;
private double x = 0.0;
private double y = 0.0;
private double z = 0.0;
public static void main(String[] args) {
Vector3D xVect = new Vector3D(1,0,0);
Vector3D yVect = new Vector3D(0,1,0);
Vector3D zVect = new Vector3D(0,0,1);
System.out.println("Initial Local Coordinate System: X:"+xVect+" / Y:"+yVect+ " / Z:"+zVect);
Quaternion rotZ = new Quaternion(Math.PI/2, zVect); // Yaw +90 deg
Quaternion rotY = new Quaternion(Math.PI/2, yVect); // Yaw +90 deg
Quaternion rotX = new Quaternion(Math.PI/2, xVect); // Then roll +90 deg
Matrix rotationMatrixZ = new Matrix(rotZ);
Vector3D localX = xVect.rotate(rotationMatrixZ);
Vector3D localY = yVect.rotate(rotationMatrixZ);
Vector3D localZ = zVect.rotate(rotationMatrixZ);
System.out.println("New Local Coordinate System after Yaw: X:"+localX+" / Y:"+localY+ " / Z:"+localZ); // Gives expected result
Quaternion localRotX = new Quaternion(Math.PI/2, localX);
Matrix localRotXMatrix = new Matrix(localRotX);
Vector3D rotatedX = localX.rotate(localRotXMatrix);
Vector3D rotatedY = localY.rotate(localRotXMatrix);
Vector3D rotatedZ = localZ.rotate(localRotXMatrix);
System.out.println("New Local Coordinate System two local rotations: X:"+rotatedX+" / Y:"+rotatedY+ " / Z:"+rotatedZ); // Gives expected result
Quaternion rotZX = rotZ.multiply(rotX);
// Quaternion rotZX = rotX.multiply(rotZ); // Tried both orders
// Quaternion rotZX = rotZ.multiply(rotY); // rotY is in fact the local rotX
// Quaternion rotZX = rotZ.multiply(rotY); // rotY is in fact the local rotX, tried both orders
rotZX.normalizeIfNeeded();
Matrix rotationXMatrixZX = new Matrix(rotZX);
rotatedX = xVect.rotate(rotationXMatrixZX);
rotatedY = localY.rotate(rotationXMatrixZX);
rotatedZ = localZ.rotate(rotationXMatrixZX);
System.out.println("New Local Coordinate System Quaternion Multiplication: X:"+rotatedX+" / Y:"+rotatedY+ " / Z:"+rotatedZ); // Expect same as above
}
public Quaternion() {
}
public Quaternion(double w, double x, double y, double z) {
this.w = w;
this.x = x;
this.y = y;
this.z = z;
}
public Quaternion(double angle, Vector3D vector){
double halfAngle = angle / 2;
double sin = Math.sin(halfAngle);
this.w = Math.cos(halfAngle);
this.x = vector.getX()*sin;
this.y = vector.getY()*sin;
this.z = vector.getZ()*sin;
}
public boolean normalizeIfNeeded() {
double sum = w * w + x * x + y * y + z * z;
if (NORMALIZATION_LOWER_TOLERANCE < sum && sum < NORMALIZATION_UPPER_TOLERANCE) {
return false;
}
double magnitude = Math.sqrt(sum);
w /= magnitude;
x /= magnitude;
y /= magnitude;
z /= magnitude;
return true;
}
public Quaternion multiply(Quaternion q2) {
Quaternion result = new Quaternion();
result.w = w * q2.w - x * q2.x - y * q2.y - z * q2.z;
result.x = w * q2.x + x * q2.w + y * q2.z - z * q2.y;
result.y = w * q2.y - x * q2.z + y * q2.w + z * q2.x;
result.z = w * q2.z + x * q2.y - y * q2.x + z * q2.w;
return result;
}
public Quaternion conjugate() {
return new Quaternion(w, -x, -y, -z);
}
public double getW() {
return w;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
#Override
public String toString() {
return "Quaternion [w=" + w + ", x=" + x + ", y=" + y + ", z=" + z + "]";
}
static class Vector3D {
double x=0;
double y=0;
double z=0;
public Vector3D(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public Vector3D rotate(Matrix rotationMatrix){
return rotationMatrix.multiply(this);
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
#Override
public String toString() {
NumberFormat df = DecimalFormat.getNumberInstance();
return "[x=" + df.format(x) + ", y=" + df.format(y) + ", z=" + df.format(z) + "]";
}
}
static class Matrix {
private double[][] values;
public Matrix(int rowCount, int colCount) {
values = new double[rowCount][colCount];
}
public Matrix(Quaternion quaternionForRotationMatrix) {
this(3,3);
double w = quaternionForRotationMatrix.getW();
double x = quaternionForRotationMatrix.getX();
double y = quaternionForRotationMatrix.getY();
double z = quaternionForRotationMatrix.getZ();
double ww = w*w;
double wx = w*x;
double xx = x*x;
double xy = x*y;
double xz = x*z;
double wy = w*y;
double yy = y*y;
double yz = y*z;
double wz = w*z;
double zz = z*z;
values[0][0] = ww + xx - yy - zz;
values[0][1] = 2 * xy - 2 * wz;
values[0][2] = 2 * xz + 2 * wy;
values[1][0] = 2 * xy + 2 * wz;
values[1][1] = ww - xx + yy - zz;
values[1][2] = 2 * yz + 2 * wx;
values[2][0] = 2 * xz - 2 * wy;
values[2][1] = 2 * yz - 2 * wx;
values[2][2] = ww - xx - yy + zz;
}
public Vector3D multiply(Vector3D vector){
double [][] vect = new double [3][1];
vect[0][0] = vector.getX();
vect[1][0] = vector.getY();
vect[2][0] = vector.getZ();
double [][] result = multiplyMatrices(values, vect);
return new Vector3D(result[0][0], result[1][0], result[2][0]);
}
private double[][] multiplyMatrices(double[][] m1, double[][] m2) {
double[][] result = null;
if (m1[0].length == m2.length) {
int rowCount1 = m1.length;
int colCount1 = m1[0].length;
int rowCount2 = m2[0].length;
result = new double[rowCount1][rowCount2];
for (int i = 0; i < rowCount1; i++) {
for (int j = 0; j < rowCount2; j++) {
result[i][j] = 0;
for (int k = 0; k < colCount1; k++) {
result[i][j] += m1[i][k] * m2[k][j];
}
}
}
} else {
int rowCount = m1.length;
int colCount = m1[0].length;
result = new double[rowCount][colCount];
for (int i = 0; i < m1.length; i++) {
for (int j = 0; j < m1[0].length; j++) {
result[i][j] = 0;
}
}
}
return result;
}
#Override
public String toString() {
StringBuffer sb = new StringBuffer("Matrix = ");
for(int row = 0 ; row<values.length; row++){
sb.append ("[ ");
for(int col = 0 ; col<values[0].length; col++){
sb.append(Double.toString(values[row][col]));
if(col<values.length-1){
sb.append(" | ");
}
}
sb.append("] ");
}
return sb.toString();
}
}
}
Nevermind. Found it. I had an error in the formulas to build the rotation matrix. It now works as expected.
I am making a mental note to use formulas from Wikipedia in the future and not some random other site.
The respective part should be
values[0][0] = ww + xx - yy - zz;
values[0][1] = 2 * xy - 2 * wz;
values[0][2] = 2 * xz + 2 * wy;
values[1][0] = 2 * xy + 2 * wz;
values[1][1] = ww - xx + yy - zz;
values[1][2] = 2 * yz - 2 * wx; //CORRECTED SIGN
values[2][0] = 2 * xz - 2 * wy;
values[2][1] = 2 * yz + 2 * wx; //CORRECTED SIGN
values[2][2] = ww - xx - yy + zz;
At the end of the main method I was also using the wrong vectors for y and z:
Matrix rotationXMatrixZX = new Matrix(rotZX);
rotatedX = xVect.rotate(rotationXMatrixZX);
rotatedY = yVect.rotate(rotationXMatrixZX); // Corrected used y-vector
rotatedZ = zVect.rotate(rotationXMatrixZX); // Corrected used z-vector
I am calculating distance of point from a line. But I am getting wrong distance. Following is my piece of code which is gettting distance from line.
float px,py,something,u;
px=x2-x1;
py=y2-y1;
something = px*px + py*py;
u = ((x - x1) * px + (y - y1) * py) /(something);
if( u > 1)
{
u = 1;
// MinDist=0;
}
else if (u < 0)
{
u = 0;
//MinDist=0;
}
float xx = x1 + u * px;
float yy = y1 + u * py;
float dx = xx - x;
float dy = yy - y;
float dist= (float)Math.sqrt((double)dx*dx +(double) dy*dy);
Dist is giving wrong answer.
From: http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Vector_formulation
distance(x=a+tn, p) = ||(a-p)-((a-p).n)n||
Where:
a = (x1, y1) //First point on line
n = |(x2-x1, y2-y1)| //Normalised direction vector
p = (x, y) //Query point
So, not going to do it all, but make functions and give meaningful names to help you follow the formular:
float[] a = new float[]{x1, y1};
float[] n = new float[]{x2-x1, y2-y1};
normalize(n);
float[] p = new float[]{x, y};
float[] aMinusP = subtract(a, p);
float aMinusPDotn = dot(aMinusP, n);
// vec2a.vec2b
float dot(float[] vec2a, float[] vec2b)
{
return vec2a[0]*vec2b[0] + vec2a[1]*vec2b[1];
}
// ||vec2||
float len(float[] vec2)
{
return (float)Math.Sqrt(dot(vec2, vec2));
}
// vec2/||vec2||
void normalize(float[] vec2)
{
float length = len(vec2);
vec2[0] /= length;
vec2[1] /= length;
}
// vec2a - vec2b
float[] subtract(float[] vec2a, float[] vec2b)
{
return new float[]{vec2a[0]-vec2b[0],vec2a[1]-vec2b[1]};
}
I am calculating Geometric median of some (x,y) points in java. To calculate Geometric median, first i am calculating centroid of all the points, then this centroid is used to calculate Geometric median. My code works fine, but sometimes it goes to an infinite loop (i think.). The problem is with my while condition. This while condition should be change according to input points, but i don't know how. Below I am putting the complete code.
import java.util.ArrayList;
public class GeometricMedian {
private static ArrayList<Point> points = new ArrayList<Point>();
private class Point {
private double x;
private double y;
Point(double a, double b) {
x = a;
y = b;
}
}
public static void main(String[] args) {
GeometricMedian gm = new GeometricMedian();
gm.addPoints();
Point centroid = gm.getCentroid();
Point geoMedian = gm.getGeoMedian(centroid);
System.out.println("GeometricMedian= {" + (float) geoMedian.x + ", "
+ (float) geoMedian.y + "}");
}
public void addPoints() {
points.add(new Point(0, 1));
points.add(new Point(2, 5));
points.add(new Point(3, 1));
points.add(new Point(4, 0));
}
public Point getCentroid() {
double cx = 0.0D;
double cy = 0.0D;
for (int i = 0; i < points.size(); i++) {
Point pt = points.get(i);
cx += pt.x;
cy += pt.y;
}
return new Point(cx / points.size(), cy / points.size());
}
public Point getGeoMedian(Point start) {
double cx = 0;
double cy = 0;
double centroidx = start.x;
double centroidy = start.y;
do {
double totalWeight = 0;
for (int i = 0; i < points.size(); i++) {
Point pt = points.get(i);
double weight = 1 / distance(pt.x, pt.y, centroidx, centroidy);
cx += pt.x * weight;
cy += pt.y * weight;
totalWeight += weight;
}
cx /= totalWeight;
cy /= totalWeight;
} while (Math.abs(cx - centroidx) > 0.5
|| Math.abs(cy - centroidy) > 0.5);// Probably this condition
// needs to change
return new Point(cx, cy);
}
private static double distance(double x1, double y1, double x2, double y2) {
x1 -= x2;
y1 -= y2;
return Math.sqrt(x1 * x1 + y1 * y1);
}
}
Please help me to fix the bug, also if there exitis any better way to calculate Geometric median of some 2D points, write here. Thank you.
I don't see why you need two loops. You only need the loop over all the points. What is the reason for the other one, in your view?
One way to solve this is to iterate certain number of times. This similar to K-Means method where it either converges to a specific threshold or stops after a predefined number of iterations.