Giá trị HSL đến RGB


17

Mục đích chính của mô hình màu RGB (Red Green Blue) là để cảm biến, đại diện và hiển thị hình ảnh trong các hệ thống điện tử, chẳng hạn như TV và máy tính

HSL (Hue Saturation Lightness) là một mô hình màu thay thế, được thiết kế vào những năm 1970 bởi các nhà nghiên cứu đồ họa máy tính để phù hợp chặt chẽ hơn với cách nhìn của con người về các thuộc tính tạo màu

Dưới đây là các bài viết wiki cho RGBHSL . Thông thường các chương trình đồ họa thực hiện các phép tính trong HSL và sau đó chuyển đổi sang định dạng ưa thích cho hầu hết các màn hình: RGB.

Nhiệm vụ là viết một hàm / chương trình lấy HSL làm đầu vào và đầu ra RGB.

Bạn có thể chọn đại diện ưa thích của mình cho I / O, miễn là nó phù hợp giữa chúng.

Ví dụ: chúng có thể là một mảng / tuple với 3 phần tử hoặc một đối tượng có 3 thuộc tính được đặt tên h, sl, nhưng tôi sẽ chấp nhận các biến thể thông minh khác, như nhận hsl dưới dạng một số nguyên (mất độ chính xác) và xuất ra một số nguyên rgb.

Đầu vào có thể được coi là an toàn trong phạm vi và định dạng, cả hai đều có thể quyết định. Tôi thực sự đề nghị hoặc các phạm vi 0-1 0-1 0-1hoặc 0-360 0-100 0-100cho hsl, 0-1 0-1 0-1hoặc 0-255 0-255 0-255cho rgb.

Mỗi câu trả lời là bắt buộc để chỉ định cả hai câu hỏi trên và không đặt nhiều biến thể khác nhau trong câu trả lời của bạn nếu bạn đặc biệt tự hào về chúng, ngay cả khi chúng không có ít ký tự hơn các biến thể khác của bạn. Đặt nhỏ nhất lên trên.

Các trường hợp thử nghiệm giả cho 0-360 0-100 0-1000-255 0-255 0-255

h   s   l   → r   g   b

0   0   0   → 0   0   0
90  56  17  → 43  68  19
202 19  39  → 81  104 118
72  55  26  → 88  103 30

Các công thức cho việc chuyển đổi có thể được tìm thấy ở đây :

Đây là một cách hay để hình dung chuyển đổi:


Phạm vi đề nghị của bạn cho Hcác 0-360[0,360), nó sẽ được viết tốt hơn như 0-359?
Jonathan Allan

3
@Jonathan ALLan Tôi nghĩ rằng nó có thể trông hơi khó hiểu hơn, đối với tôi, điều đó cho thấy rằng 395.1 không phải là một đầu vào có thể. Nếu bất cứ điều gì, việc sử dụng a-bký hiệu là sai khi tự xử lý các giá trị không nguyên, nhưng tôi nói rằng bạn có thể giữ câu hỏi dễ đọc hơn. Nếu có ai phàn nàn, tôi sẽ suy nghĩ lại, vì vậy cảm ơn bạn đã chỉ ra điều đó
kéo theo

Vâng, đã đồng ý về điểm 359,1 - có thể chỉ cần sử dụng ký hiệu chuẩn [0,360)sau đó :)
Jonathan Allan

ngạc nhiên khi thấy không có câu trả lời glsl;)
kéo theo

Câu trả lời:


8

JavaScript (ES6), 98 95 94 byte

Đưa H vào [0,360)S / L trong [0,1) . Kết quả R , GB là một mảng gồm 3 số float trong [0,1) .

(H,S,L)=>[5,3,1].map(i=>A(L*2)*S*([1,Y,0,0,Y,1][(i-~H)%6]-.5)+L,Y=(A=n=>n>1?2-n:n)((H/=60)%2))

Các trường hợp thử nghiệm

Đoạn mã này chuyển đổi kết quả trở lại thành [0,255] .

Làm sao?

Mã khởi tạo

Y = (                  // we compute Y = 1 - |(H/60) mod 2 - 1| = X / C
  A = n =>             // A = function that returns 1 - |n - 1|
    n > 1 ?            //   first compare n with 1
      2 - n            //     which allows to simplify the formula to either 2 - n
    :                  //   or
      n                //     just n
)((H /= 60) % 2)       // divide H by 60 and compute Y = A(H % 2)

Mã chính

