I have calculated the histograms of two images in Java (Code modified and shortened):
for (int posX = 0; posX < image.getWidth(); posX++)
{
for (int posY = 0; posY < image.getHeight(); posY++)
{
Color c1 = new Color(image.getRGB(posX, posY));
cummulative[0] = cummulative[0] + c1.getRed();
cummulative[1] = cummulative[1] + c1.getGreen();
cummulative[2] = cummulative[2] + c1.getBlue();
numPixels++;
}
}
r1 = cummulative[0] / numPixels;
g1 = cummulative[1] / numPixels;
b1 = cummulative[2] / numPixels;
and then calculated the Euclidean Distance of the histograms:
tempDist = Math.sqrt((r1 - r2) * (r1 - r2) + (g1 - g2) * (g1 - g2) + (b1 - b2) * (b1 - b2));
Now I want to calculate the Chi-Squared Distance distance instead the Euclidean Distance. But I have no idea how to implement that. Please can someone give an introduction for that?
Edit:
I have now the following code to generate the histogram:
float[] histogram = new float[256];
for (int i = 0; i < input.getWidth(); i++) {
for (int j = 0; j < input.getHeight(); j++) {
int color = 0;
switch (colorVal) {
case 1:
color = new Color(input.getRGB(i, j)).getRed();
break;
case 2:
color = new Color(input.getRGB(i, j)).getGreen();
break;
case 3:
color = new Color(input.getRGB(i, j)).getBlue();
break;
}
histogram[color]++;
}
}
How can I continue supposed I have the following Data:
Image 1:
R 10 count 1000
R 20 count 100
R 30 count 100
G 20 count 600
G 255 count 600
B 0 count 800
B 200 count 400
Image 2:
R 10 count 1000
R 20 count 200
G 20 count 600
G 255 count 600
B 0 count 800
B 100 count 200
B 200 count 200
you have just summed up the r,g,b values, and not computed a histogram. First, compute the histogram correctly, then Chi squared distance can be computed as d(x,y) = sum( (xi-yi)^2 / (xi+yi) ) / 2, where x and y are your histograms, and i is the bin index of the histogram
Related
I am working on a 2D platformer game. There are star objects in the background and these stars move around. I wanted to draw lines between them and I've managed to do this without much effort. What I am now trying to do is to add an alpha value(transparency) to the lines being drawn.
I have tried to write an equation where alpha value is inversely proportional to the value of distance between two objects but have not succeeded.
How do I mathematically express the following rule ?
The larger the distance is, the lesser value of alpha gets
For example, if the distance is 400 then the transparency value should be 0 (java.awt.Color uses 0 as 100% transparency and 255 as no transparency)
here is an example of what I am trying to achieve:
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var stars = [], // Array that contains the stars
FPS = 60, // Frames per second
x = 40, // Number of stars
mouse = {
x: 0,
y: 0
}; // mouse location
// Push stars to the array
for (var i = 0; i < x; i++) {
stars.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
radius: Math.random() * 1 + 1,
vx: Math.floor(Math.random() * 50) - 25,
vy: Math.floor(Math.random() * 50) - 25
});
}
// Draw the scene
function draw() {
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.globalCompositeOperation = "lighter";
for (var i = 0, x = stars.length; i < x; i++) {
var s = stars[i];
ctx.fillStyle = "#fff";
ctx.beginPath();
ctx.arc(s.x, s.y, s.radius, 0, 2 * Math.PI);
ctx.fill();
ctx.fillStyle = 'black';
ctx.stroke();
}
ctx.beginPath();
for (var i = 0, x = stars.length; i < x; i++) {
var starI = stars[i];
ctx.moveTo(starI.x,starI.y);
if(distance(mouse, starI) < 150) ctx.lineTo(mouse.x, mouse.y);
for (var j = 0, x = stars.length; j < x; j++) {
var starII = stars[j];
if(distance(starI, starII) < 150) {
//ctx.globalAlpha = (1 / 150 * distance(starI, starII).toFixed(1));
ctx.lineTo(starII.x,starII.y);
}
}
}
ctx.lineWidth = 0.05;
ctx.strokeStyle = 'white';
ctx.stroke();
}
function distance( point1, point2 ){
var xs = 0;
var ys = 0;
xs = point2.x - point1.x;
xs = xs * xs;
ys = point2.y - point1.y;
ys = ys * ys;
return Math.sqrt( xs + ys );
}
// Update star locations
function update() {
for (var i = 0, x = stars.length; i < x; i++) {
var s = stars[i];
s.x += s.vx / FPS;
s.y += s.vy / FPS;
if (s.x < 0 || s.x > canvas.width) s.vx = -s.vx;
if (s.y < 0 || s.y > canvas.height) s.vy = -s.vy;
}
}
canvas.addEventListener('mousemove', function(e){
mouse.x = e.clientX;
mouse.y = e.clientY;
});
// Update and draw
function tick() {
draw();
update();
requestAnimationFrame(tick);
}
tick();
canvas {
background: #232323;
}
<canvas id="canvas"></canvas>
You should use:
((MAX_DISTANCE - distance) / MAX_DISTANCE) * 255
Explanation:
(MAX_DISTANCE - distance) makes sure that the larger the distance, the smaller the result.
Then, diving by MAX_DISTANCE and multiplying by 255, scales it from 0-MAX_DISTANCE to 0-255.
Why are those pixel rgb values sometimes equal and sometimes not equal? I am learning image processing. It would be great if someone help me out here.
public class ColorTest1 {
Color p1;
Color p2;
ColorTest1() throws IOException, InterruptedException {
BufferedImage bi = ImageIO.read(new File("d:\\x.jpg"));
for (int y = 0; y < bi.getHeight(); y++) {
for (int x = 0; x < bi.getWidth() - 1; x++) {
p1 = new Color(bi.getRGB(x, y));
p2 = new Color(bi.getRGB(x + 1, y));
int a = (p1.getAlpha() + p2.getAlpha()) / 2;
int r = (p1.getRed() + p2.getRed()) / 2;
int g = (p1.getGreen() + p2.getGreen()) / 2;
int b = (p1.getBlue() + p2.getBlue()) / 2;
int x1 = p1.getRGB();
int x2 = p2.getRGB();
int sum1 = (x1 + x2) / 2;
int sum2 = a * 16777216 + r * 65536 + g * 256 + b;
System.out.println(sum1 == sum2);
}
}
}
public static void main(String... areg) throws IOException, InterruptedException {
new ColorTest1();
}
}
This is the image:
Take two pixels. One is black. The other is nearly black but with a slight bit of red in it, just 1/255. Ignore alpha. r will be (0 + 1) / 2 = 0. g and b will be 0 too. x1 will be 0. x2 will be 65536, right? So sum1 will be 65536 / 2 = 32768. sum2 obviously will be 0.
Whenever the sum of either red or green of the two colours is odd, the int division will set the high bit of the next colour in RGB, leading to an unexpected result.
so I am working on a program in java which creates the a rectangular image (see link below) as a ppm image that would be further written into a ppm file. Creating and writing the image to the file I get. However, I am having difficulty creating the image dynamically such that it works for any width and height specified. From my understanding, a p3 ppm file simply follows the following format for a 4x4 image.
P3
4 4
15
0 0 0 0 0 0 0 0 0 15 0 15
0 0 0 0 15 7 0 0 0 0 0 0
0 0 0 0 0 0 0 15 7 0 0 0
15 0 15 0 0 0 0 0 0 0 0 0
Where the first three numbers are the headings and the rest is simply the rgb values of each pixel. But I am having trouble figuring out how I can create the above matrix for the image below and for any dimensions specified as it does not include solid colors in a straight line?
Image to be created:
I figured I could create an arraylist which holds an array of rgb values such that each index in the list is one rgb set followed by the next rgb set to the right. However, I am quite confused on what the rgb values would be. Here is what I have:
public static void createImage(int width, int height){
pic = new ArrayList();
int[] rgb = new int[3];
for(int i = 0; i <= width; i++){
for(int j = 0; i <= height; j++){
rgb[0] = 255-j; //random values as im not sure what they should be or how to calculate them
rgb[1] = 0+j;
rgb[1] = 0+j;
pic.add(rgb);
}
}
}
Thanks in advance.
EDITED::Updated code
I have managed to fix most of the issues, however, the image generated does not match the one posted above. With this code. I get the following image:
package ppm;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
public class PPM {
private BufferedImage img;
private static final String imageDir = "Image/rect.ppm";
private final static String filename = "assignment1_q1.ppm";
private static byte bytes[]=null; // bytes which make up binary PPM image
private static double doubles[] = null;
private static int height = 0;
private static int width = 0;
private static ArrayList pic;
private static String matrix="";
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException {
createImage(200, 200);
writeImage(filename);
}
public static void createImage(int width, int height){
pic = new ArrayList();
int[] rgb = new int[3];
matrix +="P3\n" + width + "\n" + height + "\n255\n";
for(int i = 0; i <= height; i++){
for(int j = 0; j <= width; j++){
Color c = getColor(width, height, j, i);
//System.out.println(c);
if(c==Color.red){
rgb[0] = (int) (255*factor(width, height, j, i));
rgb[1] = 0;
rgb[2] = 0;
}else if(c==Color.green){
rgb[0] = 0;
rgb[1] = (int) (255*factor(width, height, j, i));
rgb[2] = 0;
}else if(c==Color.blue){
rgb[0] = 0;
rgb[1] = 0;
rgb[2] = (int) (255*factor(width, height, j, i));
}else if(c== Color.white){
rgb[0] = (int) (255*factor(width, height, j, i));
rgb[1] = (int) (255*factor(width, height, j, i));
rgb[2] = (int) (255*factor(width, height, j, i));
}
matrix += ""+ rgb[0] + " " + rgb[1] + " " + rgb[2] + " " ;
//System.out.println(""+ rgb[0] + " " + rgb[1] + " " + rgb[2] + " ");
//pic.add(rgb);
}
matrix += "\n";
}
}
public static Color getColor(int width, int height, int a, int b){
double d1 = ((double) width / height) * a;
double d2 = (((double) -width / height) * a + height);
if(d1 > b && d2 > b) return Color.green;
if(d1 > b && d2 < b) return Color.blue;
if(d1 < b && d2 > b) return Color.red;
return Color.white;
}
public static double factor(int width, int height, int a, int b){
double factorX = (double) Math.min(a, width - a) / width * 2;
double factorY = (double) Math.min(b, height - b) / height * 2;
//System.out.println(Math.min(factorX, factorY));
return Math.min(factorX, factorY);
}
public static void writeImage(String fn) throws FileNotFoundException, IOException {
//if (pic != null) {
FileOutputStream fos = new FileOutputStream(fn);
fos.write(new String(matrix).getBytes());
//fos.write(data.length);
//System.out.println(data.length);
fos.close();
// }
}
}
You can use Linear functions to model the diagonals in the picture. Keep in mind though that in the coordinates (0, 0) lie in the top-left corner of the image!
Say you want to create an image with the dimensions width and height, the diagonal from the top-left to bottom-right would cross the points (0, 0) and (width, height):
y = ax + t
0 = a * 0 + t => t = 0
height = a * width + 0 => a = height / width
d1(x) = (height / width) * x
Now we can calculate the function for the second diagonal. This diagonal goes through the points (0, height) and (width, 0), so:
y = ax + t
height = a * 0 + t => t = height
0 = a * width + height => a = -(height/width)
d2(x) = -(height/width) * x + height
From this we can determine whether a certain point in the image lies below or above a diagonal. As an example for the point (a, b):
if d1(a) > b: (a, b) lies above the first diagonal (left-top to right-bottom), thus it must be either blue or green. Otherwise it must be either red or white
if d2(a) > b: (a, b) lies above the second diagonal, thus it must be either red or green. Otherwise it must be white or blue
By applying both relationships it's easy to determine to which of the four colors a certain point belongs:
Color getColor(int width, int height, int a, int b){
double d1 = ((double) height / width) * a;
double d2 = ((double) -height / width) * a + height;
if(d1 > b && d2 > b) return greenColor;
if(d1 > b && d2 < b) return blueColor;
if(d1 < b && d2 > b) return redColor;
return whiteColor;
}
Now there's one last thing that we need to take into account: the image darkens towards it's borders.
A darker version of a color can be created by multiplying each channel with a factor. The lower the factor the darker the resulting the color. For the sake of simplicity I'll assume the change in brightness is linear from the center of the image.
Since the brightness changes along two axis independently, we need to model this by calculating the change alongside both axis and using the maximum.
The brightness change as a function of the distance of the center can be modeled using the distance to the closer border of the image in relation to the distance to the center (only on one axis):
deltaX = min(a, width - a) / (width / 2)
deltaY = min(b, height - b) / (height / 2)
So we can get the factor to multiply each color-channel by this way:
double factor(int width, int height, int a, int b){
double factorX = (double) Math.min(a, width - a) / width * 2;
double factorY = (double) Math.min(b, height - b) / height * 2;
return Math.min(factorX, factorY);
}
In my approach, I will use a hypothetical rectangle with co-ordinates (2,0) , (4,0), (2, 256) and (4, 256). I will generate random xy co-ordinates within this rectangle and find the ratio between the number of co-ordinates that fall within the region defined by y ≤ x^4 and the number of co-ordinates that fall within the entire rectangle. Multiplying this by the area of the rectangle should give me the area under the graph.
I am struggling to generate random decimal xy co-ordinates in the defined rectangle. Any help would be much appreciated :)
I have only just started integration in school so my knowledge in this area is quite narrow as of now.
Here is my code:
public class IntegralOfX2 {
public static double randDouble(double min, double max) {
min = 2;
max = 4;
Random rand = new Random();
double randomNum;
randomNum = min + rand.nextDouble((max - min) + 1); // an error keeps occuring here
return randomNum;
}
public static void main(String[] args) {
double x = 0; // x co-ordinate of dart
double y = 0; // y co-ordinate of dart
int total_darts = 0; // the total number of darts
int success_darts = 0; // the number of successful darts
double xmax = 4;
double xmin = 2;
double ymax = 256;
double ymin = 0;
double area = 0;
for (int i = 0; i < 400000000; i++) {
// x = randDouble(xmin, xmax);
// y = randDouble(ymin, ymax);
x = xmin + (Math.random() * ((xmax - xmin) + 1));
y = ymin + (Math.random() * ((ymax - ymin) + 1));
total_darts++;
if (y <= (x * x * x * x)) {
success_darts++;
}
}
double ratio = (double)success_darts/(double)total_darts;
area = ratio * 512;
System.out.println(area);
}
}
randomNum = min + rand.nextDouble((max - min) + 1); // an error keeps occuring here
This is an error because no such method exists. What you may want is
public static double randDouble(double min, double max) {
return min + Math.random() * (max - min + Math.ulp(max));
}
You can drop the Math.ulp but it is the closest to adding 1 for a random integer.
For large number of samples, you could use an even distribution e.g.
int samples = 100000;
double spacing = (max - min) / spacing;
for (int i = 0; i < samples; i++) {
double x = min + (i + 0.5) * spacing;
// use x as an input.
}
Since you're doing this on a bounded interval, you can generally get a lower variance estimate of the area by using Monte Carlo sampling of the average height of your function. Average height times the base is the area. In pseudocode:
def f(x) {
return x**4
}
range_min = 2
range_max = 4
range = range_max - range_min
sample_size = 100000
sum = 0
loop sample_size times {
sum += f(range_min + range * U) // where U is a Uniform(0,1) random number
}
estimated_area = range * (sum / sample_size)
Let's say I have a simple line chart with 5 values (a = 155, b = 200, c = 250, d = 300, e 0 345)
I need a way to calculate which values go on the Y-axis, in such a way that the values look nice. I also want to see the minor steps.
If I use a simple formula I would do this:
MaxValue - Minvalue = difference
300- 900 = 600
For 5 steps: 600/5 = 120 per step
That would lead to these values for the Y-axis:
Y0 = 200.0 (Rounding off to 200)
Y1 = 360.0 (Rounding off to 400)
Y2 = 520.0 (Rounding off to 600)
Y3 = 680.0 (Rounding off to 700)
Y4 = 840.0 (Rounding off to 900)
Y4 = 1000.0 (Rounding off to 1000)
What I actually would like is the values to be:
Y0 = 200
Y1 = 400
Y2 = 600
Y3 = 800
Y4 = 1000
But how do I calculate this?
Before calculation I don't know the magnitude of the values, it could be also like thousands, or tens.
Not exactly what you expect, but may give you an idea:
const int N = 6;
double vals[N] = {200.0, 360.0, 520.0, 680.0, 840.0, 1000.0};
for (int i = 0; i < N; i++) {
double factor = pow(10.0, floor(log10(vals[i])));
double v = floor(vals[i] / factor + 0.5) * factor;
std::cout << vals[i] << " " << v << std::endl;
}
P.S. Sorry, it's in C++ but you can easily translate it to Java.