检查图像是否为灰度的可靠方法
Reliable way to check if image is Grey scale
我目前正在处理一个用例,我需要确定上传的图像是灰度还是 RGB。我找到了几种方法来识别这一点,但不确定它们是否可靠并且可以共同用于确认图像是否为灰度。
第 1 部分:读取图像并使用栅格获取 NumberDataElements。
BufferedImage image = ImageIO.read(file);
Raster ras = image.getRaster();
int elem = ras.getNumDataElements();
我观察到 elem 的值在某些情况下为“1”,但在所有情况下都不是。
第 2 部分:检查每个像素的 RGB 值。如果给定像素的 R、G、B 值相同。
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;
}
}
我在这里检查任何给定像素的 R、G、B 值是否相同,并且此行为在所有像素中都是一致的。
我正在使用这两种方法,但不确定它们的准确性。
求推荐..
我认为您的第二个选项是证明图像是灰度的可靠且正确的方法。
您的代码有一些问题:
* 你没有按照你想要的方式跳出外循环(仔细看第二个中断 - 我认为它应该在外循环而不是内循环)。
* 正如 leonbloy 在他的评论中解释的那样,您的比较可能会更简单
但如果您解决了这些小问题,它应该可以可靠地工作。
将 if (flag) { break; }
行移到内部 for 循环之外。
而您只需要检查 (red != green || green != blue)
。打破这两个等式中的任何一个确保第三个必须被打破,所以你只需要两次检查。
我也可能只是将布尔值的 isGrayscale 变量设置为 true,然后在等式逻辑中断时将其设置为 false,而不是将标志设置为 true。应该假设它是灰度的,直到它破裂并变成假的。你这里的标志没有问题,但这更有意义和直观。
如果你想变得非常聪明,你可以考虑方差增量,以允许图像足够灰度以达到目的,即它们与平等的偏差低于设定的障碍。但这按原样工作:)
检查 R=G=B 将告诉您图像是否为灰度,这是肯定的。但我会非常小心这种方法。你不知道图像来自哪里。它们可以用有损压缩或其他一些奇怪的格式保存。我不知道像 jpg 这样的格式是否真的会改变灰度像素的颜色,但这也可能取决于压缩算法(以及用于保存图像的程序)。无论如何,我建议您自己将图像转换为灰度,以确保万无一失。至少对于那些未通过 R=G=B 测试的图像。
对于您的算法,我强烈建议您创建一个新函数来检查 R=G=B。这样,如果您发现一个像素未通过测试,您可以立即 return false。
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:我刚刚检查了压缩色移的东西。我无法使用 pohotohop 和 jpg 格式实现颜色偏移。但是可以通过这种方式将灰度图像保存为 gif,它不再完全是灰度了。
问题是:你希望图像本身是灰度的还是编码的?
你的第二个解决方案告诉你图像是否是灰度的,不管编码如何(即,它 returns 正确即使图像可能有颜色,但只是没有)。然而,它并不完美,人们可以完美地想象这样一种情况,即图像是某种颜色 space 与 RGB 不同的灰度图像,并且舍入误差会使您的测试失败。或有损编码。您应该添加误差范围并将任何足够接近的图像转换为适当的灰度。
您的第一个解决方案是尝试找出编码是否为灰度的不完美尝试。调色板大小为 255 的图像也会给你 elem=1
,如果灰度图像有 alpha 通道,它可以有 elem=2
。
为了检查您的编码是否为灰度,我建议进行以下测试:
int type = image.getColorModel().getColorSpace().getType();
boolean grayscale = (type==ColorSpace.TYPE_GRAY || type==ColorSpace.CS_GRAY);
为此,您需要从 java.awt.image
和 java.awt.color
.
导入 类 ColorModel 和 ColorSpace
您还可以调查 image.getType()
是否具有值 BufferedImage.TYPE_BYTE_GRAY
或 BufferedImage.TYPE_USHORT_GRAY
。
这是一个非常简单的方法:
- 测试图片类型
- 测试图像通道数
- 测试像素值。
这是代码
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 ;
}
以下方法对我有用。谢谢大家的帮助。
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;
}
}
我目前正在处理一个用例,我需要确定上传的图像是灰度还是 RGB。我找到了几种方法来识别这一点,但不确定它们是否可靠并且可以共同用于确认图像是否为灰度。
第 1 部分:读取图像并使用栅格获取 NumberDataElements。
BufferedImage image = ImageIO.read(file);
Raster ras = image.getRaster();
int elem = ras.getNumDataElements();
我观察到 elem 的值在某些情况下为“1”,但在所有情况下都不是。
第 2 部分:检查每个像素的 RGB 值。如果给定像素的 R、G、B 值相同。
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;
}
}
我在这里检查任何给定像素的 R、G、B 值是否相同,并且此行为在所有像素中都是一致的。
我正在使用这两种方法,但不确定它们的准确性。 求推荐..
我认为您的第二个选项是证明图像是灰度的可靠且正确的方法。 您的代码有一些问题: * 你没有按照你想要的方式跳出外循环(仔细看第二个中断 - 我认为它应该在外循环而不是内循环)。 * 正如 leonbloy 在他的评论中解释的那样,您的比较可能会更简单
但如果您解决了这些小问题,它应该可以可靠地工作。
将 if (flag) { break; }
行移到内部 for 循环之外。
而您只需要检查 (red != green || green != blue)
。打破这两个等式中的任何一个确保第三个必须被打破,所以你只需要两次检查。
我也可能只是将布尔值的 isGrayscale 变量设置为 true,然后在等式逻辑中断时将其设置为 false,而不是将标志设置为 true。应该假设它是灰度的,直到它破裂并变成假的。你这里的标志没有问题,但这更有意义和直观。
如果你想变得非常聪明,你可以考虑方差增量,以允许图像足够灰度以达到目的,即它们与平等的偏差低于设定的障碍。但这按原样工作:)
检查 R=G=B 将告诉您图像是否为灰度,这是肯定的。但我会非常小心这种方法。你不知道图像来自哪里。它们可以用有损压缩或其他一些奇怪的格式保存。我不知道像 jpg 这样的格式是否真的会改变灰度像素的颜色,但这也可能取决于压缩算法(以及用于保存图像的程序)。无论如何,我建议您自己将图像转换为灰度,以确保万无一失。至少对于那些未通过 R=G=B 测试的图像。
对于您的算法,我强烈建议您创建一个新函数来检查 R=G=B。这样,如果您发现一个像素未通过测试,您可以立即 return false。
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:我刚刚检查了压缩色移的东西。我无法使用 pohotohop 和 jpg 格式实现颜色偏移。但是可以通过这种方式将灰度图像保存为 gif,它不再完全是灰度了。
问题是:你希望图像本身是灰度的还是编码的?
你的第二个解决方案告诉你图像是否是灰度的,不管编码如何(即,它 returns 正确即使图像可能有颜色,但只是没有)。然而,它并不完美,人们可以完美地想象这样一种情况,即图像是某种颜色 space 与 RGB 不同的灰度图像,并且舍入误差会使您的测试失败。或有损编码。您应该添加误差范围并将任何足够接近的图像转换为适当的灰度。
您的第一个解决方案是尝试找出编码是否为灰度的不完美尝试。调色板大小为 255 的图像也会给你 elem=1
,如果灰度图像有 alpha 通道,它可以有 elem=2
。
为了检查您的编码是否为灰度,我建议进行以下测试:
int type = image.getColorModel().getColorSpace().getType();
boolean grayscale = (type==ColorSpace.TYPE_GRAY || type==ColorSpace.CS_GRAY);
为此,您需要从 java.awt.image
和 java.awt.color
.
您还可以调查 image.getType()
是否具有值 BufferedImage.TYPE_BYTE_GRAY
或 BufferedImage.TYPE_USHORT_GRAY
。
这是一个非常简单的方法:
- 测试图片类型
- 测试图像通道数
- 测试像素值。
这是代码
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 ;
}
以下方法对我有用。谢谢大家的帮助。
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;
}
}