【问题标题】:What is the math behind the Colour Wheel色轮背后的数学是什么
【发布时间】:2011-05-13 05:07:55
【问题描述】:

我想创建一个有 12 片的馅饼,每片都有不同的颜色。

几乎每个色轮都遵循相同的格式;例如:http://www.tigercolor.com/color-lab/color-theory/color-theory-intro.htm .

但是有什么算法可以生成颜色呢? RGB(theta) 背后的数学原理是什么?当然,这方面肯定有一些既定的科学,但谷歌没有给我任何线索。

【问题讨论】:

标签: math colors color-picker color-wheel


【解决方案1】:

看看http://www.easyrgb.com,它拥有许多颜色转换背后的算法。这是 RGB -> HSV 之一。

var_R = ( R / 255 )                     //RGB from 0 to 255
var_G = ( G / 255 )
var_B = ( B / 255 )

var_Min = min( var_R, var_G, var_B )    //Min. value of RGB
var_Max = max( var_R, var_G, var_B )    //Max. value of RGB
del_Max = var_Max - var_Min             //Delta RGB value 

V = var_Max

if ( del_Max == 0 )                     //This is a gray, no chroma...
{
   H = 0                                //HSV results from 0 to 1
   S = 0
}
else                                    //Chromatic data...
{
   S = del_Max / var_Max

   del_R = ( ( ( var_Max - var_R ) / 6 ) + ( del_Max / 2 ) ) / del_Max
   del_G = ( ( ( var_Max - var_G ) / 6 ) + ( del_Max / 2 ) ) / del_Max
   del_B = ( ( ( var_Max - var_B ) / 6 ) + ( del_Max / 2 ) ) / del_Max

   if      ( var_R == var_Max ) H = del_B - del_G
   else if ( var_G == var_Max ) H = ( 1 / 3 ) + del_R - del_B
   else if ( var_B == var_Max ) H = ( 2 / 3 ) + del_G - del_R

   if ( H < 0 ) H += 1
   if ( H > 1 ) H -= 1
}

