I have two dimensional matrix which stores values between 0 to 1. I want to plot these values as levels of gray scale.
If the value is 1, it should be drawn as white.
If the value is 0, it should be drawn as black.
How would I do that in java?
I tried the classes: Color and BufferedImage, but I could not figure it out.
To create an image and set the pixels:
final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
image.setRGB(x, y, color);
}
}
color is an int, in this case, in ARGB format (top byte is alpha, then red byte, green byte, blue byte). Since you're doing greyscale, you want R, G and B to be the same value. You don't want alpha, so you should set that top byte to 0xFF.
See: BufferedImage.setRGB()
Related
I created 2D array of floats in java, representing gray scale image, when each pixel is normalized - it between [0,1].
How can I take the 2D array and display the image (in gray scale of course)?
ty!
The easiest way is to make a BufferedImage out of it. To do that, you'll have to convert the values into colors:
int toRGB(float value) {
int part = Math.round(value * 255);
return part * 0x10101;
}
That first converts the 0-1 range into 0-255 range, then produces a color where all three channels (RGB - red, green and blue) have the same value, which makes a gray.
Then, to make the whole image, set all the pixel values:
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
image.setRGB(x, y, toRGB(theFloats[y][x]));
Once you have the image, you can save it to a file:
ImageIO.save(image, 'png', new File('some/path/file.png'));
Or, display it in some way, perhaps with Swing.. See for example this question.
I am attempting to histogram equalize a grayscale image in Java. The description is as follows: Iterate over the image using one band of each pixel's RGB as the index of the look-up table to determine the new pixel value for the image. Set the RGB for each pixel to the RGB corresponding to the new pixel value.
Implementing this I get an image that is tinted blue:
[removed]
(Expected result)
[removed]
Here is the code I have so far:
private void histogramEqualize(BufferedImage im, int[] lut) {
for (int x = 0; x < im.getWidth(); x++) {
for (int y = 0; y < im.getHeight(); y++) {
Color c = new Color(im.getRGB(x, y));
Color eq = new Color(lut[c.getRed()], c.getGreen(), c.getBlue());
im1.setRGB(x, y, eq.getRGB());
}
}
}
public int[] getLookupTable(int[] h, int n) {
// h: Histogram for im1 in either the red band or luminance.
lut = new int[256];
double sf = 255/n;
int sumH = 0;
int sk = 0;
for(int i=0; i<h.length; i++) {
sumH += h[i];
sk = (int)(sf*sumH);
lut[i] = sk;
}
return lut;
}
I also tried changing Color eq = new Color(lut[c.getRed()], c.getGreen(), c.getBlue()); to Color eq = new Color(lut[c.getRed()], lut[c.getGreen()], lut[c.getBlue()]); but this resulted in a black image.
You have mentioned that you want to apply histogram equalization on a gray scale image but you are using RGB color values of pixels.
For gray scale image you can normalize only gray scale levels in image for histogram equalization as below:
1) Iterate through each gray scale pixels values and generate a histogram data of each gray scale levels by counting their occurrences in the image.
2) Find the cumulative distribution of the above histogram.
3) Iterate through each gray scale pixel values in the original image and replace their values with the their corresponding normalized values using below formula.
where L=255, that is total gray scale levels,
M = Image height,
N = Image width,
MxN to get total number of pixels in image.
cdfmin = min value of cumulative distribution data in step 2.
This will get you the new normalized image matrix.
If you want to to apply histogram equalization on RGB image then you will need to to convert RGB color space to HSV color space and apply same steps as in gray scale image on value channels without changing their hue and saturation values.
I have the following code to read a black-white picture in java.
imageg = ImageIO.read(new File(path));
BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_USHORT_GRAY);
Graphics g = bufferedImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
int w = img.getWidth();
int h = img.getHeight();
int[][] array = new int[w][h];
for (int j = 0; j < w; j++) {
for (int k = 0; k < h; k++) {
array[j][k] = img.getRGB(j, k);
System.out.print(array[j][k]);
}
}
As you can see I have set the type of BufferedImage into TYPE_USHORT_GRAY and I expect that I see the numbers between 0 and 255 in the two D array mattrix. but I will see '-1' and another large integer. Can anyone highlight my mistake please?
As already mentioned in comments and answers, the mistake is using the getRGB() method which converts your pixel values to packed int format in default sRGB color space (TYPE_INT_ARGB). In this format, -1 is the same as ยด0xffffffff`, which means pure white.
To access your unsigned short pixel data directly, try:
int w = img.getWidth();
int h = img.getHeight();
DataBufferUShort buffer = (DataBufferUShort) img.getRaster().getDataBuffer(); // Safe cast as img is of type TYPE_USHORT_GRAY
// Conveniently, the buffer already contains the data array
short[] arrayUShort = buffer.getData();
// Access it like:
int grayPixel = arrayUShort[x + y * w] & 0xffff;
// ...or alternatively, if you like to re-arrange the data to a 2-dimensional array:
int[][] array = new int[w][h];
// Note: I switched the loop order to access pixels in more natural order
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
array[x][y] = buffer.getElem(x + y * w);
System.out.print(array[x][y]);
}
}
// Access it like:
grayPixel = array[x][y];
PS: It's probably still a good idea to look at the second link provided by #blackSmith, for proper color to gray conversion. ;-)
A BufferedImage of type TYPE_USHORT_GRAY as its name says stores pixels using 16 bits (size of short is 16 bits). The range 0..255 is only 8 bits, so the colors may be well beyond 255.
And BufferedImage.getRGB() does not return these 16 pixel data bits but quoting from its javadoc:
Returns an integer pixel in the default RGB color model (TYPE_INT_ARGB) and default sRGB colorspace.
getRGB() will always return the pixel in RGB format regardless of the type of the BufferedImage.
I have to handle VERY large (1-2GB) Tiff files, and only need to do some RGB manipulations on pixels, where I only make local corrections (color of a modified pixel is only depending on its old values, but not on e.g. neighbor pixels).
Is their (JAVA) a way to read the file as some kind of pixel stream, make adjustments on the RGB values, and write the stuff immediately to another file? I will not have enough memory to store the entire file in RAM (or at least I hope I could avoid it)
Thx for any hints...
THX
-Marco
Well, I don't actually know what a tiff file is ๐
, but if it is a file, which you can store in a BufferedImage, it should be relatively easy.
I would do something like:
public BufferedImage correctRGB()
{
BufferedImage b = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//width and height are the width and height of the original image
Graphics g = b.getGraphics();
for(int x = 0; x < b.getHeight(); x++)
{
for(int y = 0; y < b.getWidth(); y++)
{
//loop through all the pixels in the image ONCE to spare RAM
int pixels = b.getRGB(x, y);
int alpha = (pixels >> 24) &0xff;
int red = (pixels >> 16) &0xff;
int green = (pixels >> 8) &0xff;
int blue = pixels &0xff;
//in here you play around with the values
g.setColor(new Color(red, green, blue, alpha));
g.fillRect(x, y, 1, 1);
}
}
g.dispose();
return b;
}
you can basically do everything you want with the argb values now.
For example, you could turn the whole image negative by doing red = 255 - red and so on.
or turn the whole image into grayscale by doing
int average = (red + green + blue) / 3;
g.setColor(new Color(average, average, average, alpha));
I'm using a flood fill algorithm to sort through an image. If it encounters the same color, I want it copy that pixel over into an identically sized array called filled. The array filled is then transformed back into an image and saved as a jpg. However, when I open the jpg, it appears entirely black.
public static void findFace(int[][] image) throws IOException {
int height = image.length;
int width = image[0].length;
Color centerStart = new Color(image[width / 2][height / 2]);
int[][] filled = new int[width][height];
floodFill(width / 2, height / 2, centerStart, image, filled);
//construct the filled array as image. Show if the face was found.
BufferedImage bufferImage2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int Pixel = filled[x][y] << 16 | filled[x][y] << 8 | filled[x][y];
bufferImage2.setRGB(x, y, Pixel);
}
}
//save filled array as image file
File outputfile = new File("/home/lily/Pictures/APicaDay/saved.jpg");
ImageIO.write(bufferImage2, "jpg", outputfile);
}
public static int[][] floodFill(int x, int y, Color targetColor, int[][] image, int[][] filled) {
if (image[x][y] != targetColor.getRGB()) {
return filled;
}
filled[x][y] = image[x][y];
floodFill(x - 1, y, targetColor, image, filled);
floodFill(x + 1, y, targetColor, image, filled);
floodFill(x, y - 1, targetColor, image, filled);
floodFill(x, y + 1, targetColor, image, filled);
return filled;
}
bonus question: I would like the flood fill to also accept colors that are similar, but not the exact same, since I'm dealing with a photograph.
The floodFill function you've posted is missing two important elements:
If the area containing the same color as the first pixel extends all the way to the boundary of the image, the function will try to access image at an invalid index. You can fix this by first checking the x and y coordinates of the pixel you are checking, and returning immediately if they are out of bounds.
If there is more than one adjacent pixel of the same color, the function will cause recurse infinitely, since the initial call will call floodFill on the second pixel, which will then proceed to call floodFill on the first pixel, and so on. You need a way to make sure that you only call floodFill on a particular pixel once.
Since you're not observing either of these two symptoms, and you don't observe anything from the resulting image, I guess that the initial pixel's color check is not correct. When you pass an integer to the Color constructor, are you sure that it uses an RBG interpretation of that integer?