18

我有以下代码:

public List<Tuple<double, double, double>> GetNormalizedPixels(Bitmap image)
{
    System.Drawing.Imaging.BitmapData data = image.LockBits(
        new Rectangle(0, 0, image.Width, image.Height),
        System.Drawing.Imaging.ImageLockMode.ReadOnly,
        image.PixelFormat);

    int pixelSize = Image.GetPixelFormatSize(image.PixelFormat) / 8;

    var result = new List<Tuple<double, double, double>>();

    unsafe
    {
        for (int y = 0; y < data.Height; ++y)
        {
            byte* row = (byte*)data.Scan0 + (y * data.Stride);

            for (int x = 0; x < data.Width; ++x)
            {
                Color c = Color.FromArgb(
                    row[x * pixelSize + 3],
                    row[x * pixelSize + 2],
                    row[x * pixelSize + 1],
                    row[x * pixelSize]);

                // (*)
                result.Add(Tuple.Create(
                    1.0 * c.R / 255,
                    1.0 * c.G / 255,
                    1.0 * c.B / 255);
            }
        }
    }

    image.UnlockBits(data);

    return result;
}

关键片段(*)是这样的:

result.Add(Tuple.Create(
    1.0 * c.R / 255,
    1.0 * c.G / 255,
    1.0 * c.B / 255);

它添加了一个像素,其组件缩放到范围[0, 1],以进一步用于具有不同分类器的分类任务。其中一些需要像这样对属性进行规范化,而另一些则不在乎 - 因此有这个功能。

但是,当我想对不同颜色空间中的像素进行分类时,我应该怎么RGBL*a*b*?而色彩空间中所有坐标的值都RGB落入色彩空间的范围内,称为[0,256)无界。L*a*b*a*b*

因此,当将片段 (*) 更改为:

Lab lab = c.ToLab();

result.Add(Tuple.Create(
    1.0 * lab.L / 100,
    1.0 * lab.A / ?,
    1.0 * lab.B / ?);

ToLab是一种扩展方法,使用适当的算法从这里实现)

问号应该填什么?

4

3 回答 3

30

实际上,所有可能RGB颜色的数量是有限的,因此L*a*b*空间是有界的。使用以下简单程序很容易找到坐标范围:

Color c;

double maxL = double.MinValue;
double maxA = double.MinValue;
double maxB = double.MinValue;
double minL = double.MaxValue;
double minA = double.MaxValue;
double minB = double.MaxValue;

for (int r = 0; r < 256; ++r)
    for (int g = 0; g < 256; ++g)
        for (int b = 0; b < 256; ++b)
        {
            c = Color.FromArgb(r, g, b);

            Lab lab = c.ToLab();

            maxL = Math.Max(maxL, lab.L);
            maxA = Math.Max(maxA, lab.A);
            maxB = Math.Max(maxB, lab.B);
            minL = Math.Min(minL, lab.L);
            minA = Math.Min(minA, lab.A);
            minB = Math.Min(minB, lab.B);
        }

Console.WriteLine("maxL = " + maxL + ", maxA = " + maxA + ", maxB = " + maxB);
Console.WriteLine("minL = " + minL + ", minA = " + minA + ", minB = " + minB);

或使用任何其他语言的类似语言。

因此,CIELAB空间坐标范围如下:

L in [0, 100]

[-86.185, 98.254] 中的 A

[-107.863, 94.482] 中的 B

答案是:

Lab lab = c.ToLab();

result.Add(Tuple.Create(
    1.0 * lab.L / 100,
    1.0 * (lab.A + 86.185) / 184.439,
    1.0 * (lab.B + 107.863) / 202.345);
于 2013-09-30T16:20:38.540 回答
14

通常,以下值有效,因为它是常见颜色转换算法的标准输出:

  • L* 轴(亮度)范围从 0 到 100

  • a* 和 b*(颜色属性)轴范围从 -128 到 +127

更多信息可以在这里找到。

于 2015-04-27T21:11:53.753 回答
1

如果 Lab 转换代码是按照 Lab-colors 定义实现的(例如参见Lab 颜色空间),则f(...)用于定义 的函数 ,Lab[4/29,1] 内发生变化,因此

L = 116 * f(y) - 16 is in [0,100]
a = 500 * (f(x)-f(y)) is in [-500*25/29, 500*25/29]
b = 200 * (f(y)-f(z)) is in [-200*25/29, 200*25/29]

有些人(比如 bortizj 在他的回复中)将这些值标准化为范围,一个字节变量可以保存。因此,您必须分析代码以确定它产生的范围。但同样,Wiki 中的公式将为您提供上述范围。相同的范围将为您提供此处的代码

于 2016-04-21T11:55:30.087 回答