首页 > 解决方案 > HSB 颜色选择器

问题描述

对于学校作业,我需要做这样的事情: 汇丰银行 500x500 的矩形应该显示鼠标指向的任何颜色的不同色调、饱和度和亮度,有点像拾色器。

但是因为我在编码方面很烂,我不知道该怎么做。我不太了解HSB。这是我的代码和我现在拥有的图片。 党卫军

void setup() {
  size(500,550);
}

void draw() {
 noStroke();
 colorMode(HSB, 100);
 for (int i = 0; i < 500; i++) {
  for (int j = 0; j < 50; j++) {
   int h = i-200;
   int s = j+500;
   int b = 500 + j;
    stroke(h,s,b);
    point(i, j);
  }
}
noStroke();
fill(mouseX, mouseY);
rect(0,50,500,500);
}

任何帮助,将不胜感激。非常感谢!

标签: colorsprocessinggradientcolor-pickerhsb

解决方案


你在colorMode(HSB)渲染彩虹方面已经做得很好了。我会移动嵌套的 for 循环以使其更高效:它会渲染一次并留在那里,因为您没有调用background()并且rect(0,50,500,500);低于彩虹渐变。

HSB 实际上比 RGB 更容易使用。这是来自维基百科的图表: HSV 彩色压花机 SharkD,CC BY-SA 3.0 https://creativecommons.org/licenses/by-sa/3.0,来自维基共享资源

值与亮度相同。色调通常在 0-360 度范围内,因此图片以彩虹圈的形式出现,从红色开始到红色结束。假设你从红色开始,0 度色相,你知道黄色是 60 度色相。直觉上,你会在 30 度时发现介于红色和黄色之间的橙色。事实上,如果您每 60 度转一次,您将通过红色、黄色、绿色、青色、蓝色、品红色,然后在 360/0 时返回红色。

饱和度和亮度通常在 0-100% 之间。请注意,上图中的饱和度远离中心增加:0 饱和度 = 灰色,100% 饱和度 = 全色调。

图中亮度从下到上增加。

您将色调、饱和度和亮度映射到 0-100 范围有点奇怪。也许目的是通过将色调也视为百分比来简化事情。

可以使事情变得更容易的一件事是map()功能。它将一个数字从一个范围映射到另一个范围。

例如,这段代码试图将 i、j 位置重新映射到色调和饱和度。

  • i, j在 0-500、0-50 范围内(x、y 位置)
  • 上图显示了具有相同饱和度和亮度的彩虹渐变,因此可以保持不变:
  • 简单地i0-499范围0-100映射到映射到色调

例如:

void setup() {
  size(500, 550);
  
  colorMode(HSB, 100);
  for (int i = 0; i < 500; i++) {
    for (int j = 0; j < 50; j++) {
      // remap i (x -> width) to 0 - 100 range for hue
      // since map returns a float, round helps make that an int
      int h = round(map(i, 0, 499, 0, 100));
      int s = 100;
      int b = 100; 
      stroke(h, s, b);
      point(i, j);
    }
  }
  
  noStroke();
  
}

void draw() {
  fill(map(mouseX, 0, width, 0, 100), map(mouseY, 0, height, 0, 100), 100);
  rect(0, 50, 500, 500);
}

在这种特殊情况下,0-500 到 0-50 的范围是微不足道的:500 / 100 = 5,因此:

int h = i / 5;

会得到与 相同的结果int h = round(map(i, 0, 499, 0, 100));,只是不必过多考虑算术。

在嵌套的 for 循环中,您正在设置 HSB 颜色。对于下一部分,您需要获取/读取 HSB 颜色,幸运的是,Processing 已经为您提供了hue()saturation()brightness()。对于颜色选择器,您只需要hue().

要获取光标位置下的颜色,您只需调用get(x, y)它返回那些坐标的颜色。

如果您查看渐变图像,您会注意到:

  • 左侧完全饱和,右侧去饱和(灰色):x轴必须映射饱和度
  • 顶部是亮的,底部是暗的:y 轴必须映射亮度

如果您阅读了hue()鼠标单击顶部彩虹渐变时的内容,则可以通过简单地将 x,y 坐标映射到饱和度和亮度来制作更大的渐变波纹管:

float hue;

void setup() {
  size(500, 550);
  
  colorMode(HSB, 100);
  for (int i = 0; i < 500; i++) {
    for (int j = 0; j < 50; j++) {
      // remap i (x -> width) to 0 - 100 range for hue
      // since map returns a float, round helps make that an int
      int h = round(map(i, 0, 499, 0, 100));
      int s = 100;
      int b = 100; 
      stroke(h, s, b);
      point(i, j);
    }
  }
  
  noStroke();
  
}

void draw() {
  // pick colour (hue)
  if(mousePressed){
    // check if the mouse was pressed on the top side only
    if((mouseX >= 0 && mouseX <= 500) &&
       (mouseY >= 0 && mouseY <= 50)){
      hue = hue(get(mouseX, mouseY));  
    }
  }
  // render saturation , brightness mapping
  for (int i = 0; i < 500; i++) {
    for (int j = 50; j < 550; j++) {
      int saturation = round(map(i, 0, 500, 100, 0));
      // swap output mapping range: brightness goes up when y decreases
      int brightness = round(map(j, 50, 550, 100, 0));
      stroke(hue, saturation, brightness);
      point(i, j);
    }
  }
}

你会注意到这运行有点慢。使用pixels[]. 但是有一些曲线球:

  1. 您需要先调用loadPixels()才能读取像素
  2. 您需要将 x,y 位置转换为一维数组索引:index = x + y * width
  3. 您需要updatePixels()在设置值后调用pixels[]以更新

这将运行得更快:

float hue;

void setup() {
  size(500, 550);
  
  colorMode(HSB, 100);
  for (int i = 0; i < 500; i++) {
    for (int j = 0; j < 50; j++) {
      // remap i (x -> width) to 0 - 100 range for hue
      // since map returns a float, round helps make that an int
      int h = round(map(i, 0, 499, 0, 100));
      int s = 100;
      int b = 100; 
      stroke(h, s, b);
      point(i, j);
    }
  }
  
  noStroke();
  
}

void draw() {
  // make latest pixels[] data available 
  loadPixels();
  // pick colour (hue)
  if(mousePressed){
    // check if the mouse was pressed on the top side only
    if((mouseX >= 0 && mouseX <= 500) &&
       (mouseY >= 0 && mouseY <= 50)){
      //hue = hue(get(mouseX, mouseY));
      hue = hue(pixels[mouseX + mouseY * width]);
    }
  }
  // render saturation , brightness mapping
  for (int i = 0; i < 500; i++) {
    for (int j = 50; j < 550; j++) {
      int saturation = round(map(i, 0, 500, 100, 0));
      // swap output mapping range: brightness goes up when y decreases
      int brightness = round(map(j, 50, 550, 100, 0));
      //stroke(hue, saturation, brightness);
      //point(i, j);
      pixels[i + j * width] = color(hue, saturation, brightness);
    }
  }
  // update
  updatePixels();
}

推荐阅读