Helpex - Trao đổi & giúp đỡ Đăng nhập
151

Tôi muốn thiết kế một chương trình có thể giúp tôi đánh giá giữa 5 màu được xác định trước, màu nào giống với màu thay đổi và với tỷ lệ bao nhiêu. Vấn đề là tôi không biết cách làm điều đó bằng tay từng bước một. Vì vậy, nó thậm chí còn khó khăn hơn để nghĩ về một chương trình.

Thêm chi tiết: Màu sắc là từ hình ảnh của các ống với gel có màu khác nhau. Tôi có 5 ống với màu sắc khác nhau, mỗi ống là đại diện cho 1 trong 5 cấp độ. Tôi muốn chụp ảnh các mẫu khác và trên máy tính để đánh giá mức độ của mẫu đó bằng cách so sánh màu sắc và tôi muốn biết rằng với tỷ lệ xấp xỉ cũng vậy. Tôi muốn một chương trình làm một cái gì đó như thế này: http://www.colortools.net/color_matcher.html

Nếu bạn có thể cho tôi biết những bước cần thực hiện, ngay cả khi chúng là những thứ để tôi suy nghĩ và làm thủ công. Nó sẽ rất hữu ích.

151 hữu ích 5 bình luận 99k xem chia sẻ
15 trả lời 15
118

Xem bài viết của Wikipedia về Sự khác biệt màu sắc cho các khách hàng tiềm năng phù hợp. Về cơ bản, bạn muốn tính toán một thước đo khoảng cách trong một số không gian màu đa chiều. Nhưng RGB không "đồng nhất về mặt nhận thức", do đó, số liệu khoảng cách Euclide RGB của bạn được đề xuất bởi Vadim sẽ không khớp với khoảng cách nhận biết của con người giữa các màu. Để bắt đầu, L a b * được dự định là một không gian màu thống nhất về mặt nhận thức và số liệu deltaE thường được sử dụng. Nhưng có nhiều không gian màu tinh tế hơn và các công thức deltaE tinh tế hơn, gần với nhận thức của con người hơn.

Bạn sẽ phải tìm hiểu thêm về không gian màu và chất chiếu sáng để thực hiện chuyển đổi. Nhưng đối với một công thức nhanh chóng mà là tốt hơn so với Euclide RGB số liệu, chỉ cần làm như sau: giả sử rằng giá trị RGB của bạn trong không gian màu sRGB, tìm sRGB để L một b * công thức chuyển đổi, chuyển đổi màu sắc sRGB của bạn để L một b *, và tính deltaE giữa hai giá trị L a b * của bạn. Nó không đắt tiền về mặt tính toán, nó chỉ là một số công thức phi tuyến và một số phép nhân và bổ sung.

118 hữu ích 5 bình luận chia sẻ
40

Chỉ là một ý tưởng đầu tiên xuất hiện trong đầu tôi (xin lỗi nếu ngu ngốc). Ba thành phần màu sắc có thể được giả định là tọa độ 3D của các điểm và sau đó bạn có thể tính khoảng cách giữa các điểm.

FE

Point1 has R1 G1 B1
Point2 has R2 G2 B2

Khoảng cách giữa các màu là

d=sqrt((r2-r1)^2+(g2-g1)^2+(b2-b1)^2)

Tỷ lệ là

p=d/sqrt((255)^2+(255)^2+(255)^2)
40 hữu ích 5 bình luận chia sẻ
21

Một giá trị màu có nhiều hơn một chiều, vì vậy không có cách nội tại để so sánh hai màu. Bạn phải xác định cho trường hợp sử dụng của bạn ý nghĩa của màu sắc và từ đó làm thế nào để so sánh chúng tốt nhất.

Nhiều khả năng bạn muốn so sánh các đặc tính màu sắc, độ bão hòa và / hoặc độ sáng của màu sắc khi được đặt với các thành phần màu đỏ / xanh lá cây / xanh dương. Nếu bạn gặp khó khăn trong việc tìm ra cách bạn muốn so sánh chúng, hãy lấy một số cặp màu mẫu và so sánh chúng về mặt tinh thần, sau đó thử tự biện minh / giải thích cho bạn tại sao chúng giống nhau / khác nhau.

