如何在特定范围内生成随机颜色?

Kin*_*oad 0 java colors

我环顾了不同的来源:

但是,这些答案都不是我正在寻找的。

我想要做的是获得 2 种颜色范围内的随机颜色,例如紫色和粉红色。对于紫色#6A0DAD和粉红色#FFC0CB,我想在这两种颜色的范围内抓取一种颜色,但要随机一种。所以我会得到例如#D982B5,这是品红色粉红色。

到目前为止,除了制作随机数之外,我不知道从哪里开始。

aku*_*ykh 5

Tl;博士:

没那么简单。颜色是您看到可见光时的感知。形成颜色的是不同波长的光。为了用数字表示颜色,我们使用不同的颜色空间,例如 RGB、CMYK、YCbCr 等。所有这些颜色空间都进行了简化以表示物理(或生物)属性。

当你说“颜色之间”时,它可能意味着很多东西:两个波长之间的波长。甲色调它是其他两个色相之间在一个特定的色彩空间。根据您的经验和感知,您“期望”介于两种颜色之间的颜色。由两种颜色混合产生的颜色。要混合颜色,一个好的方法是使用加法混合,但在颜色空间中。但是,就“介于两者之间的颜色”而言,这可能有缺陷,具体取决于您想要什么。

以下是一些值得阅读的相关帖子:


更长的版本:

想到的第一件事是简单地采用两种颜色的 RGB 中的每个通道,并在相应通道的值之间生成一个随机值:例如,您采用颜色#6A0DAD#FFC0CB。红色通道的值为106255。因此,新颜色的红色通道的值将是106和之间的数字255。这种幼稚的方法有一个问题:#6A0DAD紫色和#FFC0CB粉红色之间的数字的结果可能#6AC0AD是汽油色。汽油绝对不是您认为“介于紫色和粉红色之间”的颜色。

其原因是 RGB 颜色空间具有由所有三个通道表示的颜色的色调:构成色调的通道的平衡。当我们为新颜色的每个通道生成相应范围内的随机数时,生成的颜色的色调可能完全不同,因为它可能是由完全不同的通道平衡造成的。

另一种方法是将我们正在使用的色彩空间更改为通过单个通道表示色调的色彩空间。一种这样的色彩空间是HSL/HSV。我们要做的是:将两个数字都转换为等效的 HSB。然后像我们在 RGB 中所做的那样为每个通道生成随机数。请注意,通道的平衡并不重要,因为色调由单个通道表示。然后获取结果并将其转换回RGB。

这里有一个简单的 Java 演示:

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JLabel;

class Main {
    
    
    static int[] purple = {106, 13, 173};
    static int[] pink = {255, 192, 203};
    
    
    static float randomBetween(float a, float b) {
        float min = Math.min(a, b);
        float max = Math.max(a, b);
        return min + (max - min) * (float) Math.random();
    }
    
    
    static Color colorBetween(int[] a, int[] b) {
        float[] a_hsb = Color.RGBtoHSB(a[0], a[1], a[2], null);
        float[] b_hsb = Color.RGBtoHSB(b[0], b[1], b[2], null);
        float[] between_hsb = {
                randomBetween(a_hsb[0], b_hsb[0]),
                randomBetween(a_hsb[1], b_hsb[1]),
                randomBetween(a_hsb[2], b_hsb[2])
        };
        return new Color(
                Color.HSBtoRGB(
                        between_hsb[0],
                        between_hsb[1],
                        between_hsb[2]));
    }
    
    
    public static void main(String args[]) {
        Color purple_color = new Color(purple[0], purple[1], purple[2]);
        Color pink_color = new Color(pink[0], pink[1], pink[2]);
        Color between_color = colorBetween(purple, pink);
        
        JFrame frame = new JFrame();
        GridLayout layout = new GridLayout(2, 2);
        frame.setLayout(layout);
        
        JLabel purple_label = new JLabel();
        purple_label.setBackground(purple_color);
        purple_label.setOpaque(true);
        frame.add(purple_label);
        
        JLabel pink_label = new JLabel();
        pink_label.setBackground(pink_color);
        pink_label.setOpaque(true);
        frame.add(pink_label);
        
        JLabel between_label = new JLabel();
        between_label.setBackground(between_color);
        between_label.setOpaque(true);
        frame.add(between_label);
        
        frame.addMouseListener(new MouseAdapter() {  
            public void mouseClicked(MouseEvent e) {  
               between_label.setBackground(colorBetween(purple, pink));
            }  
        }); 
        
        frame.setSize(1000, 1000);
        frame.setVisible(true);
    }
}

