Ok, I am using Processing which allows me to access pixels of any image as int[]. What I now want to do is to convert the image to gray-scale. Each pixel has a structure as shown below:
...........PIXEL............
[red | green | blue | alpha]
<-8--><--8---><--8--><--8-->
Now, what transformations do I need to apply to individual RGB values to make the image gray-scale ??
What I mean is, how much do I add / subtract to make the image gray-scale ?
Update
I found a few methods here: http://www.johndcook.com/blog/2009/08/24/algorithms-convert-color-grayscale/
For each pixel, the value for the red, green and blue channels should be their averages. Like this:
int red = pixel.R;
int green = pixel.G;
int blue = pixel.B;
pixel.R = pixel.G = pixel.B = (red + green + blue) / 3;
Since in your case the pixel colors seem to be stored in an array rather than in properties, your code could end up looking like:
int red = pixel[0];
int green = pixel[1];
int blue = pixel[2];
pixel[0] = pixel[1] = pixel[2] = (red + green + blue) / 3;
The general idea is that when you have a gray scale image, each pixel's color measures only the intensity of light at that point - and the way we perceive that is the average of the intensity for each color channel.
The following code loads an image and cycle through its pixels, changing the saturation to zero and keeping the same hue and brightness values.
PImage img;
void setup () {
colorMode(HSB, 100);
img = loadImage ("img.png");
size(img.width,img.height);
color sat = color (0,0,0);
img.loadPixels();
for (int i = 0; i < width * height; i++) {
img.pixels[i]=color (hue(img.pixels[i]), sat, brightness(img.pixels[i]));
}
img.updatePixels();
image(img,0,0);
}
Related
I'm designing a simple paint program and I need to make a color picker view for users to select background and paintbrush colors. I thought the best approach would be to split the rgb component of the color int in two and add them across a rectangle with vertical pixels being the 'rb' part and horizontal ones as the 'bg' part. For example: green - ff00ff00 would be broken into 00f and f00 and then added and OR'd with ff000000 to preserve the alpha. Maybe I'm doing the math wrong because I get a series of squares instead of a continuous gradient. Here is the relevant code:
int width = 500, height = 500;
int color = 0, xColor = 0, yColor = 0, MAX_HALF = 0xfff;
bitmap = Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888);
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
xColor = x * MAX_HALF / width;
yColor = (y * MAX_HALF / height) << 12;
color = xColor | yColor | 0xff000000;
bitmap.setPixel(x,y,color);
}
}
canvas.drawBitmap(bitmap,0,0,null);
This is the image I get.
Is it the code or the math?
There are two main ways you can accomplish that with a drawable:
Use two linear gradients
Use two radial gradients
check this link
Android: How to draw a two dimensional gradient
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 want to convert an image to a gray scale image where pixel intensities are between 0-255.
I was able to convert images to a gray scale images with the following Java method.
public void ConvertToGrayScale(BufferedImage bufImage, int ImgWidth, int ImgHeight) {
for (int w = 0; w < ImgWidth; w++) {
for (int h = 0; h < ImgHeight; h++) {
Color color = new Color(bufImage.getRGB(w, h));
int ColAvgVal = ((color.getRed() + color.getGreen() + color.getBlue()) / 3);
Color avg = new Color(ColAvgVal, ColAvgVal, ColAvgVal);
bufImage.setRGB(w, h, avg.getRGB());
System.out.println(avg.getRGB());
}
}
}
"System.out.println(avg.getRGB());" is used to see the pixel intensities but the all the grey levels are minus values and not between 0-255.
Am I doing it wrong ? How would I convert an image to a gray scale image where pixel intensities are between 0-255.
Thanks
color.getRGB() does not return a value from 0..255, it returns an integer composited of your red, green and blue values, including the Alpha value. Presumably, this alpha value is 0xFF, which makes any combined color end up as 0xFFrrggbb, or, as you got, a huge negative number when written in decimals.
To see the "gray" level assigned, just check ColAvgVal.
Note that a better formula to convert between RGB and grayscale is to use the PAL/NTSC conversion:
gray = 0.299 * red + 0.587 * green + 0.114 * blue
because "full blue" should be darker in grayscale than "full red" and "full green".
Note: if you use this formula directly, watch out for floating point rounding errors. In theory, it should not return a value outside of 0..255 for gray; in practice, it will. So test and clamp the result.
Another option which does not require testing-and-clamping per pixel, is to use an integer-only version:
gray = (299 * red + 587 * green + 114 * blue)/1000;
which should work with only a very small rounding error.
You can check this . I hope it can help you.
You can check some differents methods like:
// The average grayscale method
private static BufferedImage avg(BufferedImage original) {
int alpha, red, green, blue;
int newPixel;
BufferedImage avg_gray = new BufferedImage(original.getWidth(), original.getHeight(), original.getType());
int[] avgLUT = new int[766];
for(int i=0; i<avgLUT.length; i++)
avgLUT[i] = (int) (i / 3);
for(int i=0; i<original.getWidth(); i++) {
for(int j=0; j<original.getHeight(); j++) {
// Get pixels by R, G, B
alpha = new Color(original.getRGB(i, j)).getAlpha();
red = new Color(original.getRGB(i, j)).getRed();
green = new Color(original.getRGB(i, j)).getGreen();
blue = new Color(original.getRGB(i, j)).getBlue();
newPixel = red + green + blue;
newPixel = avgLUT[newPixel];
// Return back to original format
newPixel = colorToRGB(alpha, newPixel, newPixel, newPixel);
// Write pixels into image
avg_gray.setRGB(i, j, newPixel);
}
}
return avg_gray;
}
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));