Khi bạn biết thuộc tính / thành phần nào của màu bạn muốn so sánh, thì bạn cần tìm ra cách trích xuất thông tin đó từ một màu.

Nhiều khả năng bạn sẽ chỉ cần chuyển đổi màu từ đại diện RedGreenBlue phổ biến sang HueSaturationLightness, và sau đó tính toán một cái gì đó như

avghue = (color1.hue + color2.hue)/2
distance = abs(color1.hue-avghue)

Ví dụ này sẽ cung cấp cho bạn một giá trị vô hướng đơn giản cho biết độ dốc / màu của các màu cách nhau bao xa.

Xem HSL và HSV tại Wikipedia .

21 hữu ích 3 bình luận chia sẻ
20

Nếu bạn có hai Colorđối tượng c1c2, bạn chỉ có thể so sánh từng giá trị RGB với giá trị c1đó c2.

int diffRed   = Math.abs(c1.getRed()   - c2.getRed());
int diffGreen = Math.abs(c1.getGreen() - c2.getGreen());
int diffBlue  = Math.abs(c1.getBlue()  - c2.getBlue());

Những giá trị bạn chỉ có thể chia cho số lượng bão hòa chênh lệch (255) và bạn sẽ nhận được sự khác biệt giữa hai giá trị.

float pctDiffRed   = (float)diffRed   / 255;
float pctDiffGreen = (float)diffGreen / 255;
float pctDiffBlue   = (float)diffBlue  / 255;

Sau đó, bạn chỉ có thể tìm thấy sự khác biệt màu trung bình theo tỷ lệ phần trăm.

(pctDiffRed + pctDiffGreen + pctDiffBlue) / 3 * 100

Điều này sẽ cung cấp cho bạn một sự khác biệt về tỷ lệ phần trăm giữa c1c2.

20 hữu ích 2 bình luận chia sẻ
16

Thật ra tôi đã đi trên cùng một con đường vài tháng trước. không có câu trả lời hoàn hảo cho câu hỏi (đã được hỏi ở đây một vài lần) nhưng có một câu trả lời phức tạp hơn sau đó là câu trả lời sqrt (rr) vv và dễ dàng hơn để trực tiếp với RGB mà không cần di chuyển đến tất cả các không gian màu thay thế. Tôi đã tìm thấy công thức này ở đây là một xấp xỉ chi phí thấp của công thức thực khá phức tạp (bởi CIE là W3C của màu sắc, vì đây không phải là một nhiệm vụ chưa hoàn thành, bạn có thể tìm thấy các phương trình khác biệt màu cũ hơn và đơn giản hơn ở đó). chúc may mắn

Chỉnh sửa: Đối với hậu thế, đây là mã C có liên quan:

typedef struct {
     unsigned char r, g, b;
} RGB;

double ColourDistance(RGB e1, RGB e2)
{
    long rmean = ( (long)e1.r + (long)e2.r ) / 2;
    long r = (long)e1.r - (long)e2.r;
    long g = (long)e1.g - (long)e2.g;
    long b = (long)e1.b - (long)e2.b;
    return sqrt((((512+rmean)*r*r)>>8) + 4*g*g + (((767-rmean)*b*b)>>8));
}
16 hữu ích 1 bình luận chia sẻ
12

Một trong những phương pháp tốt nhất để so sánh hai màu theo nhận thức của con người là CIE76. Sự khác biệt được gọi là Delta-E. Khi nó nhỏ hơn 1, mắt người không thể nhận ra sự khác biệt.

Có lớp tiện ích màu tuyệt vời ColorUtils (mã bên dưới), bao gồm các phương thức so sánh CIE76. Nó được viết bởi Daniel Strebel, Đại học Zurich.

Từ ColorUtils. Class tôi sử dụng phương thức:

static double colorDifference(int r1, int g1, int b1, int r2, int g2, int b2)

r1, g1, b1 - Giá trị RGB của màu đầu tiên

r2, g2, b2 - Các giá trị RGB có màu thứ hai mà bạn muốn so sánh

Nếu bạn làm việc với Android, bạn có thể nhận được các giá trị như sau:

r1 = Color.red(pixel);

g1 = Color.green(pixel);

b1 = Color.blue(pixel);


ColorUtils. Class của Daniel Strebel, Đại học Zurich:

import android.graphics.Color;

