Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Java中创建X%的灰色?_Java_Rgb_Color Space_Hsb - Fatal编程技术网

如何在Java中创建X%的灰色?

如何在Java中创建X%的灰色?,java,rgb,color-space,hsb,Java,Rgb,Color Space,Hsb,假设我想要Java中25%或31%的灰色 下面的代码显示 BufferedImage image = new BufferedImage(2, 2, BufferedImage.TYPE_BYTE_GRAY); image.setRGB(0, 0, new Color(0,0,0).getRGB()); image.setRGB(1, 0, new Color(50, 50, 50).getRGB()); image.setRGB(0, 1, new Color

假设我想要Java中25%或31%的灰色

下面的代码显示

    BufferedImage image = new BufferedImage(2, 2, BufferedImage.TYPE_BYTE_GRAY);

    image.setRGB(0, 0, new Color(0,0,0).getRGB());
    image.setRGB(1, 0, new Color(50, 50, 50).getRGB());
    image.setRGB(0, 1, new Color(100,100,100).getRGB());
    image.setRGB(1, 1, new Color(255,255,255).getRGB());

    Raster raster = image.getData();
    double[] data = raster.getPixels(0, 0, raster.getWidth(), raster.getHeight(), (double[]) null);

    System.out.println(Arrays.toString(data));
显然,RGC与密度(?)非线性有关

[0.0, 8.0, 32.0, 255.0]
那么,如何创建给定密度的颜色呢

更新

我尝试过@icza和@hlg提出的方法,我还发现了另一种方法:

    double[] data;
    Raster raster;
    BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY);

    float[] grays = {0, 0.25f, 0.5f, 0.75f, 1};

    ColorSpace linearRGB = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
    ColorSpace GRAY = ColorSpace.getInstance(ColorSpace.CS_GRAY);

    Color color;
    int[] rgb;

    for(int i=0; i<grays.length; ++i) {

        System.out.println("\n\nShould be " + (grays[i]*100) + "% gray");

        color = new Color(linearRGB, new float[] {grays[i], grays[i], grays[i]}, 1f);

        image.setRGB(0, 0, color.getRGB());
        raster = image.getData();
        data = raster.getPixels(0, 0, 1, 1, (double[]) null);

        System.out.println("data by CS_LINEAR_RGB (hlg method) = " + Arrays.toString(data));

        color = new Color(GRAY, new float[] {grays[i]}, 1f);

        image.setRGB(0, 0, color.getRGB());
        raster = image.getData();
        data = raster.getPixels(0, 0, 1, 1, (double[]) null);

        System.out.println("data by CS_GRAY = " + Arrays.toString(data));

        rgb = getRGB(Math.round(grays[i]*255));

        color = new Color(rgb[0], rgb[1], rgb[2]);

        image.setRGB(0, 0, color.getRGB());
        raster = image.getData();
        data = raster.getPixels(0, 0, 1, 1, (double[]) null);

        System.out.println("data by icza method = " + Arrays.toString(data));

    }
现在我想知道哪一个是正确的

更新2


对不起,灰/白百分比当然应该颠倒。

将RGB颜色转换为灰度时,使用以下权重:

0.2989,0.5870,0.1140

资料来源:

在维基百科上:

正式地说:

gray = 0.2989*R + 0.5870*G + 0.1140*B
基本上你需要的是这个函数的倒数。您需要找到R、G和B值,这些值给出了您要查找的结果
灰色
值。由于方程中有3个参数,因此在大多数情况下,会有大量RGB值,这将导致您要查找的
灰度值

试想一下:一个具有高R分量的RGB颜色,并且G和B中没有一个给出灰色,可能存在另一个具有某些G分量的RGB颜色,并且R和B中没有一个给出相同的灰色,因此有多种可能的RGB解决方案可用于所需的灰色

算法 这里有一个可能的解决方案。它所做的是尝试将第一个RGB组件设置为同样大,因此乘以其权重将返回
灰色
。如果其“溢出”超过255,则会被切割,我们使用组件的最大值可以“表示”的量减少
灰色
,并尝试使用剩余的
灰色
量对下一个组件执行此操作

这里我使用了
灰色
输入范围
0..255
。如果要以百分比为单位指定,只需将其转换为
gray=255*percent/100

private static double[] WEIGHTS = { 0.2989, 0.5870, 0.1140 };

public static int[] getRGB(int gray) {
    int[] rgb = new int[3];

    for (int i = 0; i < 3; i++) {
        rgb[i] = (int) (gray / WEIGHTS[i]);
        if (rgb[i] < 256)
            return rgb; // Successfully "distributed" all of gray, return it

        // Not quite there, cut it...
        rgb[i] = 255;
        // And distribute the remaining on the rest of the RGB components:
        gray -= (int) (255 * WEIGHTS[i]);
    }

    return rgb;
}

结果显示了基于该算法我们所期望的结果:R分量首先是“填充”的,一旦达到255,G分量将被“填充”,最后G分量将被使用。