Run Code Online (Sandbox Code Playgroud)

单击框架以重新创建新颜色。左上角是紫色,右上角是粉红色,结果在左下角。

一种 乙

正如您应该看到的,结果绝对是一种您至少会称之为“在同一调色板中”的颜色。但这仍然存在一个问题:我们也在调整 HSB 中的亮度和饱和度。我们最初拥有的粉红色饱和度非常低,但紫色的饱和度非常高。问题是结果可能是相同的粉红色但高度饱和,看起来很红。它“看起来”不对。

另一种方法可能是回到 RGB 并尊重通道的平衡。事实上,这并不是什么新鲜事。这称为混合,这是渲染以显示透明度的常用技术。

这是相同的演示,但使用了调整后的colorBetween方法:

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JLabel;

class Main {
    
    
    static int[] purple = {106, 13, 173};
    static int[] pink = {255, 192, 203};
    
    
    static Color colorBetween(int[] a, int[] b) {
        double c_a = Math.random();
        double c_b = 1.0 - c_a;
        
        int[] blend = {
                (int) (c_a * a[0] + c_b * b[0]),
                (int) (c_a * a[1] + c_b * b[1]),
                (int) (c_a * a[2] + c_b * b[2]),
        };
        
        return new Color(blend[0], blend[1], blend[2]);
    }
    
    
    public static void main(String args[]) {
        Color purple_color = new Color(purple[0], purple[1], purple[2]);
        Color pink_color = new Color(pink[0], pink[1], pink[2]);
        Color between_color = colorBetween(purple, pink);
        
        JFrame frame = new JFrame();
        GridLayout layout = new GridLayout(2, 2);
        frame.setLayout(layout);
        
        JLabel purple_label = new JLabel();
        purple_label.setBackground(purple_color);
        purple_label.setOpaque(true);
        frame.add(purple_label);
        
        JLabel pink_label = new JLabel();
        pink_label.setBackground(pink_color);
        pink_label.setOpaque(true);
        frame.add(pink_label);
        
        JLabel between_label = new JLabel();
        between_label.setBackground(between_color);
        between_label.setOpaque(true);
        frame.add(between_label);
        
        frame.addMouseListener(new MouseAdapter() {  
            public void mouseClicked(MouseEvent e) {  
               between_label.setBackground(colorBetween(purple, pink));
            }  
        }); 
        
        frame.setSize(1000, 1000);
        frame.setVisible(true);
    }
}

Run Code Online (Sandbox Code Playgroud)

C

请注意,结果不再是“似乎错误”的高度饱和的粉红色。你要做的只是使用随机因素c_a是之间0.01.0与一个因素c_b1.0 - c_a。你乘每种颜色的通道a通过c_a,做相同的b,并c_b和添加的结果。这是按常数因子对颜色进行简单缩放,其效果是通道的平衡不变。加入结果后,你有一个新的色彩平衡是一个融合ab

另一种方法是减法方法:将每个颜色通道a乘以相应的颜色通道b并除以255

或者另一种加法方法:将通道相加,如果是<= 255,则将其作为结果,否则将255

... 等等等等 ...

请注意,当最初的两种颜色彼此接近时,所有这些方法都相对有效。在其他一些情况下它变得越来越困难:红色(255, 0, 0)、 和青色(0, 255, 255)、 是互补色。加法方法将导致白色。减法方法将导致黑色。对于“中间”颜色,让我们看一下色调(来自维基百科的 HSB/HSL 图像):

色调

您可以看到红色在左侧右侧。当我们想要选择介于两者之间的色调时,颜色空间所做的简化现在很麻烦。我们是选择 0° 和 180° 之间的颜色还是选择 180° 和 360° 之间的颜色?我展示的第一个示例将从下半部分选择一种颜色。您可以很好地理解为什么两种颜色接近另一种颜色会产生好的结果而远离另一种颜色会产生不好的结果。

一个完美的例子:(255, 0, 0)and (255, 0, 50),红色和粉红色,将产生任何颜色:绿色、蓝色、黄色等。您可以做的就是查看距离并在需要时添加 360°。例如a,色相为 10° 的颜色b和色相为 350° 的颜色将变为a370° 和b350° 的颜色。在这个范围模 360 中随机选取的色调是新颜色的色调。

我的建议是使用混合方法,因为它产生了一种加法方法的结果,它更接近可见光的工作原理,并且不会像其他一些方法那样不成比例地增加亮度。