HSB 拾色器

HSB Color Picker

对于学校作业,我需要做这样的事情: 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);
}

如有任何帮助,我们将不胜感激。非常感谢!

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

HSB其实比RGB好用。 这是来自维基百科的图表: SharkD,CC BY-SA 3.0 https://creativecommons.org/licenses/by-sa/3.0,来自 Wikimedia Commons

值与亮度相同。 色调通常在 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() and brightness()。对于颜色选择器,您只需要 hue().

要获得光标位置下的颜色,您只需调用 get(x, y),其中 returns 是那些坐标的颜色。

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

  • 左侧完全饱和,右侧不饱和(灰色):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. 您需要在将值设置为 pixels[] 后调用 updatePixels() 来更新

这会 运行 快得多:

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();
}