2008-08-04 46 views
44

Original Questionfollowup: Tìm một "khoảng cách" chính xác giữa màu sắc

Tôi đang tìm kiếm một chức năng mà cố gắng để xác định số lượng như thế nào "xa xôi" (hoặc riêng biệt) hai màu là. Câu hỏi này thực sự có hai phần:

  1. Không gian màu nào đại diện tốt nhất cho tầm nhìn của con người?
  2. gì khoảng cách số liệu trong không gian đó hiện rõ nhất nhìn của con người (Euclide?)
+1

Tôi đã kết thúc lên kế hoạch một số giải pháp bên dưới khi xử lý tình huống tương tự. Những người khác có thể tìm thấy những khoảnh khắc thú vị http://stackoverflow.com/q/5774152/156755 – Basic

Trả lời

43

Chuyển đổi thành La * b * (còn gọi là "Lab" đơn giản và bạn cũng sẽ thấy tham chiếu đến "CIELAB"). Một measaure tốt nhanh chóng của sự khác biệt màu sắc là

(L1-L2)^2 + (a1-a2)^2 + (b1-b2)^2

nhà khoa học Màu có biện pháp tinh tế hơn khác , có thể không đáng bận tâm, tùy thuộc vào độ chính xác cần thiết cho những gì bạn đang làm.

Giá trị ab đại diện cho màu tương phản theo cách tương tự như cách thức hoạt động của nón và có thể âm hoặc dương. Màu trung tính - trắng, xám là a=0, b=0. L là độ sáng được xác định theo một cách cụ thể, từ số không (bóng tối thuần túy) đến bất cứ thứ gì.

Giải thích thô: >> Với màu sắc, mắt chúng ta phân biệt giữa hai dải bước sóng rộng - xanh dương và bước sóng dài hơn. và sau đó, nhờ một đột biến di truyền gần đây hơn, các hình nón bước sóng dài hơn phân tách thành hai, phân biệt chúng ta với màu đỏ so với màu xanh lá cây.

Bằng cách này, nó sẽ là tuyệt vời cho sự nghiệp của bạn để vượt lên trên các chuyên gia hangman màu của bạn chỉ biết "RGB" hoặc "CMYK" tuyệt vời cho các thiết bị nhưng hút cho công việc nhận thức nghiêm trọng. Tôi đã làm việc cho các nhà khoa học hình ảnh không biết gì về thứ này!

Đối với nhiều niềm vui hơn đọc trên lý thuyết khác biệt màu sắc, hãy thử:

Chi tiết hơn về Lab tại http://en.kioskea.net/video/cie-lab.php3 Tôi không thể tìm thấy trang không xấu xí trên thực tế có công thức chuyển đổi b Tôi chắc chắn một người nào đó sẽ chỉnh sửa câu trả lời này để bao gồm một câu trả lời.

+4

Về tính xấu của công thức chuyển đổi : chúng xấu vì một lý do, vì việc nhận từ RGB sang XYZ thành LAB phụ thuộc vào điều kiện xem. cf: (cảnh báo, xấu xí) http://www.easyrgb.com/index.php?X=MATH –

+1

Có thể sẽ đáng để thêm mô tả về các chỉ số khoảng cách màu tiêu chuẩn và số giả được xác định bởi CIE: http: // vi .wikipedia.org/wiki/Color_difference – BartoszKP

2

thể trông giống như thư rác nhưng không có, liên kết này thực sự thú vị cho không gian màu :)

http://www.compuphase.com/cmetric.htm

+0

Giống như trang web trung bình của những năm 90, điều đó, cũng là một trang web phổ biến cho năm 2010+ Học giả. – Domi

2

Các dễ nhất khoảng cách dĩ nhiên sẽ chỉ xem xét các màu như các vectơ 3d bắt nguồn từ cùng một nguồn gốc và lấy khoảng cách giữa các điểm kết thúc của chúng.

Nếu bạn cần xem xét các yếu tố như vậy mà màu xanh lá cây nổi bật hơn trong việc đánh giá cường độ, bạn có thể cân nhắc các giá trị.

ImageMagic cung cấp quy mô như sau:

  • đỏ: 0,3
  • xanh: 0,6
  • xanh: 0,1

Tất nhiên, các giá trị như thế này sẽ chỉ có ý nghĩa liên quan đến các giá trị khác cho các màu khác, không phải là một cái gì đó có ý nghĩa đối với con người, vì vậy tất cả các bạn có thể sử dụng các giá trị cho sẽ được sắp xếp tương tự.

4

HSL và HSV tốt hơn cho nhận thức màu của con người. Theo Wikipedia:

Đó là đôi khi thích hợp hơn khi làm việc với các tài liệu nghệ thuật, hình ảnh kỹ thuật số, hoặc các phương tiện khác, sử dụng mô hình HSV hoặc màu HSL trên mô hình thay thế chẳng hạn như RGB hay CMYK, vì sự khác biệt trong cách các mô hình mô phỏng cách con người cảm nhận màu sắc. RGB và CMYK là các mô hình cộng và trừ, tương ứng, mô hình hóa cách ánh sáng màu chính hoặc sắc tố (tương ứng) kết hợp để tạo thành các màu mới khi trộn lẫn.

