问题
I am currently working on one use case where i need to determine if uploaded image is Grey Scale or RGB. I found couple of ways to identify this, but not sure if they are reliable and can be used collectively to confirm image is grey scale or not.
Part 1: Read Image and get NumberDataElements using Raster.
BufferedImage image = ImageIO.read(file);
Raster ras = image.getRaster();
int elem = ras.getNumDataElements();
I observed value of elem is "1" in some cases, but not in all.
Part 2: Check RGB value of each pixel. If R , G, B value is same of given pixel.
BufferedImage image = ImageIO.read(file);
Raster ras = image.getRaster();
//Number of Color elements
int elem = ras.getNumDataElements();
int width = image.getWidth();
int height = image.getHeight();
int pixel,red, green, blue;
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++) {
//scan through each pixel
pixel = image.getRGB(i, j);
red = (pixel >> 16) & 0xff;
green = (pixel >> 8) & 0xff;
blue = (pixel) & 0xff;
//check if R=G=B
if (red != green || green != blue ) {
flag = true;
break;
}
}
Here i check R, G,B values are same for any given pixel and this behavior is consistent across all pixels.
I am using these 2 approaches, but not sure how accurate they are. Kindly suggest..
回答1:
Move your if (flag) { break; }
line outside of the inner for loop.
And you only need to check that (red != green || green != blue)
. Breaking any one of these two equalities ensures that the third MUST be broken, so you only require two checks.
I'd also possibly just set an isGrayscale variable of boolean to true and then set it to false, when the equality logic breaks, rather than setting a flag to true. It should be assumed to be grayscale, until it breaks and becomes false. No problem with what you have here with flag, but this is a little more meaningful and intuitive.
If you want to get really clever, you could allow for a delta of variance to allow for images that are SUFFICIENTLY grayscale for purpose i.e. their deviance from equality is lower than a set barrier. But this works as it is :)
回答2:
Below approach is worked for me. Thanks guys for help.
BufferedImage image = ImageIO.read(file);
Raster ras = image.getRaster();
//Number of Color elements
int elem = ras.getNumDataElements();
int width = image.getWidth();
int height = image.getHeight();
int pixel,red, green, blue;
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++) {
//scan through each pixel
pixel = image.getRGB(i, j);
red = (pixel >> 16) & 0xff;
green = (pixel >> 8) & 0xff;
blue = (pixel) & 0xff;
//check if R=G=B
if (red != green || green != blue ) {
flag = true;
break;
}
}
回答3:
I think your second option is a reliable and correct method of proving an image is greyscale. Your code has some problems: * you don't break out of the outer loop the way you intended to (look carefully at the second break - I think it should be in the outer loop but NOT the inner loop). * as leonbloy explains in his comment your comparison could be simpler
But if you fix these small problems it should work reliably.
回答4:
Checking R=G=B will tell you if an image is greyscale, thats for sure. But i would be very careful with that approach. You dont know where the images came from. They could be saved with lossy compression or some other strange format. I dont know if formats like jpg actually colorshift greyscale pixels, but that might also be dependant on the compression algorithm (and thus the program used to save the image). Anyway i would suggest you convert images to greyscale by yourself just to be sure. At least for those images that fail the R=G=B test.
For your algorithm i strongly suggest you create a new function for checking R=G=B. This way, if you found a pixel that fails the test you can return false immediately.
public static boolean isGreyscale(BufferedImage image)
{
int pixel,red, green, blue;
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
pixel = image.getRGB(i, j);
red = (pixel >> 16) & 0xff;
green = (pixel >> 8) & 0xff;
blue = (pixel) & 0xff;
if (red != green || green != blue ) return false;
}
}
return true;
}
PS: I just checked the compression colorshift thing. I cant archieve color shifting with pohotohop and jpg format. But its possible to save a greyscale image as gif in such a way, that its not exactly greyscale anymore.
回答5:
The question is : do you want the image itself to be grayscale, or the encoding ?
Your second solution tells you whether the image is grayscale or not, regardless of the encoding (i.e, it returns true even the image could potentially have colors, but just doesn't). It isn't perfect however, one could perfectly imagine a situation where the image is grayscale in some color space different than RGB, and a rounding error makes your test fail. Or a lossy encoding. You should add a margin of error and convert to proper grayscale any image that is close enough.
Your first solution is an imperfect attempt at finding out whether the encoding is grayscale. An image with a color palette of size 255 would also give you elem=1
, and a grayscale image can have elem=2
if it has an alpha channel.
In order to check if your encoding is grayscale, I suggest the following test :
int type = image.getColorModel().getColorSpace().getType();
boolean grayscale = (type==ColorSpace.TYPE_GRAY || type==ColorSpace.CS_GRAY);
To do this, you will need to import the classes ColorModel and ColorSpace from java.awt.image
and java.awt.color
.
You could also investigate whether image.getType()
has value BufferedImage.TYPE_BYTE_GRAY
or BufferedImage.TYPE_USHORT_GRAY
.
回答6:
Here is a very simple way:
- Test the image type
- Test the image number of channels
- Test the pixels values.
Here is the code
boolean isGrayScale(BufferedImage image)
{
// Test the type
if ( image.getType() == BufferedImage.TYPE_BYTE_GRAY ) return true ;
if ( image.getType() == BufferedImage.TYPE_USHORT_GRAY ) return true ;
// Test the number of channels / bands
if ( image.getRaster().getNumBands() == 1 ) return true ; // Single channel => gray scale
// Multi-channels image; then you have to test the color for each pixel.
for (int y=0 ; y < image.getHeight() ; y++)
for (int x=0 ; x < image.getWidth() ; x++)
for (int c=1 ; c < image.getRaster().getNumBands() ; c++)
if ( image.getRaster().getSample(x, y, c-1) != image.getRaster().getSample(x, y, c) ) return false ;
return true ;
}
来源:https://stackoverflow.com/questions/36156543/reliable-way-to-check-if-image-is-grey-scale