2010-08-25 20 views
6

Hãy tưởng tượng chúng ta như thế nào một số màu cơ bản:Cách nào chính xác nhất để phân biệt một trong 8 màu?

RED = Color ((196, 2, 51), "RED") 
ORANGE = Color ((255, 165, 0), "ORANGE") 
YELLOW = Color ((255, 205, 0), "YELLOW") 
GREEN = Color ((0, 128, 0), "GREEN") 
BLUE = Color ((0, 0, 255), "BLUE") 
VIOLET = Color ((127, 0, 255), "VIOLET") 
BLACK = Color ((0, 0, 0), "BLACK") 
WHITE = Color ((255, 255, 255), "WHITE") 

Tôi muốn có một chức năng, mà được một 3-tuple như một tham số (như (206, 17, 38)), và nó sẽ quay trở lại màu sắc mà nó là. Ví dụ, (206, 17, 38) là màu đỏ, và (2, 2, 0) là màu đen, và (0, 255, 0) là màu xanh lá cây. Cách nào là chính xác nhất để chọn một trong 8 màu?

+0

2,2,0 là không kỹ thuật đen, giống như không phải là 240.240.240 về mặt kỹ thuật màu xám. – Chris

+4

Đó là một xấp xỉ. Đó là mục tiêu của kịch bản này rõ ràng. –

Trả lời

11

Câu trả lời ngắn : sử dụng khoảng cách Euclide trong không gian màu độc lập của thiết bị (nguồn: Color difference bài viết trên Wikipedia). Vì RGB phụ thuộc vào thiết bị, trước tiên bạn nên ánh xạ màu của mình đến một trong các không gian màu độc lập của thiết bị.

Tôi đề nghị chuyển đổi RGB thành Lab*. Để trích dẫn Wikipedia lần nữa:

Không giống như các mô hình màu RGB và CMYK, màu Lab được thiết kế để xấp xỉ tầm nhìn của con người.

Here's a recipe để thực hiện chuyển đổi. Khi bạn có các giá trị L, a, b, hãy tính khoảng cách Euclide giữa màu của bạn và tất cả các màu tham chiếu và chọn màu gần nhất.


Trên thực tế, Python mô-đun python-colormath trên Google Code (dưới GPL v3) có khả năng chuyển đổi giữa nhiều không gian màu khác nhau và tính toán sự khác biệt màu sắc cũng.

+1

Tuyệt vời! python-colormath là thứ tôi cần! CHÍNH XÁC! – Graf

+0

Tài liệu tham khảo python-colormath http://www.brucelindbloom.com/ - một nguồn tuyệt vời nếu bạn muốn hiểu toán học đằng sau các chuyển đổi. – Bolo

3

Xử lý màu như vectơ và khoảng cách đếm giữa giá trị đã cho và mỗi khoảng cách và chọn khoảng cách ít nhất. Khoảng cách đơn giản nhất có thể là: |a1 - a2| + |b1 - b2| + |c1 - c2|.

Đọc điều này quá: http://answers.yahoo.com/question/index?qid=20071202234050AAaDGLf, có chức năng khoảng cách tốt hơn được mô tả.

+2