Graphical depiction of HSV

+0

Xem ra: màu đỏ ở 0 °, vì vậy màu đỏ vàng là + 10 ° và màu xanh lam đỏ ở -10 ° hoặc 350 °. Tính toán khoảng cách không chỉ đơn giản bằng cách trừ hai giá trị ngay bây giờ. –

+2

Không thực sự hữu ích trong bối cảnh câu trả lời khác. Các chỉ số được xác định bởi CIE tốt hơn cho nhận thức màu sắc của con người không phải là HLS và HSV. – BartoszKP

+0

Trong bài báo này, có một công thức cho khoảng cách màu trong không gian HSV http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.84.2498&rep=rep1&type=pdf – fyts

2

Vâng, như một điểm đầu tiên của cuộc gọi, tôi muốn nói rằng các số liệu chung HSV (Hue, Saturation và Value) hoặc HSL là đại diện tốt hơn về cách con người cảm nhận được màu sắc hơn nói RGB hoặc CYMK. Xem HSL, HSV on Wikipedia.

Tôi giả sử ngây thơ tôi sẽ vẽ các điểm trong không gian HSL cho hai màu và tính toán độ lớn của vectơ chênh lệch. Tuy nhiên điều này có nghĩa là màu vàng tươi sáng và xanh lá cây sẽ được coi là khác nhau như màu xanh lá cây đến màu xanh đậm. Nhưng sau đó nhiều người cho rằng màu đỏ và hồng có hai màu khác nhau.

Hơn nữa, các vector khác nhau trong cùng một hướng trong không gian tham số này không bằng nhau. Ví dụ, mắt người chọn màu xanh lá cây tốt hơn nhiều so với các màu khác. Một sự thay đổi màu sắc từ màu xanh lá cây với cùng một số tiền như một sự thay đổi từ màu đỏ có thể có vẻ lớn hơn.Ngoài ra một sự thay đổi trong bão hòa từ một số lượng nhỏ bằng không là sự khác biệt giữa màu xám và màu hồng, ở nơi khác sự thay đổi sẽ là sự khác biệt giữa hai sắc thái của màu đỏ. Từ góc độ của một lập trình viên, bạn sẽ cần vẽ các vector khác nhau nhưng được sửa đổi bằng ma trận tỷ lệ có thể điều chỉnh độ dài tương ứng ở các vùng khác nhau của không gian HSL - điều này sẽ khá tùy ý và dựa trên các giá trị khác nhau. ý tưởng lý thuyết màu sắc nhưng được tinh chỉnh khá tùy tiện tùy thuộc vào những gì bạn muốn áp dụng điều này.

Thậm chí tốt hơn, bạn có thể xem có ai đã làm được một điều như vậy trực tuyến ...

3

Các Wikipedia article on color differences danh sách một số không gian màu sắc và số liệu khoảng cách được thiết kế để đồng ý với nhận thức của con người khoảng cách màu sắc.

2

Là một người mù màu, tôi tin rằng sẽ tốt hơn nếu bạn cố gắng chia tách nhiều hơn thì tầm nhìn bình thường. Dạng mù màu phổ biến nhất là thiếu màu đỏ/xanh lá cây. Nó không có nghĩa là bạn không thể nhìn thấy màu đỏ hoặc màu xanh lá cây, nó có nghĩa là nó là khó khăn hơn để xem và khó khăn hơn để xem sự khác biệt. Vì vậy, phải mất một sự tách biệt lớn hơn trước khi một người mù màu có thể nói sự khác biệt.

8

dưới dạng liên kết cmetric.htm phía trên không thành công cho tôi, cũng như nhiều triển khai khác cho khoảng cách màu tôi tìm thấy (sau một jurney rất dài ..) Làm thế nào để tính toán khoảng cách màu sắc tốt nhất, và .. một cách khoa học chính xác nhất: deltaE và từ 2 RGB() giá trị sử dụng OpenCV:

này đòi hỏi 3 chuyển đổi không gian màu + một số chuyển đổi mã từ javascript (http://svn.int64.org/viewvc/int64/colors/colors.js) C++

Và cuối cùng là mã (dường như để làm việc ngay ra khỏi hộp, hy vọng không ai tìm thấy một lỗi nghiêm trọng có ... nhưng nó có vẻ tốt đẹp sau một số xét nghiệm)

#include <opencv2/core/core.hpp> 
#include <opencv2/imgproc/imgproc.hpp> 
#include <opencv2/highgui/highgui.hpp> 
#include <opencv2/photo/photo.hpp> 
#include <math.h> 

using namespace cv; 
using namespace std; 

#define REF_X 95.047; // Observer= 2°, Illuminant= D65 
#define REF_Y 100.000; 
#define REF_Z 108.883; 

void bgr2xyz(const Vec3b& BGR, Vec3d& XYZ); 
void xyz2lab(const Vec3d& XYZ, Vec3d& Lab); 
void lab2lch(const Vec3d& Lab, Vec3d& LCH); 
double deltaE2000(const Vec3b& bgr1, const Vec3b& bgr2); 
double deltaE2000(const Vec3d& lch1, const Vec3d& lch2); 


void bgr2xyz(const Vec3b& BGR, Vec3d& XYZ) 
{ 
    double r = (double)BGR[2]/255.0; 
    double g = (double)BGR[1]/255.0; 
    double b = (double)BGR[0]/255.0; 
    if(r > 0.04045) 
     r = pow((r + 0.055)/1.055, 2.4); 
    else 
     r = r/12.92; 
    if(g > 0.04045) 
     g = pow((g + 0.055)/1.055, 2.4); 
    else 
     g = g/12.92; 
    if(b > 0.04045) 
     b = pow((b + 0.055)/1.055, 2.4); 
    else 
     b = b/12.92; 
    r *= 100.0; 
    g *= 100.0; 
    b *= 100.0; 
    XYZ[0] = r * 0.4124 + g * 0.3576 + b * 0.1805; 
    XYZ[1] = r * 0.2126 + g * 0.7152 + b * 0.0722; 
    XYZ[2] = r * 0.0193 + g * 0.1192 + b * 0.9505; 
} 

void xyz2lab(const Vec3d& XYZ, Vec3d& Lab) 
{ 
    double x = XYZ[0]/REF_X; 
    double y = XYZ[1]/REF_X; 
    double z = XYZ[2]/REF_X; 
    if(x > 0.008856) 
     x = pow(x , .3333333333); 
    else 
     x = (7.787 * x) + (16.0/116.0); 
    if(y > 0.008856) 
     y = pow(y , .3333333333); 
    else 
     y = (7.787 * y) + (16.0/116.0); 
    if(z > 0.008856) 
     z = pow(z , .3333333333); 
    else 
     z = (7.787 * z) + (16.0/116.0); 
    Lab[0] = (116.0 * y) - 16.0; 
    Lab[1] = 500.0 * (x - y); 
    Lab[2] = 200.0 * (y - z); 
} 

void lab2lch(const Vec3d& Lab, Vec3d& LCH) 
{ 
    LCH[0] = Lab[0]; 
    LCH[1] = sqrt((Lab[1] * Lab[1]) + (Lab[2] * Lab[2])); 
    LCH[2] = atan2(Lab[2], Lab[1]); 
} 

double deltaE2000(const Vec3b& bgr1, const Vec3b& bgr2) 
{ 
    Vec3d xyz1, xyz2, lab1, lab2, lch1, lch2; 
    bgr2xyz(bgr1, xyz1); 
    bgr2xyz(bgr2, xyz2); 
    xyz2lab(xyz1, lab1); 
    xyz2lab(xyz2, lab2); 
    lab2lch(lab1, lch1); 
    lab2lch(lab2, lch2); 
    return deltaE2000(lch1, lch2); 
} 

double deltaE2000(const Vec3d& lch1, const Vec3d& lch2) 
{ 
    double avg_L = (lch1[0] + lch2[0]) * 0.5; 
    double delta_L = lch2[0] - lch1[0]; 
    double avg_C = (lch1[1] + lch2[1]) * 0.5; 
    double delta_C = lch1[1] - lch2[1]; 
    double avg_H = (lch1[2] + lch2[2]) * 0.5; 
    if(fabs(lch1[2] - lch2[2]) > CV_PI) 
     avg_H += CV_PI; 
    double delta_H = lch2[2] - lch1[2]; 
    if(fabs(delta_H) > CV_PI) 
    { 
     if(lch2[2] <= lch1[2]) 
      delta_H += CV_PI * 2.0; 
     else 
      delta_H -= CV_PI * 2.0; 
    } 

    delta_H = sqrt(lch1[1] * lch2[1]) * sin(delta_H) * 2.0; 
    double T = 1.0 - 
      0.17 * cos(avg_H - CV_PI/6.0) + 
      0.24 * cos(avg_H * 2.0) + 
      0.32 * cos(avg_H * 3.0 + CV_PI/30.0) - 
      0.20 * cos(avg_H * 4.0 - CV_PI * 7.0/20.0); 
    double SL = avg_L - 50.0; 
    SL *= SL; 
    SL = SL * 0.015/sqrt(SL + 20.0) + 1.0; 
    double SC = avg_C * 0.045 + 1.0; 
    double SH = avg_C * T * 0.015 + 1.0; 
    double delta_Theta = avg_H/25.0 - CV_PI * 11.0/180.0; 
    delta_Theta = exp(delta_Theta * -delta_Theta) * (CV_PI/6.0); 
    double RT = pow(avg_C, 7.0); 
    RT = sqrt(RT/(RT + 6103515625.0)) * sin(delta_Theta) * -2.0; // 6103515625 = 25^7 
    delta_L /= SL; 
    delta_C /= SC; 
    delta_H /= SH; 
    return sqrt(delta_L * delta_L + delta_C * delta_C + delta_H * delta_H + RT * delta_C * delta_H); 
} 

Hy vọng nó giúp ai đó :)

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