public class ColorUtil {
public static int argb(int R, int G, int B) {
    return argb(Byte.MAX_VALUE, R, G, B);
}

public static int argb(int A, int R, int G, int B) {
    byte[] colorByteArr = {(byte) A, (byte) R, (byte) G, (byte) B};
    return byteArrToInt(colorByteArr);
}

public static int[] rgb(int argb) {
    return new int[]{(argb >> 16) & 0xFF, (argb >> 8) & 0xFF, argb & 0xFF};
}

public static int byteArrToInt(byte[] colorByteArr) {
    return (colorByteArr[0] << 24) + ((colorByteArr[1] & 0xFF) << 16)
            + ((colorByteArr[2] & 0xFF) << 8) + (colorByteArr[3] & 0xFF);
}

public static int[] rgb2lab(int R, int G, int B) {
    //http://www.brucelindbloom.com

    float r, g, b, X, Y, Z, fx, fy, fz, xr, yr, zr;
    float Ls, as, bs;
    float eps = 216.f / 24389.f;
    float k = 24389.f / 27.f;

    float Xr = 0.964221f;  // reference white D50
    float Yr = 1.0f;
    float Zr = 0.825211f;

    // RGB to XYZ
    r = R / 255.f; //R 0..1
    g = G / 255.f; //G 0..1
    b = B / 255.f; //B 0..1

    // assuming sRGB (D65)
    if (r <= 0.04045)
        r = r / 12;
    else
        r = (float) Math.pow((r + 0.055) / 1.055, 2.4);

    if (g <= 0.04045)
        g = g / 12;
    else
        g = (float) Math.pow((g + 0.055) / 1.055, 2.4);

    if (b <= 0.04045)
        b = b / 12;
    else
        b = (float) Math.pow((b + 0.055) / 1.055, 2.4);


    X = 0.436052025f * r + 0.385081593f * g + 0.143087414f * b;
    Y = 0.222491598f * r + 0.71688606f * g + 0.060621486f * b;
    Z = 0.013929122f * r + 0.097097002f * g + 0.71418547f * b;

    // XYZ to Lab
    xr = X / Xr;
    yr = Y / Yr;
    zr = Z / Zr;

    if (xr > eps)
        fx = (float) Math.pow(xr, 1 / 3.);
    else
        fx = (float) ((k * xr + 16.) / 116.);

    if (yr > eps)
        fy = (float) Math.pow(yr, 1 / 3.);
    else
        fy = (float) ((k * yr + 16.) / 116.);

    if (zr > eps)
        fz = (float) Math.pow(zr, 1 / 3.);
    else
        fz = (float) ((k * zr + 16.) / 116);

    Ls = (116 * fy) - 16;
    as = 500 * (fx - fy);
    bs = 200 * (fy - fz);

    int[] lab = new int[3];
    lab[0] = (int) (2.55 * Ls + .5);
    lab[1] = (int) (as + .5);
    lab[2] = (int) (bs + .5);
    return lab;
}

/**
 * Computes the difference between two RGB colors by converting them to the L*a*b scale and
 * comparing them using the CIE76 algorithm { http://en.wikipedia.org/wiki/Color_difference#CIE76}
 */
public static double getColorDifference(int a, int b) {
    int r1, g1, b1, r2, g2, b2;
    r1 = Color.red(a);
    g1 = Color.green(a);
    b1 = Color.blue(a);
    r2 = Color.red(b);
    g2 = Color.green(b);
    b2 = Color.blue(b);
    int[] lab1 = rgb2lab(r1, g1, b1);
    int[] lab2 = rgb2lab(r2, g2, b2);
    return Math.sqrt(Math.pow(lab2[0] - lab1[0], 2) + Math.pow(lab2[1] - lab1[1], 2) + Math.pow(lab2[2] - lab1[2], 2));
}
}
12 hữu ích 3 bình luận chia sẻ
9

Chỉ là một câu trả lời khác, mặc dù nó tương tự như câu trả lời của Supr - chỉ là một không gian màu khác.

Vấn đề là: Con người nhận thấy sự khác biệt về màu sắc không đồng nhất và không gian màu RGB đang bỏ qua điều này. Kết quả là nếu bạn sử dụng không gian màu RGB và chỉ cần tính khoảng cách euclide giữa 2 màu, bạn có thể có một sự khác biệt hoàn toàn chính xác về mặt toán học, nhưng sẽ không trùng với những gì con người sẽ nói với bạn.