RGB phụ thuộc vào thiết bị và do đó nó không phải là một không gian màu tốt để đo sự khác biệt màu sắc (xem tại đây: http://en.wikipedia.org/wiki/Color_difference) – Bolo

3

Sử dụng rgb_to_hsv để chuyển đổi. Sau đó kết hợp các màu sắc với tủ quần áo màu sắc

Ví dụ của bạn nó sẽ là RED vì màu sắc phù hợp chính xác

>>> from colorsys import rgb_to_hsv 
>>> rgb_to_hsv(192,2,51) 
(0.83333333333333337, 0, 192) 
>>> rgb_to_hsv(206, 17, 38) 
(0.83333333333333337, 0, 206) 
>>> 

Dưới đây là một ví dụ về làm thế nào để tìm ra trận đấu gần nhất

>>> from colorsys import rgb_to_hsv 
>>> 
>>> colors = dict((
...  ((196, 2, 51), "RED"), 
...  ((255, 165, 0), "ORANGE"), 
...  ((255, 205, 0), "YELLOW"), 
...  ((0, 128, 0), "GREEN"), 
...  ((0, 0, 255), "BLUE"), 
...  ((127, 0, 255), "VIOLET"), 
...  ((0, 0, 0), "BLACK"), 
...  ((255, 255, 255), "WHITE"),)) 
>>> 
>>> color_to_match = (206,17,38) 
>>> 
>>> print min((abs(rgb_to_hsv(*k)[0]-rgb_to_hsv(*color_to_match)[0]),v) for k,v in colors.items()) 
(0.0, 'RED') 
+0

Điều đó không hiệu quả với tôi, hãy thử nó với màu sắc (2,2,0), có màu đen, mã của bạn có màu cam. – Graf

1

Tôi hy vọng đây là cách nó hoạt động: Nó chuyển đổi màu thành hsv, sau đó lấy khoảng cách euclide (bình phương) cho tất cả các màu sẵn có và trả về kết quả gần nhất.

Chủ yếu là phiên bản mã gnibblers cố định.

from colorsys import rgb_to_hsv 

colors = dict((
((196, 2, 51), "RED"), 
((255, 165, 0), "ORANGE"), 
((255, 205, 0), "YELLOW"), 
((0, 128, 0), "GREEN"), 
((0, 0, 255), "BLUE"), 
((127, 0, 255), "VIOLET"), 
((0, 0, 0), "BLACK"), 
((255, 255, 255), "WHITE"),)) 

def to_hsv(color): 
    """ converts color tuples to floats and then to hsv """ 
    return rgb_to_hsv(*[x/255.0 for x in color]) #rgb_to_hsv wants floats! 

def color_dist(c1, c2): 
    """ returns the squared euklidian distance between two color vectors in hsv space """ 
    return sum((a-b)**2 for a,b in zip(to_hsv(c1),to_hsv(c2))) 

def min_color_diff(color_to_match, colors): 
    """ returns the `(distance, color_name)` with the minimal distance to `colors`""" 
    return min(# overal best is the best match to any color: 
     (color_dist(color_to_match, test), colors[test]) # (distance to `test` color, color name) 
     for test in colors) 

color_to_match = (127, 255, 255) 
print min_color_diff(color_to_match, colors) 

Tất cả danh sách hiểu sôi nổi sẽ trông tốt hơn nhiều với một Color lớp đơn giản mà hỗ trợ sắp xếp và khoảng cách (nhưng bạn có thể làm điều đó cho thực hành ;-).

+0

Có thể hoạt động, cảm ơn nhận xét của bạn, nhưng tôi đã tìm thấy một giải pháp tốt hơn. – Graf

+0

Không có điều đó không hoạt động tốt, tôi đã thử màu (2,2,0) và nó cho biết nó là màu xanh lá cây. Tôi nghĩ rằng việc chuyển đổi sang hsv không phải là ý tưởng hay nhất. Nó thường được gợi ý rằng bạn chỉ nên sử dụng khoảng cách euclide trên hai màu Lab, không phải màu RGB, hoặc màu hsv. – Graf

+0

@Graf: cảm ơn thông tin. Tôi đoán chúng ta nên để lại những thứ như vậy cho những người thực sự biết những gì họ đang làm và sử dụng mô-đun python-colormath ;-) –

3

Tôi không phải là chuyên gia về màu sắc, nhưng tôi đã tìm kiếm RGB/HEX/HSV để chuyển đổi tên màu đơn giản thành python. Sau khi thực hiện một số nghiên cứu, tôi tin rằng tôi đã thực hiện một giải pháp ghê gớm.Theo IfLoop trong this post:

Nếu bạn kết thúc bằng khoảng cách Descartes để so sánh màu, bạn thường phải dịch đầu vào thành không gian màu theo cảm nhận, chẳng hạn như Lab hoặc Yuv. Cả RGB và HSV đều không tuyến tính, và vì vậy khoảng cách Descartes không liên quan nhiều đến hai màu tương tự. - IfLoop ngày 27 tháng 7 '11 tại 21:15

Do đó, mã của Jochen Ritzel sẽ không luôn trả về màu sắc phù hợp, như Graf đã chỉ ra. Điều này là do cả RGB và HSV đều là các không gian màu tuyến tính. Chúng ta cần sử dụng một không gian màu cảm nhận tuyến tính như YUV.