[5, 3, 1].map(i =>     // for each i in (5, 3, 1):
  A(L * 2) * S * (     //   compute (1 - |2L - 1|) * S (this is C), and multiply it by:
    [1, Y, 0, 0, Y, 1] //     either 0, 1 or Y (let's call this factor K), picked from
    [(i - ~H) % 6]     //     a cyclic sequence of period 6, using i and ~H (-6 ≤ ~H ≤ -1)
    - .5               //     minus 1/2
  )                    //   this gives: C(K - 1/2) = CK - C/2, where CK = 0, C or X
  + L                  //   we add L, leading to CK - C/2 + L = CK + m
)                      // end of map() --> returns [R, G, B]

Hoán vị của (0, C, X)

Phần hơi khó là tạo ra hoán vị chính xác của (0, C, X) theo góc của thành phần màu. Như được hiển thị trong hình dưới đây, mỗi giá trị cột được chọn từ cùng một chuỗi chu kỳ của giai đoạn 6 , bắt đầu từ các độ lệch khác nhau. Trong đoạn mã trên, chúng tôi đang sử dụng - ~ H thay vì chỉ + H vì chúng tôi cần ép H thành một số nguyên. Do đó, bù đắp (5,3,1) thay vì (0,4,2) .

                       C,X,0,0,X,C,C,X,0,0,X,C, ...
 +------> C,X,0,0,X,C  <--------->                  offset = 0, (0 - 1) mod 6 = 5
 | +----> X,C,C,X,0,0          <--------->          offset = 4, (4 - 1) mod 6 = 3
 | | +--> 0,0,X,C,C,X      <--------->              offset = 2, (2 - 1) mod 6 = 1
 | | |
(C,X,0) for   0 ≤ H <  60
(X,C,0) for  60 ≤ H < 120
(0,C,X) for 120 ≤ H < 180
(0,X,C) for 180 ≤ H < 240
(X,0,C) for 240 ≤ H < 300
(C,0,X) for 300 ≤ H < 360

Would dùng Htrong [0,6)và xuất trong [0,1]tiết kiệm một số byte?
Jonathan Allan

@Jonathan ALLan Ah, tôi không nhận thấy định dạng I / O bị lỏng lẻo. Cảm ơn!
Arnauld

4

Toán học, 155 byte