Đây có thể không phải là vấn đề - tôi nghĩ sự khác biệt không lớn, nhưng nếu bạn muốn giải quyết vấn đề "tốt hơn" này, bạn nên chuyển đổi màu RGB của mình thành không gian màu được thiết kế riêng để tránh vấn đề trên. Có một số cải tiến từ các mô hình trước đó (vì điều này dựa trên nhận thức của con người, chúng ta cần đo các giá trị "chính xác" dựa trên dữ liệu thử nghiệm). không gian màu Lab mà tôi nghĩ sẽ là tốt nhất mặc dù hơi phức tạp để chuyển đổi nó thành. Đơn giản hơn sẽ là một CIE XYZ .

Đây là một trang web liệt kê các công thức để chuyển đổi giữa các không gian màu khác nhau để bạn có thể thử nghiệm một chút.

9 hữu ích 0 bình luận chia sẻ
2

Cách tốt nhất là deltaE. DeltaE là một con số cho thấy sự khác biệt của màu sắc. Nếu deltae <1 thì sự khác biệt không thể nhận ra bằng mắt người. Tôi đã viết một mã bằng canvas và js để chuyển đổi rgb sang lab và sau đó tính delta e. Trong ví dụ này, mã nhận dạng các pixel có màu khác với màu cơ bản mà tôi đã lưu là LAB1. và sau đó nếu nó khác nhau làm cho các pixel đó màu đỏ. Bạn có thể tăng hoặc giảm độ nhạy của chênh lệch màu với tăng hoặc giảm phạm vi delta e chấp nhận được. Trong ví dụ này, tôi đã gán 10 cho deltaE trong dòng mà tôi đã viết (deltae <= 10):

<script>   
  var constants = {
    canvasWidth: 700, // In pixels.
    canvasHeight: 600, // In pixels.
    colorMap: new Array() 
          };



  // -----------------------------------------------------------------------------------------------------

  function fillcolormap(imageObj1) {


    function rgbtoxyz(red1,green1,blue1){ // a converter for converting rgb model to xyz model
 var red2 = red1/255;
 var green2 = green1/255;
 var blue2 = blue1/255;
 if(red2>0.04045){
      red2 = (red2+0.055)/1.055;
      red2 = Math.pow(red2,2.4);
 }
 else{
      red2 = red2/12.92;
 }
 if(green2>0.04045){
      green2 = (green2+0.055)/1.055;
      green2 = Math.pow(green2,2.4);    
 }
 else{
      green2 = green2/12.92;
 }
 if(blue2>0.04045){
      blue2 = (blue2+0.055)/1.055;
      blue2 = Math.pow(blue2,2.4);    
 }
 else{
      blue2 = blue2/12.92;
 }
 red2 = (red2*100);
 green2 = (green2*100);
 blue2 = (blue2*100);
 var x = (red2 * 0.4124) + (green2 * 0.3576) + (blue2 * 0.1805);
 var y = (red2 * 0.2126) + (green2 * 0.7152) + (blue2 * 0.0722);
 var z = (red2 * 0.0193) + (green2 * 0.1192) + (blue2 * 0.9505);
 var xyzresult = new Array();
 xyzresult[0] = x;
 xyzresult[1] = y;
 xyzresult[2] = z;
 return(xyzresult);
} //end of rgb_to_xyz function
function xyztolab(xyz){ //a convertor from xyz to lab model
 var x = xyz[0];
 var y = xyz[1];
 var z = xyz[2];
 var x2 = x/95.047;
 var y2 = y/100;
 var z2 = z/108.883;
 if(x2>0.008856){
      x2 = Math.pow(x2,1/3);
 }
 else{
      x2 = (7.787*x2) + (16/116);
 }
 if(y2>0.008856){
      y2 = Math.pow(y2,1/3);
 }
 else{
      y2 = (7.787*y2) + (16/116);
 }
 if(z2>0.008856){
      z2 = Math.pow(z2,1/3);
 }
 else{
      z2 = (7.787*z2) + (16/116);
 }
 var l= 116*y2 - 16;
 var a= 500*(x2-y2);
 var b= 200*(y2-z2);
 var labresult = new Array();
 labresult[0] = l;
 labresult[1] = a;
 labresult[2] = b;
 return(labresult);

}

    var canvas = document.getElementById('myCanvas');
    var context = canvas.getContext('2d');
    var imageX = 0;
    var imageY = 0;

    context.drawImage(imageObj1, imageX, imageY, 240, 140);
    var imageData = context.getImageData(0, 0, 240, 140);
    var data = imageData.data;
    var n = data.length;
   // iterate over all pixels

    var m = 0;
    for (var i = 0; i < n; i += 4) {
      var red = data[i];
      var green = data[i + 1];
      var blue = data[i + 2];
    var xyzcolor = new Array();
    xyzcolor = rgbtoxyz(red,green,blue);
    var lab = new Array();
    lab = xyztolab(xyzcolor);
    constants.colorMap.push(lab); //fill up the colormap array with lab colors.         
      } 

  }