一种颜色有一个特定的亮度,如果颜色更灰,您希望保留该亮度

亮度可能类似于:

Y = 0.2989*R + 0.5870*G + 0.1140*B
Y = 0.2126*R + 0.7152*G + 0.0722*B
因此,
新颜色(Y,Y,Y)
对应于具有相同亮度的灰度值。 灰显到特定百分比是一种插值

Color grayed(Color color, int perc) {
    double percGrayed = perc / 100.0;
    double percColored = 1.0 - percGrayed;

    double[] weights = { 0.2989, 0.5870, 0.1140 };
    double[] rgb = { color.getR(), color.getG(), color.getB() };

    // Determine luminance:
    double y = 0.0;
    for (int i = 0; i < 3; ++i) {
        y += weights[i] * rgb[i];
    }

    // Interpolate between (R, G, B) and (Y, Y, Y):
    for (int i = 0; i < 3; ++i) {
        rgb[i] *= percColoured;
        rgb[i] += y * percGrayed;
    }

    return new Color((int)rgb[0], (int)rgb[1], (int)rgb[2]);
}

Color grayedColor = grayed(color, 30); // 30% grayed.
颜色灰显(颜色,int perc){
双PERCGREED=perc/100.0;
双过彩色=1.0-过灰色;
双[]权重={0.2989,0.5870,0.1140};
double[]rgb={color.getR(),color.getG(),color.getB()};
//确定亮度:
双y=0.0;
对于(int i=0;i<3;++i){
y+=权重[i]*rgb[i];
}
//在(R,G,B)和(Y,Y,Y)之间插值:
对于(int i=0;i<3;++i){
rgb[i]*=1;
rgb[i]+=y*灰色;
}
返回新颜色((int)rgb[0],(int)rgb[1],(int)rgb[2]);
}
颜色灰色=灰色(颜色,30);//30%为灰色。

巨大的差异是由于sRGB()中的gamma编码造成的。sRGB是
color
构造函数中使用的默认颜色空间。如果改用线性RGB颜色空间设置颜色,则灰色值不会失真:

ColorSpace linearRGB = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
Color grey50 = new Color(linearRGB, new float[]{50f/255,50f/255,50f/255}, 1f);
Color grey100 = new Color(linearRGB, new float[]{100f/255,100f/255,100f/255}, 1f);
Color grey255 = new Color(linearRGB, new float[]{1f,1f,1f}, 1f);
但是,当使用
Color.getRGB
ImageBuffer.setRGB
设置像素时,线性灰度值将转换为sRGB并返回。因此,它们是伽马编码和解码的,根据所选的颜色空间产生舍入误差

通过直接在灰度颜色模型后面设置原始像素数据,可以避免这些错误:

WritableRaster writable = image.getRaster();
writable.setPixel(0,0, new int[]{64});

请注意,您必须对百分比值进行四舍五入,例如,对于25%,您不能存储
63.75
。如果需要更高的精度,请使用
TYPE\u USHORT\u GRAY
而不是
TYPE\u BYTE\u GRAY

+1。这个问题实际上是放在MathOverflow上进行反向函数计算。在问题示例中,我们有R=G=B,因此权重应该是无关的。+1。我想我误解了什么。这应该是公认的答案。但是请注意,您使用整数除法的结果初始化
浮点
数组,因此,例如
50/255
100/255
将全部为零!使用
50f/255
100f/255
正确获取
float
数字。在某些舍入误差范围内,
CS\u LINEAR\u RGB
CS\u GRAY
方法都给出了正确的结果。是否可以修复舍入误差,使100%的结果为255?
Y = 0.2989*R + 0.5870*G + 0.1140*B
Y = 0.2126*R + 0.7152*G + 0.0722*B
Color grayed(Color color, int perc) {
    double percGrayed = perc / 100.0;
    double percColored = 1.0 - percGrayed;

    double[] weights = { 0.2989, 0.5870, 0.1140 };
    double[] rgb = { color.getR(), color.getG(), color.getB() };

    // Determine luminance:
    double y = 0.0;
    for (int i = 0; i < 3; ++i) {
        y += weights[i] * rgb[i];
    }

    // Interpolate between (R, G, B) and (Y, Y, Y):
    for (int i = 0; i < 3; ++i) {
        rgb[i] *= percColoured;
        rgb[i] += y * percGrayed;
    }

    return new Color((int)rgb[0], (int)rgb[1], (int)rgb[2]);
}

Color grayedColor = grayed(color, 30); // 30% grayed.
ColorSpace linearRGB = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
Color grey50 = new Color(linearRGB, new float[]{50f/255,50f/255,50f/255}, 1f);
Color grey100 = new Color(linearRGB, new float[]{100f/255,100f/255,100f/255}, 1f);
Color grey255 = new Color(linearRGB, new float[]{1f,1f,1f}, 1f);
WritableRaster writable = image.getRaster();
writable.setPixel(0,0, new int[]{64});