2008-08-01 32 views
61

Đây là điều tôi đã giải quyết nhiều lần và không bao giờ tìm được giải pháp. Đó là khó khăn với tôi. Vấn đề là tạo ra một cách để tạo ra các màu N, có thể phân biệt nhất có thể khi một tham số N.Chức năng tạo bánh xe màu

+0

Cuối cùng tôi đã kiểm tra [JFreeChart] (http://www.jfree.org/jfreechart/) có thuật toán chính xác này và vì nó là mã nguồn mở, bạn có thể kiểm tra những gì nó làm. Tôi biết rằng các màu sắc tôi nhận được dường như không được đặt cách nhau ngẫu nhiên dọc theo một số vòng tròn hoặc hình cầu, nhưng được chọn cụ thể hơn. –

Trả lời

22

Suy nghĩ đầu tiên của tôi về điều này là "cách tạo ra N vectơ trong không gian để tối đa hóa khoảng cách với nhau." Bạn có thể thấy rằng RGB (hoặc bất kỳ thang đo nào khác mà bạn sử dụng tạo thành cơ sở trong không gian màu) chỉ là các vectơ. Hãy xem Random Point Picking. Hy vọng đây là một khởi đầu tốt cho bạn! Một khi bạn có một tập hợp các vectơ được tối đa hóa một phần, bạn có thể lưu chúng trong một bảng băm hoặc một cái gì đó sau này, và chỉ thực hiện các phép quay ngẫu nhiên trên chúng để có được tất cả các màu mà bạn mong muốn cách nhau tối đa!

Chỉnh sửa: Suy nghĩ về vấn đề này nhiều hơn, sẽ tốt hơn để ánh xạ màu trong trang viên tuyến tính, có thể (0,0,0) -> (255,255,255) theo từ điển, và sau đó phân phối chúng đồng đều. Tôi thực sự không biết điều này sẽ hiệu quả như thế nào, nhưng phải kể từ đó, hãy nói:

n = 10 chúng tôi biết chúng tôi có 16777216 màu (256^3). Chúng tôi có thể sử dụng buckles algorithm 515 để tìm màu được lập chỉ mục theo từ điển. \frac {\binom {256^3} {3}} {n} * i. Có thể bạn sẽ phải chỉnh sửa thuật toán để tránh tràn và có thể thêm một số cải thiện tốc độ nhỏ.

+1

Điều này là không chính xác vì không gian màu RGB không đồng đều theo cảm nhận –

+0

Tôi đồng ý rằng âm thanh hợp lý. RGB chủ yếu làm cho các giống lai màu tím và cam và tương đối hiếm làm cho các giống lai màu xanh dương ... quy mô màu sắc đồng nhất từ ​​hồng ngoại đến xanh thẳm, vì vậy phải chọn các điểm bằng nhau cách nhau. cần một bản ngã dựa trên cầu vồng. –

+0

Xin vui lòng xem xét upvoting/sau các trang web lý thuyết màu StackExchange: https://area51.stackexchange.com/proposals/110687/color-theory –

1

Tôi đã đọc ở đâu đó mà mắt người không thể phân biệt được cách nhau ít hơn 4 giá trị. Vì vậy, đây là một cái gì đó để ghi nhớ. Thuật toán sau đây không bù đắp cho điều này.

Tôi không chắc chắn này là chính xác những gì bạn muốn, nhưng đây là một cách để tạo ra một cách ngẫu nhiên giá trị không lặp lại màu sắc:

(hãy cẩn thận, không phù hợp pseudo-code trước)

//colors entered as 0-255 [R, G, B] 
colors = []; //holds final colors to be used 
rand = new Random(); 

//assumes n is less than 16,777,216 
randomGen(int n){ 
    while (len(colors) < n){ 
     //generate a random number between 0,255 for each color 
     newRed = rand.next(256); 
     newGreen = rand.next(256); 
     newBlue = rand.next(256); 
     temp = [newRed, newGreen, newBlue]; 
     //only adds new colors to the array 
     if temp not in colors { 
     colors.append(temp); 
     } 
    } 
} 

Một cách bạn có thể tối ưu hóa điều này để có khả năng hiển thị tốt hơn là so sánh khoảng cách giữa mỗi màu mới và tất cả các màu trong mảng:

for item in color{ 
    itemSq = (item[0]^2 + item[1]^2 + item[2]^2])^(.5); 
    tempSq = (temp[0]^2 + temp[1]^2 + temp[2]^2])^(.5); 
    dist = itemSq - tempSq; 
    dist = abs(dist); 
} 
//NUMBER can be your chosen distance apart. 
if dist < NUMBER and temp not in colors { 
    colors.append(temp); 
} 