// ------------------------------------------------ -------------------------------------------------- ---

    function colorize(pixqty) {

         function deltae94(lab1,lab2){    //calculating Delta E 1994

         var c1 = Math.sqrt((lab1[1]*lab1[1])+(lab1[2]*lab1[2]));
         var c2 =  Math.sqrt((lab2[1]*lab2[1])+(lab2[2]*lab2[2]));
         var dc = c1-c2;
         var dl = lab1[0]-lab2[0];
         var da = lab1[1]-lab2[1];
         var db = lab1[2]-lab2[2];
         var dh = Math.sqrt((da*da)+(db*db)-(dc*dc));
         var first = dl;
         var second = dc/(1+(0.045*c1));
         var third = dh/(1+(0.015*c1));
         var deresult = Math.sqrt((first*first)+(second*second)+(third*third));
         return(deresult);
          } // end of deltae94 function
    var lab11 =  new Array("80","-4","21");
    var lab12 = new Array();
    var k2=0;
    var canvas = document.getElementById('myCanvas');
                                        var context = canvas.getContext('2d');
                                        var imageData = context.getImageData(0, 0, 240, 140);
                                        var data = imageData.data;

    for (var i=0; i<pixqty; i++) {

    lab12 = constants.colorMap[i];

    var deltae = deltae94(lab11,lab12);     
                                        if (deltae <= 10) {

                                        data[i*4] = 255;
                                        data[(i*4)+1] = 0;
                                        data[(i*4)+2] = 0;  
                                        k2++;
                                        } // end of if 
                                } //end of for loop
    context.clearRect(0,0,240,140);
    alert(k2);
    context.putImageData(imageData,0,0);
} 
// -----------------------------------------------------------------------------------------------------

$(window).load(function () {    
  var imageObj = new Image();
  imageObj.onload = function() {
  fillcolormap(imageObj);    
  }
  imageObj.src = './mixcolor.png';
});

// ---------------------------------------------------------------------------------------------------
 var pixno2 = 240*140; 
 </script>
2 hữu ích 2 bình luận chia sẻ
2

Tất cả các phương pháp dưới đây dẫn đến một thang điểm từ 0-100.

internal static class ColorDifference
{
    internal enum Method
    {
        Binary, // true or false, 0 is false
        Square,
        Dimensional,
        CIE76
    }

    public static double Calculate(Method method, int argb1, int argb2)
    {
        int[] c1 = ColorConversion.ArgbToArray(argb1);
        int[] c2 = ColorConversion.ArgbToArray(argb2);
        return Calculate(method, c1[1], c2[1], c1[2], c2[2], c1[3], c2[3], c1[0], c2[0]);
    }

    public static double Calculate(Method method, int r1, int r2, int g1, int g2, int b1, int b2, int a1 = -1, int a2 = -1)
    {
        switch (method)
        {
            case Method.Binary:
                return (r1 == r2 && g1 == g2 && b1 == b2 && a1 == a2) ? 0 : 100;
            case Method.CIE76:
                return CalculateCIE76(r1, r2, g1, g2, b1, b2);
            case Method.Dimensional:
                if (a1 == -1 || a2 == -1) return Calculate3D(r1, r2, g1, g2, b1, b2);
                else return Calculate4D(r1, r2, g1, g2, b1, b2, a1, a2);
            case Method.Square:
                return CalculateSquare(r1, r2, g1, g2, b1, b2, a1, a2);
            default:
                throw new InvalidOperationException();
        }
    }

