2015-12-27 15 views
6

Tôi đang cố gắng tạo hình nền và đang sử dụng chuyển đổi HSV trong lớp "android.graphics.color". Tôi đã rất ngạc nhiên khi tôi nhận ra rằng một chuyển đổi của một màu HSV tạo ra với một màu sắc quy định (0..360) cho một màu rgb (một số nguyên) và một chuyển đổi trở lại màu HSV sẽ không dẫn đến cùng một màu sắc. Đây là mã của tôi:Chuyển đổi HSV không chính xác trên Android

int c = Color.HSVToColor(new float[] { 100f, 1, 1 }); 
float[] f = new float[3]; 
Color.colorToHSV(c, f); 
alert(f[0]); 

Tôi bắt đầu với màu 100 độ và kết quả là 99.76471. Tôi tự hỏi tại sao có (theo ý kiến ​​của tôi) tương đối không chính xác lớn.

Nhưng vấn đề lớn hơn nhiều là khi bạn đặt lại giá trị đó trong mã, kết quả mới sẽ giảm một lần nữa.

int c = Color.HSVToColor(new float[] { 99.76471f, 1, 1 }); 
float[] f = new float[3]; 
Color.colorToHSV(c, f); 
alert(f[0]); 

Nếu tôi bắt đầu với 99.76471, tôi nhận được 99.52941. Đây là một vấn đề đối với tôi. Tôi đã làm một cái gì đó tương tự trong java với lớp "java.awt.Color", nơi tôi không có những vấn đề đó. Thật không may, tôi không thể sử dụng lớp này trong android.

+0

Tôi * tin rằng đây là trường hợp của một chuyển đổi khác được sử dụng giữa số nguyên 16 và 32 bit, tuy nhiên điều này có thể là cách tắt. Tôi nhớ một số năm trước đây đang gặp sự cố với các tệp âm thanh và chuyển đổi từ một mảng byte. Cuối cùng tôi chỉ làm tròn hình lên đến toàn bộ int gần nhất. – dave

+1

Tôi ủng hộ ý tưởng của dave. Một điều có thể hữu ích là nhận thấy rằng sự khác biệt giữa giá trị ban đầu của 100 và kết quả được làm tròn của 99.76471 là 60/255 và 255 = 2^8-1 (Nó khá phổ biến để lưu trữ giá trị rgb trên 8 bit) . Điều này cũng đúng với 99.76471 và 99.52941. Tôi không có một lý thuyết hoàn chỉnh, nhưng có vẻ như số học cơ bản đã đi sai. – elias

Trả lời

1

Đây là một vấn đề thú vị. Nó không thể tránh được với lớp android vì độ chính xác thấp. Tuy nhiên, tôi đã tìm thấy một giải pháp tương tự được viết bằng javascript here.

Nếu nó đủ quan trọng để bạn có thể muốn xác định phương pháp riêng của mình/lớp để thực hiện chuyển đổi là, đây là một sự chuyển đổi Java mà nên cung cấp cho bạn độ chính xác tốt hơn:

@Size(3) 
/** Does the same as {@link android.graphics.Color#colorToHSV(int, float[])} */ 
public double[] colorToHSV(@ColorInt int color) { 
    //this line copied vertabim 
    return rgbToHsv((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF); 
} 

@Size(3) 
public double[] rgbToHsv(double r, double g, double b) { 
    final double max = Math.max(r, Math.max(g, b)); 
    final double min = Math.min(r, Math.min(g, b)); 
    final double diff = max - min; 
    final double h; 
    final double s = ((max == 0d)? 0d : diff/max); 
    final double v = max/255d; 
    if (min == max) { 
     h = 0d; 
    } else if (r == max) { 
     double tempH = (g - b) + diff * (g < b ? 6: 0); 
     tempH /= 6 * diff; 
     h = tempH; 
    } else if (g == max) { 
     double tempH = (b - r) + diff * 2; 
     tempH /= 6 * diff; 
     h = tempH; 
    } else { 
     double tempH = (r - g) + diff * 4; 
     tempH /= 6 * diff; 
     h = tempH; 
    } 
    return new double[] { h, s, v }; 
} 

Tôi phải thú nhận sự thiếu hiểu biết ở đây - Tôi đã thực hiện chuyển đổi nhanh và không có thời gian để kiểm tra đúng cách. Có thể có một giải pháp tối ưu hơn, nhưng điều này sẽ giúp bạn bắt đầu ít nhất.

+0

Vâng có vẻ như đôi chính xác hơn không giải quyết được vấn đề của tôi bởi vì nó vẫn làm tròn đến một int và có thể có vấn đề mà tôi không nhận được cùng một giá trị trở lại – user2957782

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