Not sure how to implement the following algorithm - java

I am trying to implement Histogram/image Equalization on a coloured image. I am not sure if I have implemented it correct because the screen just goes black every time I apply it to a bitmap image. The algorithm is called histogram equalization.
The part of my code that does the Histogram Equalization calculation:
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
A = (pixels[index] >> 24) & 0xFF;
R = (pixels[index] >> 16) & 0xFF;
G = (pixels[index] >> 8) & 0xFF;
B = pixels[index] & 0xFF;
R = Math.round(((R - cumR[minR]) / (cumR[maxR] - cumR[minR])) * 255);
G = Math.round(((G - cumG[minG]) / (cumG[maxG] - cumG[minG])) * 255);
B = Math.round(((B - cumB[minB]) / (cumB[maxB] - cumB[minB])) * 255);
returnBitmap.setPixel(x, y, Color.argb(A, R, G, B));
++index;
}
}
The image appears black once my code is applied, why doesnt it display an equalized image?

You're not calculating the histograms correctly. You shouldn't have a histogram spot for each pixel, you have one for each value[0..255]. You want to count how many pixels have that value, not the total "value" of red.
Here's a good way to get the histogram(and cumulative) for an image. It should get you started on the right path.
// generate histogram channels
// histogram arrays should be [0...255]
for (int i = 0; i < pixels.length; i++) {
R = (pixels[i] >> 16) & 0xFF;
G = (pixels[i] >> 8) & 0xFF;
B = pixels[i] & 0xFF;
histoR[R]++;
histoG[G]++;
histoB[B]++;
}
// generate cumulative histograms
cumR[0] = histoR[0];
cumG[0] = histoG[0];
cumB[0] = histoB[0];
for(int i=1;i<histoR.length;i++){
cumR[i] = histoR[i] + histoR[i-1];
cumG[i] = histoG[i] + histoG[i-1];
cumB[i] = histoB[i] + histoB[i-1];
}

After some research, I was able to find a Histogram Equalization using a LUT example for Java and it is a better option than converting it to another Color Space such as RGB to YUV.
With minimal modification, I was able to use the following code:
Histogram Equalization for Java

Related

How many iterations of the Mandelbrot set for an accurate picture at a certain zoom?