    public static double Calculate(Method method, Color c1, Color c2, bool alpha)
    {
        switch (method)
        {
            case Method.Binary:
                return (c1.R == c2.R && c1.G == c2.G && c1.B == c2.B && (!alpha || c1.A == c2.A)) ? 0 : 100;
            case Method.CIE76:
                if (alpha) throw new InvalidOperationException();
                return CalculateCIE76(c1, c2);
            case Method.Dimensional:
                if (alpha) return Calculate4D(c1, c2);
                else return Calculate3D(c1, c2);
            case Method.Square:
                if (alpha) return CalculateSquareAlpha(c1, c2);
                else return CalculateSquare(c1, c2);
            default:
                throw new InvalidOperationException();
        }
    }

    // A simple idea, based on on a Square
    public static double CalculateSquare(int argb1, int argb2)
    {
        int[] c1 = ColorConversion.ArgbToArray(argb1);
        int[] c2 = ColorConversion.ArgbToArray(argb2);
        return CalculateSquare(c1[1], c2[1], c1[2], c2[2], c1[3], c2[3]);
    }

    public static double CalculateSquare(Color c1, Color c2)
    {
        return CalculateSquare(c1.R, c2.R, c1.G, c2.G, c1.B, c2.B);
    }

    public static double CalculateSquareAlpha(int argb1, int argb2)
    {
        int[] c1 = ColorConversion.ArgbToArray(argb1);
        int[] c2 = ColorConversion.ArgbToArray(argb2);
        return CalculateSquare(c1[1], c2[1], c1[2], c2[2], c1[3], c2[3], c1[0], c2[0]);
    }

    public static double CalculateSquareAlpha(Color c1, Color c2)
    {
        return CalculateSquare(c1.R, c2.R, c1.G, c2.G, c1.B, c2.B, c1.A, c2.A);
    }

    public static double CalculateSquare(int r1, int r2, int g1, int g2, int b1, int b2, int a1 = -1, int a2 = -1)
    {
        if (a1 == -1 || a2 == -1) return (Math.Abs(r1 - r2) + Math.Abs(g1 - g2) + Math.Abs(b1 - b2)) / 7.65;
        else return (Math.Abs(r1 - r2) + Math.Abs(g1 - g2) + Math.Abs(b1 - b2) + Math.Abs(a1 - a2)) / 10.2;
    }

    // from:http://stackoverflow.com/questions/9018016/how-to-compare-two-colors
    public static double Calculate3D(int argb1, int argb2)
    {
        int[] c1 = ColorConversion.ArgbToArray(argb1);
        int[] c2 = ColorConversion.ArgbToArray(argb2);
        return Calculate3D(c1[1], c2[1], c1[2], c2[2], c1[3], c2[3]);
    }

    public static double Calculate3D(Color c1, Color c2)
    {
        return Calculate3D(c1.R, c2.R, c1.G, c2.G, c1.B, c2.B);
    }

    public static double Calculate3D(int r1, int r2, int g1, int g2, int b1, int b2)
    {
        return Math.Sqrt(Math.Pow(Math.Abs(r1 - r2), 2) + Math.Pow(Math.Abs(g1 - g2), 2) + Math.Pow(Math.Abs(b1 - b2), 2)) / 4.41672955930063709849498817084;
    }

    // Same as above, but made 4D to include alpha channel
    public static double Calculate4D(int argb1, int argb2)
    {
        int[] c1 = ColorConversion.ArgbToArray(argb1);
        int[] c2 = ColorConversion.ArgbToArray(argb2);
        return Calculate4D(c1[1], c2[1], c1[2], c2[2], c1[3], c2[3], c1[0], c2[0]);
    }

    public static double Calculate4D(Color c1, Color c2)
    {
        return Calculate4D(c1.R, c2.R, c1.G, c2.G, c1.B, c2.B, c1.A, c2.A);
    }

    public static double Calculate4D(int r1, int r2, int g1, int g2, int b1, int b2, int a1, int a2)
    {
        return Math.Sqrt(Math.Pow(Math.Abs(r1 - r2), 2) + Math.Pow(Math.Abs(g1 - g2), 2) + Math.Pow(Math.Abs(b1 - b2), 2) + Math.Pow(Math.Abs(a1 - a2), 2)) / 5.1;
    }

