Android上的HSV转换不准确



我正在尝试创建一个壁纸,并在"android.graphics.color"类中使用HSV转换。当我意识到将创建的具有指定色调(0..360)的HSV颜色转换为rgb颜色(整数)并反向转换为HSV颜色不会产生相同的色调时,我感到非常惊讶。这是我的代码:

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

我从100度的色调开始,结果是99.76471。我想知道为什么(在我看来)有那么大的不准确性。

但更大的问题是,当你再次将该值放入代码中时,新结果会再次减少。

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

如果我从99.76471开始,我得到了99.52941。这对我来说是个问题。我在java中用"java.awt.Color"类做了类似的事情,在那里我没有这些问题。不幸的是,我不能在android中使用这个类。

这是一个有趣的问题。由于浮点精度低,android类无法避免这种情况。然而,我在这里找到了一个用javascript编写的类似解决方案。

如果你想定义自己的方法/类来进行转换,这一点足够重要,那么这里有一个Java转换,它应该会给你更好的精度:

@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 };
}

我不得不承认我的无知——我很快就转换了,没有时间进行适当的测试。可能有一个更优化的解决方案,但这至少应该让你开始。

不要错过源链接中的镜像过程。接下来是Kotlin语言的翻译。

    fun hsvToRGB(hsv: DoubleArray): Int {
        val i = floor(hsv[0] * 6).toInt()
        val f = hsv[0] * 6 - i
        val p = hsv[2] * (1 - hsv[1])
        val q = hsv[2] * (1 - f * hsv[1])
        val t = hsv[2] * (1 - (1 - f) * hsv[1])
        val r: Double
        val g: Double
        val b: Double
        when (i % 6) {
            0 -> {r = hsv[2]; g = t; b = p}
            1 -> {r = q; g = hsv[2]; b = p}
            2 -> {r = p; g = hsv[2]; b = t}
            3 -> {r = p; g = q; b = hsv[2]}
            4 -> {r = t; g = p; b = hsv[2]}
            5 -> {r = hsv[2]; g = p; b = q}
            else -> {r = 0.0; g = 0.0; b = 0.0}
        }
        return Color.rgb((r * 255).roundToInt(), (g * 255).roundToInt(), (b * 255).roundToInt())
    }
    fun rgbToHSV(color: Int, target: DoubleArray) {
        val r = Color.red(color).toDouble()
        val g = Color.green(color).toDouble()
        val b = Color.blue(color).toDouble()
        val max = kotlin.math.max(r, kotlin.math.max(g, b))
        val min = kotlin.math.min(r, kotlin.math.min(g, b))
        val diff = max - min
        target[1] =  if (max == 0.0)  {0.0} else {diff / max}
        target[2] = max / 255.0
        target[0] = if (min == max) {
            0.0
        } else if (r == max) {
            var tempH = (g - b) + diff * if (g < b) { 6} else {0}
            tempH /= 6 * diff
            tempH
        } else if (g == max) {
            var tempH = (b - r) + diff * 2
            tempH /= 6 * diff
            tempH
        } else {
            var tempH = (r - g) + diff * 4
            tempH /= 6 * diff
            tempH
        }
    }

最新更新