I have implemented the mandelbrot set algorithm in Java which I am using to make an animation of zooming into the set. My problem is that the algorithm is performing very slowly since I have it set such that the maximum number of iterations is high (1000) so that clarity will be preserved when zooming in closely. However, when on a more zoomed-out picture, only around 100 iterations are required to have an accurate picture.
My question is: is there some function f(x) such that for x screen width, clarity will be acceptable? (This only needs to be approximate since the definition of "clear" isn't itself very clear, but the trendline should follow the rate of increase of accuracy which follows the set itself)
Here is my current implementation of the algorithm:
private double[] target = {-1.256640565451168862869, -0.382386428889165027247};
// Returns an integer RGB value (0xRRGGBB) representing the colour which should be drawn at a certain position on the screen
private int getMandleRGB(int x, int y, int w, int h) {
Complex c = new Complex();
c.r = lerp(lerp(-2, target[0], 1-zoom), lerp(1, target[0], 1-zoom), x/(double) w);
c.i = lerp(lerp(-1.5, target[1], 1-zoom), lerp(1.5, target[1], 1-zoom), y/(double) h);
Complex z = new Complex();
z.r = c.r;
z.i = c.i;
int i = 0;
for (i = 0; i < 1000; i++) {
z = Complex.add(Complex.multiply(z, z), c);
if (z.i*z.i+z.r*z.r > 4) {
double t = Math.log(i)/Math.log(1000d);
return (int) lerp((gradient[0] & 0xff0000) >> 16,
(gradient[1] & 0xff0000) >> 16, t)*0x10000
+ (int) lerp((gradient[0] & 0xff00) >> 8,
(gradient[1] & 0xff00) >> 8, t)*0x100
+ (int) lerp((gradient[0] & 0xff),
(gradient[1] & 0xff), t);
}
}
return 0x000000; // black
}

How to match a webcam captured image with another image in Java Swing?

I am trying to make a hand sign converter in java for my university project . For that i have to match hand sign image and find out the meaning of that particular hand sign .
i have already tired this way to find out the difference percentage between two image .But this way doesn't get me the perfect result .
imgA = ImageIO.read(fileA);
imgB = ImageIO.read(fileB);
}
catch (IOException e)
{
System.out.println(e);
}
int width1 = imgA.getWidth();
int width2 = imgB.getWidth();
int height1 = imgA.getHeight();
int height2 = imgB.getHeight();
if ((width1 != width2) || (height1 != height2))
System.out.println("Error: Images dimensions"+
" mismatch");
else
{
long difference = 0;
for (int y = 0; y < height1; y++)
{
for (int x = 0; x < width1; x++)
{
int rgbA = imgA.getRGB(x, y);
int rgbB = imgB.getRGB(x, y);
int redA = (rgbA >> 16) & 0xff;
int greenA = (rgbA >> 8) & 0xff;
int blueA = (rgbA) & 0xff;
int redB = (rgbB >> 16) & 0xff;
int greenB = (rgbB >> 8) & 0xff;
int blueB = (rgbB) & 0xff;
difference += Math.abs(redA - redB);
difference += Math.abs(greenA - greenB);
difference += Math.abs(blueA - blueB);
}
}
// Total number of red pixels = width * height
// Total number of blue pixels = width * height
// Total number of green pixels = width * height
// So total number of pixels = width * height * 3
double total_pixels = width1 * height1 * 3;
// Normalizing the value of different pixels
// for accuracy(average pixels per color
// component)
double avg_different_pixels = difference /
total_pixels;
// There are 255 values of pixels in total
double percentage = (avg_different_pixels /
255) * 100;
I expect the output to be that much accurate ,it can distinguish different hand sign and find me the correct match
for image manipulation using java you should use javacv which is wrapper over opencv . Though javacv is not an official release from opencv still you can find many useful functionalities in javacv.
The official site for javacv is
http://bytedeco.org/
To get started with javacv you can follow articles from the below site
Basic image manipulation using javacv
Capturing image from webcam using javacv
Hand and finger detection using javacv

Getting all RGB colors of an image

So far I have this:
BufferedImage image = ImageIO.read(
new URL("http://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png"));
int w = image.getWidth();
int h = image.getHeight();
int[] dataBuffInt = image.getRGB(0, 0, w, h, null, 0, w);
Color c = new Color(dataBuffInt[100]);
System.out.println(c.getRed()); // = (dataBuffInt[100] >> 16) & 0xFF
System.out.println(c.getGreen()); // = (dataBuffInt[100] >> 8) & 0xFF
System.out.println(c.getBlue()); // = (dataBuffInt[100] >> 0) & 0xFF
System.out.println(c.getAlpha()); // = (dataBuffInt[100] >> 24) & 0xFF
Earlier, I tried putting the getRed, getGreen, and getBlue in a for loop but it only shows the same RGB value. How do I get all the RGB values in an image? Given that I wanna store them in different arrays.
I'm not entirely clear on the question, but assuming you mean unique RGB values, just loop, and just use say java.util.Set implementation that maintains uniqueness?
Set<Color> colors = new HashSet<Color>();
for (int datum : dataBuffInt) {
colors.add(new Color(datum));
}
System.out.println(String.format("%d different colors", colors.size()));
Or if you mean separate components?
for (int datum : dataBuffInt) {
Color color = new Color(datum);
reds.add(color.getRed());
greens.add(color.getGreen());
blues.add(color.getBlue());
}
System.out.println(String.format("reds: %d greens: %d blues: %d", reds.size(), greens.size(), blues.size()));
Are you certain when you had the for loop you were using the index variable into the array and not a static value, like 100? When I run your code with a for loop I see different values:
for (int i = 0; i < dataBuffInt.length; i++) {
Color c = new Color(dataBuffInt[i]);
System.out.println("COLOR");
System.out.println(c.getRed()); // = (dataBuffInt[100] >> 16) & 0xFF
System.out.println(c.getGreen()); // = (dataBuffInt[100] >> 8) & 0xFF
System.out.println(c.getBlue()); // = (dataBuffInt[100] >> 0) & 0xFF
System.out.println(c.getAlpha()); // = (dataBuffInt[100] >> 24) & 0xFF
System.out.println();
}
If you want unique colors you could build a set one pixel at a time:
final BufferedImage image = ImageIO.read(new URL("http://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png"));
final Set<Color> uniqueColors = new HashSet<Color>(image.getWidth() * image.getHeight());
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
final int rgb = image.getRGB(x, y);
uniqueColors.add(new Color(rgb));
}
}
for (final Color color : uniqueColors) {
System.out.println(format("red: {0}, green: {1}, blue: {2}, alpha: {3}",
color.getRed(),
color.getGreen(),
color.getBlue(),
color.getAlpha()));
}
Or use your existing code and dump the array into a set.

Converting grayscale image pixels to defined scale

I'm looking to use a very crude heightmap I've created in Photoshop to define a tiled isometric grid for me:
Map:
http://i.imgur.com/jKM7AgI.png
I'm aiming to loop through every pixel in the image and convert the colour of that pixel to a scale of my choosing, for example 0-100.
At the moment I'm using the following code:
try
{
final File file = new File("D:\\clouds.png");
final BufferedImage image = ImageIO.read(file);
for (int x = 0; x < image.getWidth(); x++)
{
for (int y = 0; y < image.getHeight(); y++)
{
int clr = image.getRGB(x, y) / 99999;
if (clr <= 0)
clr = -clr;
System.out.println(clr);
}
}
}
catch (IOException ex)
{
// Deal with exception
}
This works to an extent; the black pixel at position 0 is 167 and the white pixel at position 999 is 0. However when I insert certain pixels into the image I get slightly odd results, for example a gray pixel that's very close to white returns over 100 when I would expect it to be in single digits.
Is there an alternate solution I could use that would yield more reliable results?
Many thanks.
Since it's a grayscale map, the RGB parts will all be the same value (with range 0 - 255), so just take one out of the packed integer and find out what percent of 255 it is:
int clr = (int) ((image.getRGB(x, y) & 0xFF) / 255.0 * 100);
System.out.println(clr);
getRGB returns all channels packed into one int so you shouldn't do arithmetic with it. Maybe use the norm of the RGB-vector instead?
for (int x = 0; x < image.getWidth(); ++x) {
for (int y = 0; y < image.getHeight(); ++y) {
final int rgb = image.getRGB(x, y);
final int red = ((rgb & 0xFF0000) >> 16);
final int green = ((rgb & 0x00FF00) >> 8);
final int blue = ((rgb & 0x0000FF) >> 0);
// Norm of RGB vector mapped to the unit interval.
final double intensity =
Math.sqrt(red * red + green * green + blue * blue)
/ Math.sqrt(3 * 255 * 255);
}
}
Note that there is also the java.awt.Color class that can be instantiated with the int returned by getRGB and provides getRed, getGreen and getBlue methods if you don't want to do the bit manipulations yourself.

Incorrect result of image subtraction

I wanted to subtract two images pixel by pixel to check how much they are similar. Images have the same size one is little darker and beside brightness they don't differ. But I get those little dots in the result. Did I subtract those two images rigth? Both are bmp files.
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class Main2 {
public static void main(String[] args) throws Exception {
int[][][] ch = new int[4][4][4];
BufferedImage image1 = ImageIO.read(new File("1.bmp"));
BufferedImage image2 = ImageIO.read(new File("2.bmp"));
BufferedImage image3 = new BufferedImage(image1.getWidth(), image1.getHeight(), image1.getType());
int color;
for(int x = 0; x < image1.getWidth(); x++)
for(int y = 0; y < image1.getHeight(); y++) {
color = Math.abs(image2.getRGB(x, y) - image1.getRGB(x, y));
image3.setRGB(x, y, color);
}
ImageIO.write(image3, "bmp", new File("image.bmp"));
}
}
Image 1
Image 2
Result
The problem here is that you can't subtract the colors direcly. Each pixel is represented by one int value. This int value consists of 4 bytes. These 4 bytes represent the color components ARGB, where
A = Alpha
R = Red
G = Green
B = Blue
(Alpha is the opacity of the pixel, and always 255 (that is, the maximum value) in BMP images).
Thus, one pixel may be represented by
(255, 0, 254, 0)
When you subtract another pixel from this one, like (255, 0, 255, 0), then the third byte will underflow: It would become -1. But since this is part of ONE integer, the resulting color will be something like
(255, 0, 254, 0) -
(255, 0, 255, 0) =
(255, 255, 255, 0)
and thus, be far from what you would expect in this case.
The key point is that you have to split your color into the A,R,G and B components, and perform the computation on these components. In the most general form, it may be implemented like this:
int argb0 = image0.getRGB(x, y);
int argb1 = image1.getRGB(x, y);
int a0 = (argb0 >> 24) & 0xFF;
int r0 = (argb0 >> 16) & 0xFF;
int g0 = (argb0 >> 8) & 0xFF;
int b0 = (argb0 ) & 0xFF;
int a1 = (argb1 >> 24) & 0xFF;
int r1 = (argb1 >> 16) & 0xFF;
int g1 = (argb1 >> 8) & 0xFF;
int b1 = (argb1 ) & 0xFF;
int aDiff = Math.abs(a1 - a0);
int rDiff = Math.abs(r1 - r0);
int gDiff = Math.abs(g1 - g0);
int bDiff = Math.abs(b1 - b0);
int diff =
(aDiff << 24) | (rDiff << 16) | (gDiff << 8) | bDiff;
result.setRGB(x, y, diff);
Since these are grayscale images, the computations done here are somewhat redundant: For grayscale images, the R, G and B components are always equal. And since the opacity is always 255, it does not have to be treated explicitly here. So for your particular case, it should be sufficient to simplify this to
int argb0 = image0.getRGB(x, y);
int argb1 = image1.getRGB(x, y);
// Here the 'b' stands for 'blue' as well
// as for 'brightness' :-)
int b0 = argb0 & 0xFF;
int b1 = argb1 & 0xFF;
int bDiff = Math.abs(b1 - b0);
int diff =
(255 << 24) | (bDiff << 16) | (bDiff << 8) | bDiff;
result.setRGB(x, y, diff);
You did not "subtract one pixel from the other" correctly. getRGB returns "an integer pixel in the default RGB color model (TYPE_INT_ARGB)". What you are seeing is an "overflow" from one byte into the next, and thus from one color into the next.
Suppose you have colors 804020 - 404120 -- this is 3FFF00; the difference in the G component, 1 gets output as FF.
The correct procedure is to split the return value from getRGB into separate red, green, and blue, subtract each one, make sure they fit into unsigned bytes again (I guess your Math.abs is okay) and then write out a reconstructed new RGB value.
I found this which does what you want. It does seem to do the same thing and it may be more "correct" than your code. I assume it's possible to extract the source code.
http://tutorial.simplecv.org/en/latest/examples/image-math.html
/Fredrik Wahlgren

Categories