(x~Clear~c;d=Piecewise@Table[{(P=Permutations)[P@{c,x,0}][[42,i]],(i-1)<=#<i*p},{i,6}];c=(1-Abs[2#3-1])#2;x=c(1-Abs[Mod[#/(p=60),2]-1]);m=#3-c/2;(m+d)255)&


Hãy thử trực tuyến!



1
@totallyhuman Tôi không nghĩ điều đó đúng như HueHSB (AKA HSV) không phải HSL (xem hình 2a và 2b trên trang Wikipedia được liên kết).
Jonathan Allan

1
Jenny - nếu đúng, không có lý do gì để không đăng nó dưới dạng số byte với phần không được xây dựng bên dưới của bạn!
Jonathan Allan

1
@Jonathan ALLan Ồ, vậy thôi. Nó hơi khó chịu như thế nào RGBColortồn tại nhưng HSLColorkhông. > _>
hoàn toàn là

Có một phiên bản vô căn cứ này?
user76284

4

Python 2 , 32 byte

from colorsys import*;hls_to_rgb

Hãy thử trực tuyến!

Chức năng này thực sự được tích hợp vào Python thông qua hls_to_rgbbên trong colorsysthư viện. Các định dạng đầu vào của tôi là một phạm vi 0-1 của HLS (thay vì HSL, cả hai đều là từ viết tắt phổ biến cho cùng một điều [mặc dù, HSL là phổ biến hơn]). Và tôi khai thác các giá trị RGB trong một tuple với phạm vi từ 0 đến 1.

Tín dụng

Cảm ơn Jonathan Allan đã chỉ ra rằng tôi chỉ cần nhập nó (và sau đó tiếp tục giúp tôi giảm số byte).


Tôi nghĩ rằng điều này chỉ có thể là 31 byte from colorsys import hls_to_rgbkể từ khi cung cấp cho chúng ta một chức năng có thể được sử dụng lại. Chỉnh sửa - làm cho 21 như from colorsys import*.
Jonathan Allan

1
@Jonathan ALLan Cảm ơn, đã cập nhật.
Neil

Thật ra có lẽ chỉ import colorsysdành cho 15!
Jonathan Allan

@Jonathan ALLan Đẹp, cập nhật lại.
Neil

1
tuy nhiên có thể đúng như vậy, tôi nghĩ rằng điều này ảnh hưởng đến tinh thần của việc mã hóa hơi quá nhiều: /
kéo theo

4

C ++, 228 221 byte

-7 byte nhờ Zacharý

#define S(o,n)r[t[int(h[0])/60*3+o]+o-2]=(n+h[2]-c/2)*255;
void C(float*h,int*r){float g=2*h[2]-1,c=(g<0?1+g:1-g)*h[1],a=int(h[0])%120/60.f-1;int t[]={2,2,2,3,1,2,3,3,0,4,2,0,4,1,1,2,3,1};S(0,c)S(1,c*(a<0?1+a:1-a))S(2,0)}

Các đối số là cả hai mảng có kích thước tối thiểu 3 phần tử (nghĩa là float hsl[3]int rgb[3]

Được chứ. Bây giờ, làm thế nào mà làm việc? Mảng dài đó là gì?

Chà, nó không phải là một mảng dài, nó là một intmảng. Nói đùa, mảng chỉ ra có bao nhiêu vị trí chúng ta phải dịch chuyển CX và 0 khi chúng ta muốn chọn hoán vị chính xác, + 2. Hãy nhớ cách R ', G' và B 'được chọn?

Cách chọn R ', G' và B '

Giả sử chúng ta có một thứ tự "bình thường" đó là {C, X, 0}

Bây giờ, khi hoán vị đầu tiên (ví dụ {C, X, 0}) được chọn, bạn không cần dịch chuyển, điều này hoàn toàn giống với dịch chuyển phải bằng 0. Vì vậy, 3 phần tử đầu tiên của mảng là 0,0 và 0

Đối với hoán vị thứ hai ({X, C, 0}), chúng ta cần dịch chuyển sang phải C 1, và dịch chuyển trái X theo -1, do đó phần tử thứ tư, thứ năm và thứ sáu của mảng là 1, -1 và 0

Và như thế...

Với trường hợp hoán vị thứ 3 và thứ 4, tôi cần dịch chuyển trái sang 0 bằng 2, do đó dịch chuyển sang phải bằng -2. Vì có nhiều hơn 2 số âm, nên tôi thêm 2 vào mỗi phần tử trong mảng và trừ 2 trong thời gian chạy (vì lý do chơi gôn, chỉ có toàn bộ số trong mảng).




3

HTML + JavaScript (ES6), 8 + 88 = 96 byte

f=
(h,s,l)=>(p.style.color=`hsl(${h},${s}%,${l}%)`,getComputedStyle(p).color.match(/\d+/g))
<div oninput=o.textContent=f(h.value,s.value,l.value)>H: <input type=number min=0 max=360 value=0 id=h>°<br>S: <input type=number min=0 max=100 value=0 id=s>%<br>L: <input type=number min=0 max=100 value=0 id=l>%<pre id=o>0,0,0</pre>
<p id=p>

Lấy đầu vào là một góc và hai phần trăm. Tôi đang chấm điểm đoạn mã HTML <p id=p>và hàm mũi tên JavaScript. Tôi không biết trình duyệt làm tròn sử dụng cái gì, vì vậy câu trả lời của tôi có thể hơi khác so với của bạn.


2

Swift 4, 218 byte

Chấp nhận các giá trị HSL trong phạm vi [0,1] làm đối số và trả về một mảng chứa các giá trị RGB trong cùng phạm vi:

import Cocoa;typealias F=CGFloat;func f(h:F,s:F,l:F)->[F]{var r=F(),g=F(),b=F(),x=s*min(1-l,l),n=2*x/max(l+x,1e-9);NSColor(hue:h,saturation:n,brightness:l+x,alpha:1).getRed(&r,green:&g,blue:&b,alpha:nil);return[r,g,b]}

Ý tưởng trước tiên là chuyển đổi đầu vào từ HSL sang HSB, sau đó sử dụng hàm tạo HSB của đối tượng màu tích hợp trong Ca cao để lấy các giá trị RGB.

Phiên bản UIKit có cùng độ dài, vì các thay thế duy nhất là:

  • CocoaUIKit
  • NSColorUIColor

Ung dung:

#if os(iOS)
    import UIKit
    typealias Color = UIColor
#elseif os(OSX)
    import Cocoa
    typealias Color = NSColor
#endif

typealias F = CGFloat

func f(h: F,s: F,l: F) -> [F] {
    var r = F(), g = F(), b = F()

    let x = s * min(1 - l, l)
    let n = 2 * x / max(l + x, 1e-9)

    let color = Color(hue: h, saturation: n, brightness: l + x, alpha: 1)
    color.getRed(&r, green: &g,blue: &b, alpha: nil)

    return [r, g, b]
}

Đoạn sau đây có thể được sử dụng để thử nghiệm, bởi chỉ cần thay thế các giá trị của h, sl:

let h: CGFloat = 0
let s: CGFloat = 0
let l: CGFloat = 0

let result = f(h: h/360, s: s/100, l: l/100).map { Int(round($0*255)) }
print(result)

Thật không may, tôi không thể cung cấp một liên kết đến một hộp cát trực tuyến, vì tất cả chúng đều chạy trên Linux, không bao gồm Ca cao.


2

GLSL (GL_ES) 160 144 134 131 byte

Hue nằm trong phạm vi 0-6 (tiết kiệm 3 byte)
Sat, ánh sáng và rgb là 0-1

vec3 f(vec3 c){return mix(c.bbb,mix(clamp(vec3(-1,2,2)-abs(c.r-vec3(3,2,4))*vec3(-1,1,1),0.,1.),vec3(c.b>.5),abs(.5-c.b)*2.),c.g);}

Hãy thử nó trên cuốn sách của shader

Sử dụng công cụ tô màu trên màn hình in để kiểm tra đầu ra là chính xác,
ngoại trừ một lỗi nhỏ trên 202 19 39 → 81 104 118, cho 80 104 118 118


1

R , 88 byte

function(h,s,l){v=(2*l+s*(1-abs(2*l-1)))/2;col2rgb(hsv(h,ifelse(v==0,v,(2*(v-l))/v),v))}

Hãy thử trực tuyến!

Hàm này lấy đầu vào là các giá trị H, S và L làm giá trị trong khoảng 0-1 và xuất giá trị RGB thành giá trị trong khoảng 0-255. Nó chuyển đổi biểu diễn HSL thành biểu diễn HSV, sau đó sử dụng hsv()để chuyển đổi biểu diễn HSV thành màu R (nghĩa là biểu diễn hex - #rrggbb), sau đó sử dụng col2rgb()để chuyển đổi màu R thành giá trị RGB.


1

Thạch ,  39  32 byte

-1 cảm ơn caird coinheringaahing ( %2chỉ )
-1 và / hoặc cảm hứng cho -4 nhờ caird coinheringaahing quá!

Ḥ;Ḃ’ACש"⁵×\;0+³_®H¤⁴Ḟị336Œ?¤¤œ?

Một chương trình đầy đủ lấy ba đối số dòng lệnh:

  • L, H, STrong phạm vi [0,1), [0,6)[0,1)tương ứng

trong đó in một danh sách cho định dạng RGB là

  • [R, G, B] với mỗi trong ba giá trị trong phạm vi [0,1]

Lưu ý: Hcũng có thể bọc giống như [0,360)muốn.

Hãy thử trực tuyến!

Làm sao?

Ḥ;Ḃ’ACש"⁵×\;0+³_®H¤⁴Ḟị336Œ?¤¤œ? - Main link: number, L (in [0,1]); number, H (in [0,6))
Ḥ                                - double                 =     2L
  Ḃ                              - modulo by 2            =              H%2
 ;                               - concatenate            = [   2L   ,   H%2]

   ’                             - decrement              = [   2L-1 ,   H%2-1]
    A                            - absolute               = [  |2L-1|,  |H%2-1|]
     C                           - complement             = [1-|2L-1|,1-|H%2-1|]
                                 -                        = [C/S     ,C/X]
         ⁵                       - 3rd program argument   = S  (in [0,1])
        "                        - zip with:
      ×                          -   multiplication       = [C,C/X]
       ©                         -   (copy the result, C, to the register)
           \                     - cumulative reduce with:
          ×                      -   multiplication       = [C, C/X*C] = [C,X]
            ;0                   - concatenate zero       = [C,X,0]
               ³                 - 1st program argument   = L
              +                  - add (vectorises)       = [C+L,X+L,L]
                   ¤             - nilad followed by link(s) as a nilad:
                 ®               -   recall from register = C
                  H              -   halve                = C/2
                _                - subtract               = [C+L-C/2,X+L-C/2,L-C/2]
                             ¤   - nilad followed by link(s) as a nilad:
                    ⁴            -   2nd program argument = H
                     Ḟ           -   floor                = floor(H)
                            ¤    -   nilad followed by link(s) as a nilad:
                       336       -     literal 336
                          Œ?     -     Shortest permutation of natural numbers with a
                                 -     lexicographical index of 336 in all permutations
                                 -     thereof            = [3,5,6,4,2,1]
                      ị          -   index into (1-indexed & modular)
                              œ? - get that permutation of [C+L-C/2,X+L-C/2,L-C/2]
                                 - implicit print

Rất tiếc, tất nhiên. Cảm ơn!
Jonathan Allan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.