代码之家  ›  专栏  ›  技术社区  ›  P i

色轮后面的数学是什么

  •  12
  • P i  · 技术社区  · 15 年前

    我想做一个12片的派,每片都有不同的颜色。

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

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

    4 回复  |  直到 8 年前
        1
  •  8
  •   dalton    15 年前

    看一看 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
  •  7
  •   Gareth Rees    15 年前

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

    Mac OS X colour picker

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

        3
  •  3
  •   Visual Vincent    8 年前

    我在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中,保持 中高音 然后击中 11层 + 我 + 米 然后 Ctrl键 + 五 粘贴,和 五楼 去跑。)


    更多信息:

        4
  •  2
  •   dynamichael    9 年前

    如果你想要一个像你提供的例子一样的色轮(和你在工艺商店的油漆部分找到的大多数色轮一样),红色是绿色的对立面,蓝色是黄橙色的对立面,紫色是黄色的对立面,等等,你可以简单地做下面的数学修改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;
    }