Vì vậy, những gì tôi đã làm là tôi lấy mã của Jochen Ritzel và thay thế mã rgb thành mã hsv bằng mã rgb thành yuv dựa trên this post.

colors = dict((
((196, 2, 51), "RED"), 
((255, 165, 0), "ORANGE"), 
((255, 205, 0), "YELLOW"), 
((0, 128, 0), "GREEN"), 
((0, 0, 255), "BLUE"), 
((127, 0, 255), "VIOLET"), 
((0, 0, 0), "BLACK"), 
((255, 255, 255), "WHITE"),)) 

def rgb_to_ycc(r, g, b): #http://bit.ly/1blFUsF 
    y = .299*r + .587*g + .114*b 
    cb = 128 -.168736*r -.331364*g + .5*b 
    cr = 128 +.5*r - .418688*g - .081312*b 
    return y, cb, cr 

def to_ycc(color): 
    """ converts color tuples to floats and then to yuv """ 
    return rgb_to_ycc(*[x/255.0 for x in color]) 

def color_dist(c1, c2): 
    """ returns the squared euklidian distance between two color vectors in yuv space """ 
    return sum((a-b)**2 for a,b in zip(to_ycc(c1),to_ycc(c2))) 

def min_color_diff(color_to_match, colors): 
    """ returns the `(distance, color_name)` with the minimal distance to `colors`""" 
    return min(# overal best is the best match to any color: 
     (color_dist(color_to_match, test), colors[test]) # (distance to `test` color, color name) 
     for test in colors) 

if __name__ == "__main__": 
    r = input('r: ') 
    g = input('g: ') 
    b = input('b: ') 
    color_to_match = (r, g, b) 
    print min_color_diff(color_to_match, colors) 
    input('Press enter to exit.') 

Bây giờ chúng ta dường như kết thúc với màu sắc phù hợp hầu hết thời gian:

>>> color_to_match = (2, 2, 0) #Graf's test 
>>> print min_color_diff(color_to_match, colors) 
>>> 
(6.408043991348166e-05, 'BLACK') 

Thêm ví dụ:

>>> color_to_match = (131, 26, 26) 
>>> print min_color_diff(color_to_match, colors) 
>>> 
(0.027661314571288835, 'RED') 
>>> color_to_match = (69, 203, 136) 
>>> print min_color_diff(color_to_match, colors) 
>>> 
(0.11505647737959283, 'GREEN') 

Cho đến nay có vẻ như phiên bản của tôi dường như được làm việc gần như hoàn toàn, nhưng xin lưu ý: Có khả năng nếu màu rgb quá sáng hoặc quá tối, có thể bạn sẽ được trả về 'TRẮNG' hoặc 'ĐEN'. Để giải quyết điều này, bạn sẽ cần phải thêm màu sáng hơn và tối hơn cho từ điển màu của bạn. Ngoài ra, thêm nhiều màu sắc như 'BROWN' và 'GRAY' (v.v.) vào từ điển màu cũng sẽ trả lại kết quả tốt hơn.

+1

Điều này chủ yếu là những gì OP yêu cầu nếu anh ta/cô ấy muốn có một mã nguồn thực sự. Hầu hết mọi người quên sự khác biệt giữa các không gian màu. RGB dành cho thiết bị và HSV không tuyến tính. So sánh với euclide nên được thực hiện trong YUV (Lab cũng hoạt động, nhưng nó chủ yếu được thực hiện để so sánh với tầm nhìn của con người). –

+0

Cảm ơn bạn đã cung cấp câu trả lời. Khi tôi thử, (45, 106, 168), nó in XANH. Nhưng trên thực tế, màu đó gần với BLUE. – Indrajeet

0

Mô-đun màu của thư viện Goulib của tôi thực hiện điều này khá tốt và nhiều hơn thế nữa. Nó định nghĩa một lớp màu có thể được inited từ một số không gian màu, và được nhóm lại trong một từ điển bảng màu. Một số bảng màu được xác định trước, đáng chú ý là một bảng được lập chỉ mục bởi các tên html/matplotlib. Mỗi màu Automagically recieves một tên từ chỉ số của màu gần nhất trong bảng màu này, được đo trong không gian phòng thí nghiệm (deltaE)

xem demo ở đây http://nbviewer.jupyter.org/github/Goulu/Goulib/blob/master/notebooks/colors.ipynb

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