Nhưng cách tiếp cận này sẽ có ý nghĩa ntly làm chậm thuật toán của bạn.

Một cách khác là loại bỏ ngẫu nhiên và có hệ thống đi qua tất cả 4 giá trị và thêm màu vào một mảng trong ví dụ trên.

3

Nó cũng không phải là một yếu tố mà thứ tự bạn thiết lập màu sắc?

Giống như nếu bạn sử dụng ý tưởng Dillie-Os bạn cần trộn màu càng nhiều càng tốt. 0 64 128 256 là từ trang này đến trang kế tiếp. nhưng 0 256 64 128 trong một bánh xe sẽ có nhiều "cách biệt"

Điều này có hợp lý không?

17

Tốt nhất là nên tìm các màu tối đa trong không gian màu "theo cảm nhận đồng nhất", ví dụ: CIELAB (sử dụng khoảng cách Euclide giữa L *, a *, b * phối hợp làm chỉ số khoảng cách của bạn) và sau đó chuyển đổi sang không gian màu bạn chọn. Nhận thức đồng nhất đạt được bằng cách tinh chỉnh không gian màu để ước tính các tuyến tính phi tuyến tính trong hệ thống thị giác của con người.

+0

Đây có lẽ là giải pháp tốt nhất vì nó là khá đơn giản. Tuy nhiên có các công thức khác biệt màu sắc cần xem xét, như CIE2000 hoặc thậm chí CIECAM –

7

Một số tài nguyên liên quan:

ColorBrewer - Bộ đồ màu sắc được thiết kế để tối đa phân biệt để sử dụng trên bản đồ.

Escaping RGBland: Selecting Colors for Statistical Graphics - Báo cáo kỹ thuật mô tả tập hợp các thuật toán để tạo các bộ màu tốt (tức là có thể phân biệt tối đa) trong không gian màu hcl.

+1

Thoát RGBland là phải đọc tham chiếu để chọn các bảng màu có thể phân biệt được. – Drake

6

Dưới đây là một số mã để phân bổ màu RGB đồng đều xung quanh một bánh xe màu HSL có độ sáng được chỉ định.

class cColorPicker 
{ 
public: 
    void Pick(vector<DWORD>&v_picked_cols, int count, int bright = 50); 
private: 
    DWORD HSL2RGB(int h, int s, int v); 
    unsigned char ToRGB1(float rm1, float rm2, float rh); 
}; 
/** 

    Evenly allocate RGB colors around HSL color wheel 

    @param[out] v_picked_cols a vector of colors in RGB format 
    @param[in] count number of colors required 
    @param[in] bright 0 is all black, 100 is all white, defaults to 50 

    based on Fig 3 of http://epub.wu-wien.ac.at/dyn/virlib/wp/eng/mediate/epub-wu-01_c87.pdf?ID=epub-wu-01_c87 

*/ 

void cColorPicker::Pick(vector<DWORD>&v_picked_cols, int count, int bright) 
{ 
    v_picked_cols.clear(); 
    for(int k_hue = 0; k_hue < 360; k_hue += 360/count) 
     v_picked_cols.push_back(HSL2RGB(k_hue, 100, bright)); 
} 
/** 

    Convert HSL to RGB 

    based on http://www.codeguru.com/code/legacy/gdi/colorapp_src.zip 

*/ 

DWORD cColorPicker::HSL2RGB(int h, int s, int l) 
{ 
    DWORD ret = 0; 
    unsigned char r,g,b; 

    float saturation = s/100.0f; 
    float luminance = l/100.f; 
    float hue = (float)h; 

    if (saturation == 0.0) 
    { 
     r = g = b = unsigned char(luminance * 255.0); 
    } 
    else 
    { 
     float rm1, rm2; 

     if (luminance <= 0.5f) rm2 = luminance + luminance * saturation; 
     else      rm2 = luminance + saturation - luminance * saturation; 
     rm1 = 2.0f * luminance - rm2; 
     r = ToRGB1(rm1, rm2, hue + 120.0f); 
     g = ToRGB1(rm1, rm2, hue); 
     b = ToRGB1(rm1, rm2, hue - 120.0f); 
    } 

    ret = ((DWORD)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))); 

    return ret; 
} 