【讨论】:

    【解决方案2】:

    色轮(例如 Mac OS X 颜色选择器,如下图所示)显示 huesaturation(来自HSV colour space 的三个组件中的两个)。色调随角度变化,饱和度随半径变化。通常,(又名亮度)有一个单独的滑块。

    See Wikipedia 了解如何在 HSV 和 RGB 之间来回转换。或者,您选择的编程语言可能有一个 API。例如,Python 有colorsys library

    【讨论】:

      【解决方案3】:

      我正在尝试在 Excel VBA 中制作一个基于 HSL 的色轮,使用微小的单元格作为“像素”,结果非常好,所以我想我会分享。

      这演示了 HSL 和 RGB 之间的转换,以及如何以编程方式在任何网格上绘制线条/圆——甚至是电子表格单元格。

      代码已准备好按原样运行:

      Option Explicit
      
      Const colorSheetName = "COLORS"
      Const pi = 3.14159265358979
      Const squareSize = 3.75             'cell square size (pts)
      Const cDiameter = 80#               'circle diameter (cells)
      Const numAngles = 360#              'number of angles (lines to draw)
      
      Sub CalculateColorWheel()
        Dim ws As Worksheet, radsPerAngle As Double, radius As Long, xStop As Double, _
            yStop As Double, z As Integer, xyLength As Double, lineDot As Long, _ 
            lineLength As Long, h As Byte, s As Byte, v As Byte, r As Byte, g As Byte, b As Byte
      
          Set ws = ThisWorkbook.Sheets.Add                        'create new worksheet
          On Error Resume Next                                    'ignore error 
          Application.DisplayAlerts = False                       'ignore warning
          ThisWorkbook.Sheets(colorSheetName).Delete              'delete worksheet (if exists)
          Application.DisplayAlerts = True                        'stop ignoring warnings
          On Error GoTo 0                                         'stop ignoring errors
      
          With ws
              .Name = colorSheetName                              'name the new sheet
              .Rows.RowHeight = squareSize                        'set rowheight 
              .Columns.ColumnWidth=widthToColumnWidth(squareSize) 'match columnwidth to row
              ActiveWindow.DisplayGridlines = False               'hide gridlines
              ActiveWindow.DisplayHeadings = False                'hide row/col headings
              radius = cDiameter / 2                              'centre point
              lineLength = radius * 1.5                           'dots per angle (line)
              radsPerAngle = (360 / numAngles) * pi / 180         'radians=a(degrees)×pi÷180°
      
              Debug.Print "Grid size=" & .[a1].Height & "×" & .[a1].Width _
                      & ", Diameter:" & cDiameter _
                      & ", Area=" & Round(pi * radius ^ 2, 0) _
                      & ", Circumference=" & Round(2 * pi * radius, 0) _
                      & ", Radians per Angle=" & Round(radsPerAngle, 3) _
                      & " × " & numAngles & " angles"                 'stats
      
              For z = 0 To numAngles - 1  'loop through each angle
                  For lineDot = 1 To lineLength   'loop thru length of line
                      xyLength = radius * (lineDot / lineLength)  'calc dot xy& offset top-left
                      xStop = Int(Cos(radsPerAngle * z) * xyLength) + radius + 2 'x (column)
                      yStop = Int(Sin(radsPerAngle * z) * xyLength) + radius + 2 'y (row)
      
                      If .Cells(yStop, xStop).Interior.Pattern=xlNone Then 'skip colored cells
                          h = ((z + 1) / numAngles) * 255                'hue=angle
                          s = (lineDot / lineLength) * 255                    'saturation=radius
                          v = 255                    'maximum brightness. (Adjustable)
                          HSVtoRGB h, s, v, r, g, b                      'convert HSV to RGB
                          .Cells(yStop, xStop).Interior.Color=rgb(r,g,b) 'color the cell
                          dots = dots + 1
                      End If
                  Next lineDot
                  Application.StatusBar = Format(z / (numAngles - 1), "0%") 
                  DoEvents    'don't lag
              Next z
          End With
          Beep
          Application.StatusBar = "Finished drawing color circle (" & dots & " colors)"
      End Sub
      
      Public Function widthToColumnWidth(pts As Double) As Double
      'convert desired column width (points) to Excel "ColWidthUnits"
      '12pts and under is a 1:12 ratio of (colWidthUnits:Pts).
      ' Over 12pts: 1:12 for 1st unit, then 1:(75/11) for remainder
          Select Case pts
              Case Is <= 0:  widthToColumnWidth = 0
              Case Is <= 12: widthToColumnWidth = pts / 12
              Case Else:     widthToColumnWidth = 1 + (pts - 12) / (75 / 11) '
          End Select
      End Function
      
      Public Sub HSVtoRGB(h As Byte, s As Byte, v As Byte, r As Byte, g As Byte, b As Byte)
          Dim minV As Byte, maxV As Byte, Chroma As Byte, tempH As Double
      
          If v = 0 Then
              r = 0: g = 0: b = 0
          Else
              If s = 0 Then
                  r = v: g = v: b = v:
              Else
                  maxV = v: Chroma = s / 255 * maxV: minV = maxV - Chroma
                  Select Case h
                      Case Is >= 170: tempH = (h - 170) / 43: g = 0
                                      If tempH < 1 Then
                                          b = maxV: r = maxV * tempH
                                      Else: r = maxV: b = maxV * (2 - tempH): End If
                      Case Is >= 85:  tempH = (h - 85) / 43: r = 0
                                      If tempH < 1 Then
                                          g = maxV: b = maxV * tempH
                                      Else: b = maxV: g = maxV * (2 - tempH): End If
                      Case Else:      tempH = h / 43: b = 0
                                      If tempH < 1 Then
                                          r = maxV: g = maxV * tempH
                                      Else: g = maxV: r = maxV * (2 - tempH): End If
                  End Select
                  r = r / maxV * (maxV - minV) + minV
                  g = g / maxV * (maxV - minV) + minV
                  b = b / maxV * (maxV - minV) + minV
              End If
          End If
      End Sub
      

      如何在 Excel 中运行: 将上面的代码粘贴到regular module 中。 (选择代码,Ctrl+C复制,然后在Excel中,按住Alt并点击F11+I+M 然后 Ctrl+V 粘贴,F5 运行。) ?


      更多信息:

      【讨论】:

        【解决方案4】:

        如果您想要一个像您提供的示例一样的色轮(并且像大多数色轮一样,您会在工艺品商店的油漆区找到),其中红色与绿色相对,蓝色与黄橙色相对,紫色与黄色相对等.,您可以简单地进行以下数学运算来修改 HSL 或 HSV 的色调以获得旧色调...

        double ToLegacyHue(double modernHue) {
           modernHue = ((modernHue % 360) + 360) % 360; // normalize 360 > modernHue >= 0
           double ret = 0;
           if(modernHue < 60) {
              ret = modernHue * 2;
           } else if(modernHue < 120) {
              ret = modernHue + 60;
           } else {
              ret = (modernHue - 120) * 0.75 + 180;
           }
           return ret;
        }
        
        double FromLegacyHue(double legacyHue) {
           legacyHue = ((legacyHue % 360) + 360) % 360; // normalize 360 > legacyHue >= 0
           double ret = 0;
           if(legacyHue < 120) {
              ret = legacyHue / 2;
           } else if(legacyHue < 180) {
              ret = legacyHue - 60;
           } else {
              ret = (legacyHue - 180) / 0.75 + 120;
           }
           return ret;
        }
        

        【讨论】:

          【解决方案5】:

          绘制色轮的步骤

          • 用笛卡尔坐标取一点:(x,y)
          • 将笛卡尔坐标转换为极坐标:(x,y) -> (r,theta)
          • 将坐标转换为颜色 = 极坐标为 hsv : (r,theta) -> (h,s,v)

          在哪里:

          • theta = 色相
          • 半径 r = 饱和度
          • 值为常量

          这是toolnice examples

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-02-15
            • 2019-01-04
            • 1970-01-01
            • 2012-03-31
            • 2012-05-04
            • 2021-02-15
            • 1970-01-01
            相关资源
            最近更新 更多