    /**
    * Computes the difference between two RGB colors by converting them to the L*a*b scale and
    * comparing them using the CIE76 algorithm { http://en.wikipedia.org/wiki/Color_difference#CIE76}
    */
    public static double CalculateCIE76(int argb1, int argb2)
    {
        return CalculateCIE76(Color.FromArgb(argb1), Color.FromArgb(argb2));
    }

    public static double CalculateCIE76(Color c1, Color c2)
    {
        return CalculateCIE76(c1.R, c2.R, c1.G, c2.G, c1.B, c2.B);
    }

    public static double CalculateCIE76(int r1, int r2, int g1, int g2, int b1, int b2)
    {
        int[] lab1 = ColorConversion.ColorToLab(r1, g1, b1);
        int[] lab2 = ColorConversion.ColorToLab(r2, g2, b2);
        return Math.Sqrt(Math.Pow(lab2[0] - lab1[0], 2) + Math.Pow(lab2[1] - lab1[1], 2) + Math.Pow(lab2[2] - lab1[2], 2)) / 2.55;
    }
}


internal static class ColorConversion
{

    public static int[] ArgbToArray(int argb)
    {
        return new int[] { (argb >> 24), (argb >> 16) & 0xFF, (argb >> 8) & 0xFF, argb & 0xFF };
    }

    public static int[] ColorToLab(int R, int G, int B)
    {
        // http://www.brucelindbloom.com

        double r, g, b, X, Y, Z, fx, fy, fz, xr, yr, zr;
        double Ls, fas, fbs;
        double eps = 216.0f / 24389.0f;
        double k = 24389.0f / 27.0f;

        double Xr = 0.964221f;  // reference white D50
        double Yr = 1.0f;
        double Zr = 0.825211f;

        // RGB to XYZ
        r = R / 255.0f; //R 0..1
        g = G / 255.0f; //G 0..1
        b = B / 255.0f; //B 0..1

        // assuming sRGB (D65)
        if (r <= 0.04045) r = r / 12;
        else r = (float)Math.Pow((r + 0.055) / 1.055, 2.4);

        if (g <= 0.04045) g = g / 12;
        else g = (float)Math.Pow((g + 0.055) / 1.055, 2.4);

        if (b <= 0.04045) b = b / 12;
        else b = (float)Math.Pow((b + 0.055) / 1.055, 2.4);

        X = 0.436052025f * r + 0.385081593f * g + 0.143087414f * b;
        Y = 0.222491598f * r + 0.71688606f * g + 0.060621486f * b;
        Z = 0.013929122f * r + 0.097097002f * g + 0.71418547f * b;

        // XYZ to Lab
        xr = X / Xr;
        yr = Y / Yr;
        zr = Z / Zr;

        if (xr > eps) fx = (float)Math.Pow(xr, 1 / 3.0);
        else fx = (float)((k * xr + 16.0) / 116.0);

        if (yr > eps) fy = (float)Math.Pow(yr, 1 / 3.0);
        else fy = (float)((k * yr + 16.0) / 116.0);

        if (zr > eps) fz = (float)Math.Pow(zr, 1 / 3.0);
        else fz = (float)((k * zr + 16.0) / 116);

        Ls = (116 * fy) - 16;
        fas = 500 * (fx - fy);
        fbs = 200 * (fy - fz);

        int[] lab = new int[3];
        lab[0] = (int)(2.55 * Ls + 0.5);
        lab[1] = (int)(fas + 0.5);
        lab[2] = (int)(fbs + 0.5);
        return lab;
    }
}
2 hữu ích 0 bình luận chia sẻ
1

Tôi hy vọng bạn muốn phân tích toàn bộ hình ảnh ở cuối, phải không? Vì vậy, bạn có thể kiểm tra sự khác biệt nhỏ nhất / cao nhất đối với ma trận màu nhận dạng.

Hầu hết các phép toán để xử lý đồ họa đều sử dụng ma trận, bởi vì các thuật toán có thể sử dụng chúng thường nhanh hơn điểm cổ điển theo khoảng cách điểm và tính toán so sánh. (ví dụ: đối với các hoạt động sử dụng DirectX, OpenGL, ...)

Vì vậy, tôi nghĩ rằng bạn nên bắt đầu ở đây:

http://en.wikipedia.org/wiki/Identity_matrix

http://en.wikipedia.org/wiki/Matrix_difference_equation

... và như Beska đã nhận xét ở trên:

Điều này có thể không mang lại sự khác biệt "có thể nhìn thấy" tốt nhất ...

Điều đó cũng có nghĩa là thuật toán của bạn phụ thuộc vào định nghĩa "tương tự" của bạn nếu bạn đang xử lý hình ảnh.

1 hữu ích 0 bình luận chia sẻ
1

Một phương pháp đơn giản chỉ sử dụng RGB là

cR=R1-R2 
cG=G1-G2 
cB=B1-B2 
uR=R1+R2 
distance=cR*cR*(2+uR/256) + cG*cG*4 + cB*cB*(2+(255-uR)/256)

Tôi đã sử dụng cái này một thời gian rồi và nó hoạt động đủ tốt cho hầu hết các mục đích.

1 hữu ích 2 bình luận chia sẻ
0

Bạn sẽ cần chuyển đổi bất kỳ màu RGB nào sang không gian màu Lab để có thể so sánh chúng theo cách mà con người nhìn thấy chúng. Nếu không, bạn sẽ có được màu RGB 'khớp' theo một số cách rất lạ.

Liên kết wikipedia về Sự khác biệt màu sắc cung cấp cho bạn một phần giới thiệu về các thuật toán khác biệt không gian màu Lab khác nhau đã được xác định qua nhiều năm. Đơn giản nhất chỉ cần kiểm tra khoảng cách Euclidian của hai màu trong phòng thí nghiệm, hoạt động nhưng có một vài sai sót.

Thuận tiện có triển khai Java thuật toán CIEDE2000 tinh vi hơn trong dự án OpenIMAJ . Cung cấp cho nó hai bộ màu Lab của bạn và nó sẽ trả lại cho bạn giá trị khoảng cách duy nhất.

0 hữu ích 0 bình luận chia sẻ
0

Cách "đúng" duy nhất để so sánh màu sắc là làm điều đó với deltaE trong CIELab hoặc CIELuv.

Nhưng đối với rất nhiều ứng dụng tôi nghĩ rằng đây là một xấp xỉ đủ tốt:

distance = 3 * |dR| + 4 * |dG| + 3 * |dB|

Tôi nghĩ rằng một khoảng cách manhattan có ý nghĩa hơn khi so sánh màu sắc. Hãy nhớ rằng màu gốc chỉ có trong đầu của chúng tôi. Họ không có bất kỳ ý nghĩa vật lý. CIELab và CIELuv được mô hình hóa theo thống kê từ nhận thức của chúng ta về màu sắc.

0 hữu ích 0 bình luận chia sẻ
0

Để nhanh và bẩn, bạn có thể làm

import java.awt.Color;
private Color dropPrecision(Color c,int threshold){
    return new Color((c.getRed()/threshold),
                     (c.getGreen()/threshold),
                     (c.getBlue()/threshold));
}
public boolean inThreshold(Color _1,Color _2,int threshold){
    return dropPrecision(_1,threshold)==dropPrecision(_2,threshold);
}

sử dụng phân chia số nguyên để định lượng màu sắc.

0 hữu ích 0 bình luận chia sẻ
0

Tôi đã sử dụng điều này trong Android của tôi và nó có vẻ thỏa đáng mặc dù không nên sử dụng không gian RGB:

    public double colourDistance(int red1,int green1, int blue1, int red2, int green2, int blue2)
{
      double rmean = ( red1 + red2 )/2;
    int r = red1 - red2;
    int g = green1 - green2;
    int b = blue1 - blue2;
    double weightR = 2 + rmean/256;
    double weightG = 4.0;
    double weightB = 2 + (255-rmean)/256;
    return Math.sqrt(weightR*r*r + weightG*g*g + weightB*b*b);
}

Sau đó, tôi đã sử dụng như sau để có được phần trăm tương tự:

double maxColDist = 764.8339663572415;
double d1 = colourDistance(red1,green1,blue1,red2,green2,blue2);
String s1 = (int) Math.round(((maxColDist-d1)/maxColDist)*100) + "% match";

Nó hoạt động đủ tốt.

0 hữu ích 0 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ algorithm colors compare rgb hsv , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading