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.
Related
I am trying to make a game where the player can only see in a small radius around them. i'm attempting to do this by covering a 500X500 display with 1X1 black pixels that i can set active or inactive. The problem is that using a standered for loop to add them takes a large amount of time when the program launches and it slows the entire thing down. Any Solutions?
the pix object takes two paramaters(int x, int y)
code
public ArrayList<Pix> pixs= new ArrayList<>();
for(int i = 0; i<=500; i++)
{
for(int ii = 0; ii<=500; ii++)
{
pixs.add(new Pix(ii,i));
}
}
You are constructing 250000 instances of your Pix class. That will take some time.
Consider having a 2 dimensional array of booleans instead. Where false means the pixel is black.
You don't need to initialize the values yourself as they will default to false.
boolean[][] pixs = new boolean[500][500];
You can iterate over the structure with this:
for (int x = 0; x < 500; x++) {
for (int y = 0; y < 500; y++) {
System.out.println(pixs[x][y]);
}
}
And you can set a particular pix with
int x = 232;
int y = 455;
pixs[x][y] = true;
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.
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 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.
I essentially have a bunch of data objects which map timestamps in milliseconds to float values. I'm looking to essentially find the peak/max of the data in a given range. I've been essentially using something like this:
float previousValue = 0;
for (int i = 0; i < data.size(); i++) {
MyData value = data.get(i);
if (value.getData() < previousValue) {
// found the peak!
break;
} else {
previousValue = value.getData();
}
}
The only problem with this algorithm is that it doesn't account for noise. Essentially, I could have values like this:
[0.1025, 0.3000, 0.3025, 0.3500, 0.3475, 0.3525, 0.1025]
The actual peak is at 0.3525, but my algorithm above would see it as 0.3500, as it comes first. Due to the nature of my calculations, I can't just do max() on the array and find out the largest value, I need to find the largest value that comes first before it falls.
How can I find the top of my peak, while accounting for some variance in noise?
There are two issues:
filtering out the noise;
finding the peak.
It seems like you already have a solution for 2, and need to solve 1.
To filter out the noise, you need some kind of low-pass filter. A moving average is one such filter. For example, exponential moving average is very easy to implement and should work well.
In summary: put your series through the filter, and then apply the peak finding algorithm.
an easier method to find a single peak (or the highest value) in an array (any numeric array: int, double) is to loop through the array and set a variable to the highest value...
Example: (all examples use a float array called "data")
float highest = 0; //use a number equal to or below the lowest possible value
for (int i = 0; i < data.length; i++){
if (data[i] > highest){
highest = data[i];
}
}
to find multiple peaks in noisy data filtering some of the noise out I used this method:
boolean[] isPeak = new boolean[20]; // I am looking for 20 highest peaks
float[] filter = new float[9]; // the range to which I want to define a peak is 9
float[] peaks = new float[20]; // again the 20 peaks I want to find
float lowpeak = 100; // use a value higher than the highest possible value
// first we start the filter cycling through the data
for (int i = 0; i < data.length; i++){
for (int a = filter.length-1; a > 0; a--){
filter[a] = filter[a-1];
}
filter[0] = data[1]
// now we check to see if the filter detects a peak
if (filter[4]>filter[0] && filter[4]>filter[1] && filter[4]>filter[2] &&
filter[4]>filter[3] && filter[4]>filter[5] && filter[4]>filter[6] &&
filter[4]>filter[7] && filter[4]>filter[8]){
// now we find the lowest peak
for (int x = 0; x < peaks.lengt-1; x++){
if (peaks[x] < lowpeak){
lowpeak = peaks[x];
}
}
// now we check to see if the peak is above the lowest peak
for (int x = 0; x < peaks.length; x++){
if (peaks[x] > lowpeak && peaks[x] != peaks[x+1]){
for (int y = peaks.length-1; y > 0 && !isPeak[y]; y--){
peaks[y] = peaks[y-1];
}
peaks[0] = filter[4];
}
}
}
}
this may not be the most efficient way to do this but it gets the job done!