Given a 2D array, I am required to come up with an algorithm which outputs the center of mass. I came up with algorithm below, however, it is producing incorrect solution when the array size is increased to 10 x 10 matrix. I wrote and ran the algorithm using java. I have not provided the codes here, but just an explanation of my algorithm as i feel that it is not right. However, I am unable to find out why.
Store into an array: Mean of each row
Store into an array: Mean of each column
The algo below is used for row and column:
Loop through the row array,
if(row = 1){
value = (mean of row 1) - (mean of row 2 + mean of row 3+ mean of row 4)
}else if(row =Length of array){
value = (mean of row 1 + mean of row 2 + mean of row 3) - (mean of row 4)}
else{
value = (mean of rows until ith row) - (ith row till end of array)
}
final value = lowest value;
I know that it is supposed to deal with mean of the rows and columns. So in my algorithm, i find out the means of rows and columns and then conduct the calculation shown above. The same algo applies to the columns.
Any and all help is appreciated. Maybe, my understanding of center of mass is incorrect. If something is not clear, then do ask. This is my own algorithm, created from my understanding of center of mass, so if its not clear, please do ask. Thank you!
Expanding on my comment, you should be able calculate the center of mass as follows:
foreach col
foreach row
massvector.x += matrix[col][row] * col
massvector.y += matrix[col][row] * row
totalmass += matrix[col][row]
massvector.x /= totalmass
massvector.y /= totalmass
The idea is based on the section "A system of particles" in https://en.wikipedia.org/wiki/Center_of_mass: treat the matrix elements as equally spaced particles laid out on a 2D plane. The position of each element is equal to its position within the matrix, i.e. column and row, while the particle mass is the value of that cell/element/matrix position.
Example-Implementation using your (now deleted) test case:
double[][] matrix = new double[][]{
{0.70,0.75,0.70,0.75,0.80},
{0.55,0.30,0.20,0.10,0.70},
{0.80,0.10,0.00,0.00,0.80},
{0.70,0.00,0.00,0.00,0.80},
{0.80,0.90,0.80,0.75,0.90}};
double cx = 0;
double cy = 0;
double m = 0;
for(int x = 0; x < matrix.length; x++ ) {
for(int y = 0; y < matrix[x].length; y++) {
cx += matrix[x][y] * x;
cy += matrix[x][y] * y;
m += matrix[x][y];
}
}
//those are center's the cell coordinates within the matrix
int cmx = (int)(cx/m);
int cmy = (int)(cy/m);
//whatever you'd need that value for (the position is more likely what you're after)
double centerOfMassValue = matrix[cmx][cmy];
The example above would return coordinates 2/2 with is the center of the 5x5 matrix.
You need to do a weighted average so for an 3x3 array,
x̄= (mass(col1)*1 + mass(col2)*2 + mass(col3)*3) / (mass(col1) + mass(col2) + mass(col3))
and similarly for y replacing columns with rows.
Once you have those two values, the pair of them will tell you the x and y coordinates of the center of mass for your array.
See example one in the following link if you need a visual example: http://www.batesville.k12.in.us/physics/APPhyNet/Dynamics/Center%20of%20Mass/2D_1.html
I assume that since you are storing the weights in a matrix, that the position in the matrix will correspond with the coordinates of the weight where the column index is x row index is y. Thus a weight at row=2,col=3 we will take to be (3,2) on the x/y coordinate system.
This code follows the solution for center of mass from a system of particles on Wikipedia:
public static Point2D.Double getCenterOfMass( double[][] matrix) {
double massTotal = 0;
double xTotal = 0;
double yTotal = 0;
for (int rowIndex = 0; rowIndex < matrix.length; rowIndex++) {
for (int colIndex = 0; colIndex < matrix[0].length; colIndex++) {
massTotal += matrix[rowIndex][colIndex];
xTotal += matrix[rowIndex][colIndex] * colIndex;
yTotal += matrix[rowIndex][colIndex] * rowIndex;
}
}
xTotal /= massTotal;
yTotal /= massTotal;
return new Point2D.Double(xTotal,yTotal);
}
Full working code here.
Related
I want to multiply 2 diagonals of a Matrix. But i am not able to get the diagonals of matrix. like in given code two diagonals are d1=5*5*9. and d2=3*5*7 then i will use d1 and d2 values for further process.
How to do it.
Note: matrix size can be different like here its 3x3 but it can be 5x5
private static int diagonalMultiply(int [][]arr1){
int[][] arr= {
{5,2,3},
{4,5,6},
{7,8,9}
};
for ( int x = 0; x < arr.length; x++) //stepping along the x axis again.
{
for ( int y = 0; y < arr[x].length; y++) // stepping along the y axis.
{
System.out.print(arr[x][y]+" ");
}
}
return 0;
}
A diagonal of an N×N matrix has N elements. A pair of nested loops, each going from 0 to N-1, cover N2 elements. This means that you need one loop, not two.
Both diagonals can be retrieved in a single loop. Indexes of the descending diagonal are (i, i), while indexes of the ascending one are (N-i-1, i):
int N = arr.length;
for ( int i = 0; i < N ; i++) {
System.out.println(arr[i][i]+" "+arr[N-i-1][i]);
}
Demo.
I've created a grid of objects called Cell. Each cell has following properties:
x coordinate
y coordinate
width
height
The width of a cell is equal to it's height. Every cell has got the same width/height.
There are 9*9 cells, one beside another, created by this algorithm:
cells = new Cell[9][0];
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
cells[i][j] = new Cell(i*cellWidth, j*cellHeight);
}
}
The cell's constructor asks for the x and y coordinates. Now we got a grid of Cells.
When I touch the screen, I know the x and y coordinates where I touched the screen. This cell I touched should run a method called isTouched.
How can I find out which cell I've touched?
I've tried this algorithm:
public boolean isTouched(int zx, int zy) {
if((zx >= x && zx <= x+cellSize) && (zy >= y && zy <= y+cellSize)) {
return true;
}else {
return false;
}
}
zx and zy are the touched coordinates. It checks whether the touched x axis is bigger or equal the cell's own x coordinate and if it's smaller than the cell's x coordinate + the cell's width. Same thing with the y coordinate.
It won't work as when I tap on a cell of the first row, the first element in the first row gets selected. When tapping on an element in the fifth row, the fifth element in the fifth row gets selected although I've pressed on another cell.
Here's a screenshot
I can't find my mistake, any suggestions? Thanks in advance
It would be more efficient and easier to compute the cell which contains the touch point.
Cell touchedCell(int x, int y) {
i = x / cellWidth;
j = y / cellHeight;
if (i >= 9 || j >= 9 || i < 0 || j < 0)
return null;
else
return cell[i][j];
}
The array size is also off:
cells = new Cell[9][0];
This is whats causing the strange effect as there are only 9 cells in the array, since j will be multiplied by 0 when indexing cell[i][j] == cell[i][0] no matter what j.
should be
cells = new Cell[9][9];
I have a 36x25 grid of nodes that I wish to search through all triangular numbers from the corner opposite of the hypotenuse. Here's psuedocode for what I was considering, but this method only works until it hits the next corner of the grid, and I'm sure there is a much simpler way to do this recursively, I just am having difficulty figuring it out.
for(int iteration; iteration < maxDistance(49); iteration++)
{
int xAdd = iteration;
int yAdd = 0;
while(xAdd != 0)
{
checkStuff(nodeGrid[x+xAdd][y+yAdd]);
xAdd--;
yAdd++;
}
}
What I want program to do:
[0][1][2][3][4][5]
[1][2][3][4][5][6]
[2][3][4][5][6][7]
[3][4][5][6][7][8]
[4][5][6][7][8][9]
check in this order. So first check all tiles with value 0, then 1 and so on.
Note: in this case my function will only work up until the 4th set up tiles. Any further and it will reach out of bounds.
/**
* Only works for rectangular arrays
*/
public void iterateOver(Node[][] a){
int x_dim = a[0].length;
int y_dim = a.length;
for (int i = 0; i < x_dim + y_dim - 1; i++){
int x, y;
if (i < x_dim){
x = i;
y = 0;
}
else{
x = x_dim - 1;
y = i - x_dim + 1;
}
for (;x >=0 && y < y_dim; y++, x--){
doStuff(a[y][x]);
}
}
}
How it works
Picture your rectangular array:
[0][1][2][3][4][5]
[1][2][3][4][5][6]
[2][3][4][5][6][7]
[3][4][5][6][7][8]
[4][5][6][7][8][9]
There are clearly 6 columns and 5 rows (or 6 x values and 5 y values). That means that we need to do 6 + 5 - 1 iterations, or 10. Thus, the for (int i = 0; i < x_dim + y_dim - 1; i++). (i is the current iteration, measured from 0).
We start by columns. When i is less than the x dimension, x = i and y = 0 to start with. x is decremented and y is incremented until x is less than zero or y is equal to the y dimension. Then, we do a similar thing down the right hand side.
I'm working on a project in which I'm trying to use histogram equalization to do something like going from this image
http://zerocool.is-a-geek.net/wp-content/uploads/2011/12/input-300x200.jpg
"http://zerocool.is-a-geek.net/wp-content/uploads/2011/12/hist_before.png"
to this image
http://zerocool.is-a-geek.net/wp-content/uploads/2011/12/output-300x200.jpg
"http://zerocool.is-a-geek.net/wp-content/uploads/2011/12/hist_after.png"
but I can't seem to figure it out.
This is my enhanced image code which should implement the same type of adjustment..
public void EnhancedImage (File fileName) {
double sumc = 0;
for(int r = 0; r < array.length; r++){
for(int c = 0; c < array[r].length; c++){
sumc = r+c;
if (sumc <= array[r][c]) {
sumc = array[r][c];
}
newc = Math.round(maxshade * ((double)sumc / pixtot));
array[r][c] = (int) (newc);
if (array[r][c] > 255) {
array[r][c] = 255;
}
}
}
The algorithm that i would like to use is below where maxShade is the maximum shade of the image (usually 255) sumc is the total number of pixels in the image with a value less than or equal to c and pixtot is the total number of pixels in the picture:
newc := round(maxShade * ((double)sumc / pixtot))
but im not sure if i did it right...currently my image just turns really dark.
Any help would be appreciated!! Thanks.
Also my pixtot routine:
pixtot = 0;
for(int y = 0; y < imageArray.length; y++)
for(int x = 0; x < imageArray[0].length; x++)
pixtot = x+y;
Your problem is here:
pixtot = x+y;
First, you want +=, not =. Second, this is adding up the indexes of the pixels, not the value of the pixels. You want something like
pixtot += imageArray[y][x];
You make the same conceptual error with sumc.
Edit:
There's lots of other problems with your code. If you want to stretch the dynamic range, you want to compute min and max, the minimum and maximum of all the pixel values, then compute each pixel value as value = maxshade * (value - min) / (max - min). That gives you a result pixel value of 0 if value==min and maxshade if value==max.
This doesn't really give you histogram equalization, however. For that you need to compute a histogram of the input pixel values and compute quantiles in that histogram to figure out the output values, it isn't easy.
I am using a perlin noise function to generate data for a game I am making, but for some reason it keeps returning the exact same results for different inputs. I spent like 4 hours trying to debug this on my FBM function and couldn't figure it out so I tried Ken Perlin's improved noise function and the same thing happens.
Does anyone know why this is? What is a good way to fix it? The only thing I have been able to do is add a decimal value like .6473 to the x and y coordinates, which helped, but introduced other problems such as the values repeating themselves inside the arrays.
Here is some test code. I am trying to create two different 2D arrays filled with noise values. The x and y inputs are coordinates from my game. On the lines with '**' after them, if I don't increase those values, both arrays will be filled with all zeros. In the example, the coordinates (0.0, -768.0) and (-1024.0, -768.0) return the exact same noise values. In my game, 9 different coordinates return the same values.
The Perlin Noise function I am using for this test is here
public class TestPerlinMain
{
public static void main(String[] args)
{
int seed = 532434;
//create first noise array
double x = 0.0; //x-coordinate
double y = -768.0; //y-coordinate
float z = 10.0f;
double[][] test = new double[15][15];
System.out.println("Noise Array 1: ");
for(int i = 0; i < test.length; i++)
{
for(int j = 0; j < test[i].length; j++)
{
test[i][j] = ImprovedNoise.noise(x + (j * 64.0), y + (i * 64.0), 10.0);
x += .314f;//************
System.out.print(test[i][j] + " ");
}
y += .314f;//***********
}
System.out.println();
//create 2nd noise array
double x2 = -1024.0; //x coordinate
double y2 = -768.0; //y coordinate
float z2 = 10.0f;
System.out.println();
double[][] test2 = new double[15][15];
System.out.println("Noise Array 2: ");
for(int i = 0; i < test2.length; i++)
{
for(int j = 0; j < test2[i].length; j++)
{
test2[i][j] = ImprovedNoise.noise(x2 + (j * 64.0), y2 + (i * 64.0), 10.0);
x2 += .314f;//*************
System.out.print(test2[i][j] + " ");
}
y2 += .314f;//************
}
System.out.println();
}
Perlin noise is defined to be 0 at all grid locations (integer x, y, z). You can prove this to yourself by hand-simulating it in the code you linked. Since x, y, and z all become 0 when their floors are subtracted, the grad() values are all 0, so the lerp() values are all 0.
There are several ways to get the noise you want. First, if you use a non-integer value of z, then you should get random values of noise. However, since your grid spacing of 64 is much larger than the noise basis, this will look like static, not Perlin noise. A better approach would be to scale up the noise by doing something like noise(j/4., i/4., z). Sampling 4 points across each noise cell will allow some of the smoothness of the noise to be seen.
Note also that your noise implementation is designed to repeat with tiles of size 256 in each direction (see the first line of noise(). This is why you get repeating values every 4 in your array.