How to isolate red/green/blue channel in BufferedImage: I have following code that does NOT work:`
public static BufferedImage isolateChannel(BufferedImage image,
EIsolateChannel channel)
{
BufferedImage result=new BufferedImage(image.getWidth(),
image.getHeight(),
image.getType());
int iAlpha=0;
int iRed=0;
int iGreen=0;
int iBlue=0;
int newPixel=0;
for(int i=0; i<image.getWidth(); i++)
{
for(int j=0; j<image.getHeight(); j++)
{
iAlpha=new Color(image.getRGB(i, j)).getAlpha();
iRed=new Color(image.getRGB(i, j)).getRed();
iGreen=new Color(image.getRGB(i, j)).getGreen();
iBlue=new Color(image.getRGB(i, j)).getBlue();
if(channel.equals(EIsolateChannel.ISOLATE_RED_CHANNEL))
{
newPixel=iRed;
}
if(channel.equals(EIsolateChannel.ISOLATE_GREEN_CHANNEL))
{
newPixel=iGreen;
}
if(channel.equals(EIsolateChannel.ISOLATE_BLUE_CHANNEL))
{
newPixel=iBlue;
}
result.setRGB(i,
j,
newPixel);
}
}
return result;
}`
By isolating channel I mean that if red channel is selected for isolation, for example, that only red component of picture is shown!
Color in java is defined in a packed integer,that is in a 32 bit integer the first 8 bits are alpha, next 8 are red, next 8 are green and last 8 are blue.
Suppose the following is an 32 bit integer representing a color.Then,
AAAAAAAA RRRRRRRR GGGGGGGG BBBBBBBB
^Alpha ^Red ^Green ^Blue
That is, each of alpha, red, green and blue are basically 8 bits with values from 0 to 255 (the color range). So when you would want to combine these individual components back into the 32 bit integer color you should write
color=alpha<<24 | red<<16 | green<<8 | blue
So as per the rules change the code to the following
if(channel.equals(EIsolateChannel.ISOLATE_RED_CHANNEL))
{
newPixel = newPixel | iRed<<16;
//Can also write newPixel=iRed , since newPixel is always 0 before this
}
if(channel.equals(EIsolateChannel.ISOLATE_GREEN_CHANNEL))
{
newPixel = newPixel | iGreen<<8;
}
if(channel.equals(EIsolateChannel.ISOLATE_BLUE_CHANNEL))
{
newPixel = newPixel | iBlue;
}
Note : I have ORed the newPixel before each component to allow display of multiple channels simultaneously, i.e you could display red and green with blue turned off.
UPDATE
The second error you are getting is due to the fact that you are not resetting the value of newPixel after each iteration. So to fix it add the line newPixel=0 within the loop.
Your code should be
newPixel=0; //Add this line
iAlpha=new Color(img.getRGB(x, y)).getAlpha();
iRed=new Color(img.getRGB(x, y)).getRed();
iGreen=new Color(img.getRGB(x, y)).getGreen();
iBlue=new Color(img.getRGB(x, y)).getBlue();
For added efficiency I would suggest using bitshifts for obtaining the red, green, blue, and the alpha.
int rgb = img.getRGB(x,y);
iAlpha = rgb>>24 & 0xff;
iRed = rgb >>16 & 0xff;
iGreen = rgb>>8 & 0xff;
iBlue = rgb & 0xff;
This code would run faster as it does not creates 4 Color objects for each pixel in the source image
Try this:
int width = bufferedImage.getWidth(), height = bufferedImage.getHeight();
Object dataElements = null;
Raster raster = bufferedImage.getRaster();
ColorModel colorModel = bufferedImage.getColorModel();
int red, blue, green, alpha;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
dataElements = raster.getDataElements(x, y, dataElements);
// extract colors
red = colorModel.getRed(dataElements);
blue = colorModel.getBlue(dataElements);
green = colorModel.getGreen(dataElements);
alpha = colorModel.getAlpha(dataElements);
}
}
Related
SOLVED : Issue was "jpeg compression". Saving as ".png" worked.
I had detected edges of an image using a canny filter program in java.
After applying filter ...
This is my image
If zoomed in ...
Zoomed
All have different shades of black and white.
I want all my edge pixels as pure white(#FFFFFF) and the remaining portion black.
Note: Different pixels may have different shades apart from the one above(#F7F7F7). The zoomed image above is just an example.
Edit:
I had written this code to take effect on image ...
public void convert(){
try{
BufferedImage img = ImageIO.read(new File("input.jpg"));
int rgb;
int height = img.getHeight();
int width = img.getWidth();
File f = new File("newThreshold.jpg");
Color white = new Color(255,255,255);
int wh = white.getRGB();
for (int h = 0; h<height; h++){
for (int w = 0; w<width; w++){
rgb = img.getRGB(w, h);
red = (rgb & 0x00ff0000) >> 16;
green = (rgb & 0x0000ff00) >> 8;
blue = rgb & 0x000000ff;
if(red >= 200 || blue >= 200 || green >= 200){
img.setRGB(w,h,wh);
}
}
}
ImageIO.write(img,"jpg",f);
}
catch(Exception e){
}
}
Even after running the code, there is no change in my image.
Even if the red, green and blue values are above 200, my image is not changing.
UPDATE: Saving the image as ".png" rather than ".jpg" worked!
You can go through each pixel in the image and determine if it is above a certain threshold, if it is set its value to pure white. You can also do the same for the darker areas if needed.
Example:
public Image thresholdWhite(Image in, int threshold)
{
Pixel[][] pixels = in.getPixels();
for(int i = 0; i < pixels.length; ++i)
{
for(int j = 0; j < pixels[i].length; ++j)
{
byte red = pixels[i][j].getRed();
byte green = pixels[i][j].getGreen();
byte blue = pixels[i][j].getBlue();
/* In case it isn't a grayscale image, if it is grayscale this if can be removed (the block is still needed though) */
if(Math.abs(red - green) >= 16 && Math.abs(red - blue) >= 16 && Math.abs(blue- green) >= 16)
{
if(red >= threshold || blue >= threshold || green >= threshold)
{
pixels[i][j] = new Pixel(Colors.WHITE);
}
}
}
}
return new Image(pixels);
}
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 am trying to read the pixel values of the image using the below code
int[] pixel;
BufferedImage imageA = ImageIO.read(new File("xyz.bmp"));
for (int y = 0; y < imageA.getHeight(); ++y) {
for (int x = 0; x < imageA.getWidth(); ++x) {
pixel = imageA.getRaster().getPixel(x, y, new int[3]);
}}
values of RGB are stored in pixel[0],pixel[1] and pixel[2] respectively and when i saw the output i saw the values ranging between 0 to 255.
I saw some use the below code to get pixel values
int pixel;
BufferedImage imageA = ImageIO.read(new File("xyz.bmp"));
for (int y = 0; y < imageA.getHeight(); ++y) {
for (int x = 0; x < imageA.getWidth(); ++x) {
pixel = imageA.getRGB(x, y);
}}
When i saw the output for a particular pixel it was -14935264 . What does this value represent and whats the difference between the above two methods.
In the second case, you get an int that contains the RGB-values in the lower 24 bits. The red component is bits 23-16, the green component is bits 15-8 and the blue component is bits 7-0.
If you want to get the components out of the int:
int red = (pixel >> 16) & 0xFF;
int green = (pixel >> 8) & 0xFF;
int blue = pixel & 0xFF;
The other way around:
int pixel = (red << 16) | (green << 8) | blue;
I have been trying out some basic image processing using java (after a long gap).
Any operation I do on the original image and save it as a new image -> the o/p image always appears DULL (may be an issue with opacity or transparency).
I am pasting the function which I am using to do this job below :
//Returns a blurred java buffered image
public static BufferedImage blurImage(BufferedImage image)
{
int w = image.getWidth();
int h = image.getHeight();
int alpha = 0;
int red, green, blue, newPix;
int pix[] = null;
BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
for(int i=0,j=0; i<w; i++)
{
for(j=0; j<h; j++)
{
pix = getSurroundingPixels(image, i>0?i-1:0, i<w-1?i+1:w-1, j>0?j-1:0, j<h-1?j+1:h-1);
red = green = blue = 0;
for(int k=0; k<pix.length; k++)
{
red += (pix[k]>>16) & 0xFF;
green += (pix[k]>>8) & 0xFF;
blue += (pix[k]) & 0xFF;
}
alpha = (image.getRGB(i,j)>>24) & 0xFF;
red /= pix.length;
green /= pix.length;
blue /= pix.length;
newPix = ((alpha<<24) | (red<<16) | (green<<8) | blue);
newImage.setRGB(i,j, newPix);
}
}
return newImage;
}
I would appreciate someone helping me on this issue.
I have now replaced BufferedImage.INT_TYPE_ARGB with BufferedImage.INT_TYPE_RGB, after this, the [processed] image doesn't appear dull, and [it] looks normal. Can you please explain why does this happen?
TYPE_INT_ARGB has a DirectColorModel with alpha; TYPE_INT_RGB has a DirectColorModel without alpha. Your algorithm scales the RGB, but clones the A. At a guess, your test image is opaque, possibly a .jpg image, requiring BufferedImage.TYPE_INT_RGB. You may want to examine your image using this example that scales A or this example that illustrates the color conversion done by setRGB().
I know the java code for grayscale is this( 0.2126 * red + 0.7152 * green + 0.0722 * blue(
I was wondering if anyone knows how I can find more variety of coloring formulas, like if i want to make the picture old fashion way, more orange, make it brighter, or darker ... sharper and so on
int pixel = image.getRGB(j, i);
int red = (pixel) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel >> 16) & 0xff;
int newPixel = (int) (0.2126 * red + 0.7152 * green + 0.0722 * blue);
image1.setRGB(j, i, newPixel);
The old fashion way you mention is called "sepia" effect. Take a look at this question particularly this answer which points out to the following code snippet (note that I did not write this code, just helping out in finding answers to your question)
/**
*
* #param img Image to modify
* #param sepiaIntensity From 0-255, 30 produces nice results
* #throws Exception
*/
public static void applySepiaFilter(BufferedImage img, int
sepiaIntensity) throws Exception
{
// Play around with this. 20 works well and was recommended
// by another developer. 0 produces a grey image
int sepiaDepth = 20;
int w = img.getWidth();
int h = img.getHeight();
WritableRaster raster = img.getRaster();
// We need 3 integers (for R,G,B color values) per pixel.
int[] pixels = new int[w*h*3];
raster.getPixels(0, 0, w, h, pixels);
// Process 3 ints at a time for each pixel. Each pixel has 3 RGB
colors in array
for (int i=0;i<pixels.length; i+=3)
{
int r = pixels[i];
int g = pixels[i+1];
int b = pixels[i+2];
int gry = (r + g + b) / 3;
r = g = b = gry;
r = r + (sepiaDepth * 2);
g = g + sepiaDepth;
if (r>255) r=255;
if (g>255) g=255;
if (b>255) b=255;
// Darken blue color to increase sepia effect
b-= sepiaIntensity;
// normalize if out of bounds
if (b<0) b=0;
if (b>255) b=255;
pixels[i] = r;
pixels[i+1]= g;
pixels[i+2] = b;
}
raster.setPixels(0, 0, w, h, pixels);
}
I would just play with the numbers.
more orange,
more red and a little more green (red + green = yellow)
brighter
increase all the factors
darker
decrease all the factors
sharper
This is specific filter which compare surrounding pixels to find edges. It not just a matter of playing with the colours.
BTW: You should add capping of the values. i.e. Math.min(255, Math.max(0, value))
You can manipulate the proportion between the color channels in order to change the scene "atmosphere". The images below were created using the ColorChannel plug-in.
The algorithm source code is presented below. The method getAttribute() gets the parameters (red,gree,blue) passed by the user. The methods getIntComponent0, getIntComponent1 and getIntComponent2 get each color channel (red, gree and blue). The method setIntColor sets back the value of each channel.
#Override
public void process
(
MarvinImage imageIn,
MarvinImage imageOut,
MarvinAttributes attrOut,
MarvinImageMask mask,
boolean preview
) {
int vr = (Integer)getAttribute("red");
int vg = (Integer)getAttribute("green");
int vb = (Integer)getAttribute("blue");
double mr = 1+Math.abs((vr/100.0)*2.5);
double mg = 1+Math.abs((vg/100.0)*2.5);
double mb = 1+Math.abs((vb/100.0)*2.5);
mr = (vr > 0? mr : 1.0/mr);
mg = (vg > 0? mg : 1.0/mg);
mb = (vb > 0? mb : 1.0/mb);
int red,green,blue;
for(int y=0; y<imageIn.getHeight(); y++){
for(int x=0; x<imageIn.getWidth(); x++){
red = imageIn.getIntComponent0(x, y);
green = imageIn.getIntComponent1(x, y);
blue = imageIn.getIntComponent2(x, y);
red = (int)Math.min(red * mr, 255);
green = (int)Math.min(green * mg, 255);
blue = (int)Math.min(blue * mb, 255);
imageOut.setIntColor(x, y, 255, red, green, blue);
}
}
}