unsigned char cColorPicker::ToRGB1(float rm1, float rm2, float rh) 
{ 
    if  (rh > 360.0f) rh -= 360.0f; 
    else if (rh < 0.0f) rh += 360.0f; 

    if  (rh < 60.0f) rm1 = rm1 + (rm2 - rm1) * rh/60.0f; 
    else if (rh < 180.0f) rm1 = rm2; 
    else if (rh < 240.0f) rm1 = rm1 + (rm2 - rm1) * (240.0f - rh)/60.0f;  

    return static_cast<unsigned char>(rm1 * 255); 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    vector<DWORD> myCols; 
    cColorPicker colpick; 
    colpick.Pick(myCols, 20); 
    for(int k = 0; k < (int)myCols.size(); k++) 
     printf("%d: %d %d %d\n", k+1, 
     (myCols[k] & 0xFF0000) >>16, 
     (myCols[k] & 0xFF00) >>8, 
     (myCols[k] & 0xFF)); 

    return 0; 
} 
+2

AFAIK thật đơn giản đối với mã cổng từ C++ đến Java – ravenspoint

+0

không phải khi tôi không hiểu tất cả các công cụ chuyển bit, trong số những thứ khác:/ – CodeGuy

+0

Tôi đã cung cấp các URL liên kết đến giải thích về mã. – ravenspoint

1

Tôi biết điều này một bài cũ nhưng tôi tìm thấy nó trong khi tìm kiếm một giải pháp PHP đến chủ đề và cuối cùng đi kèm với một giải pháp đơn giản:

function random_color($i = null, $n = 10, $sat = .5, $br = .7) { 
    $i = is_null($i) ? mt_rand(0,$n) : $i; 
    $rgb = hsv2rgb(array($i*(360/$n), $sat, $br)); 
    for ($i=0 ; $i<=2 ; $i++) 
     $rgb[$i] = dechex(ceil($rgb[$i])); 
    return implode('', $rgb); 
} 

function hsv2rgb($c) { 
    list($h,$s,$v)=$c; 
    if ($s==0) 
     return array($v,$v,$v); 
    else { 
     $h=($h%=360)/60; 
     $i=floor($h); 
     $f=$h-$i; 
     $q[0]=$q[1]=$v*(1-$s); 
     $q[2]=$v*(1-$s*(1-$f)); 
     $q[3]=$q[4]=$v; 
     $q[5]=$v*(1-$s*$f); 
     return(array($q[($i+4)%6]*255,$q[($i+2)%6]*255,$q[$i%6]*255)); //[1] 
    } 
} 

Vì vậy, chỉ cần gọi random_color() chức năng ở đâu $ i xác định màu, $ n số màu có thể, $ sat độ bão hòa và $ br độ sáng.

+0

Bạn có thể giải thích "i" là gì trong trường hợp này không? Câu hỏi được đặt ra cho số N. "I" paramater là gì? – CodeGuy

+0

Trên 'random_color()', '$ i' là" hạt giống "để tạo ra màu sắc, phải là một số từ 0 đến' $ n', nếu bạn nhập không có hạt giống (NULL), hàm sẽ chọn một số ngẫu nhiên. '$ n' là số lượng màu có thể cho độ bão hòa và độ sáng nhất định, tức là số màu trong bảng màu. Về cơ bản chúng tôi chia độ 360 độ thành '$ n' và sử dụng' $ i' làm hệ số nhân. Nói cách khác, '$ n' cao hơn sẽ cho bạn nhiều màu hơn, thấp hơn' $ n' sẽ cho bạn ít màu hơn nhưng khác nhau hơn. '$ i' sẽ xác định màu và sẽ luôn giống nhau nếu bạn tiếp tục sử dụng chức năng này. Tôi hy vọng rằng sẽ giúp. – Mauro

+0

Tôi hiểu rồi! Cảm ơn lời giải thích. Một điều nữa ... bất kỳ gợi ý nào về việc phải làm gì nếu tôi có màu nền và tôi muốn cách xa điều đó càng tốt cho tất cả các màu sắc? – CodeGuy

0

Để đạt được "phân biệt nhất", chúng tôi cần sử dụng không gian màu cảm nhận như Lab (hoặc bất kỳ không gian màu tuyến tính nhận thức nào khác) chứ không phải RGB. Ngoài ra, chúng ta có thể lượng hóa không gian này để giảm kích thước của không gian.

Tạo không gian 3D đầy đủ với tất cả các mục nhập có thể lượng tử hóa và chạy thuật toán K-means với k=N. Các kết quả trung tâm/"có nghĩa là" nên được phân biệt nhất từ ​​mỗi khác.

Các vấn đề liên quan