汇总HSL值

时间:2017-09-18 01:40:00

标签: algorithm math colors aggregate median

我编写了一段采用输入HSL颜色值的代码,并将其归类为八种预定义颜色之一。因为我正在测量的物体的颜色并不是完全“平滑”(确切的H,S和L值逐像素变化,但每种颜色的范围都有限,视情况而定),我想在将得到的HSL值标识为特定颜色之前,汇总对象上几个像素的H,S和L'。

举一个例子,如果对象实际上是黑色的,那么它的任何像素的H应该在24-33的范围内,而黄色的H范围是33-37。聚合几个测量的H,而不是依赖于单个测量,将倾向于产生更接近正确颜色的任何范围的中间的结果,这有望降低需要解释模糊33情况的可能性。

我一直在使用类似于中位数的东西作为我的聚合算法(下面显示的精确算法),但我遇到过一个不能正常工作的情况。特别是,紫色物体的H范围包括231-240和0-10(240是最大H值,因此它包裹)。所有其他颜色'可能的H,S和L'是单个连续范围,中间方法(或我的修改版本)效果很好,但在紫色H情况下它并不理想,因为它产生的结果实际上是更靠近其范围的边缘,因此输入的HSL值更可能被误认为是另一种颜色(红色的H范围是9 - 14)。

对于此任务,是否存在比中位数更好的聚合算法,即使在包裹紫色H的情况下,也会产生接近颜色的H,S和L范围中间的结果?

算法:

private hslColor aggregateEachAttribute(hslColor[] hslData)
{
    List<double> hAttributes = new List<double>();
    List<double> sAttributes = new List<double>();
    List<double> lAttributes = new List<double>();

    for (int i = 0; i < hslData.Length; i++)
    {
        hAttributes.Add(hslData[i].H);
    }

    for (int i = 0; i < hslData.Length; i++)
    {
        sAttributes.Add(hslData[i].S);
    }

    for (int i = 0; i < hslData.Length; i++)
    {
        lAttributes.Add(hslData[i].L);
    }

    hAttributes.Sort();
    sAttributes.Sort();
    lAttributes.Sort();

    while (hAttributes.Distinct().Count() >= 3)
    {
        hAttributes.RemoveAll(h => h == hAttributes[0]);
        hAttributes.RemoveAll(h => h == hAttributes[hAttributes.Count() - 1]);
    }

    while (sAttributes.Distinct().Count() >= 3)
    {
        sAttributes.RemoveAll(s => s == sAttributes[0]);
        sAttributes.RemoveAll(s => s == sAttributes[sAttributes.Count() - 1]);
    }

    while (lAttributes.Distinct().Count() >= 3)
    {
        lAttributes.RemoveAll(l => l == lAttributes[0]);
        lAttributes.RemoveAll(l => l == lAttributes[lAttributes.Count() - 1]);
    }

    return new hslColor(hAttributes[0], sAttributes[0], lAttributes[0]);
}

1 个答案:

答案 0 :(得分:1)

如果你只是担心环绕而且你的要点是&lt; X或&gt;对于一些相当小的X,240-X,您可以通过将X添加到数据模型240,计算中位数,然后从结果模型240中减去X来计算中位数。

更一般地说,您可以通过找到最小化距离总和的值来寻找中位数或中位数,其中d(x,y)= min(| xy |,| 240 + x - y |,| 240 + y - x |)。我认为你可以在一个带有O(n log n)的排序之后用时间O(n)来计算它,其中有一些相当繁琐的代码,你可以计算与每个候选中位数或mediod相关的距离之和,将这些点分成两组根据它们是从当前点顺时针还是逆时针方向,并在从一个候选中位数或中间位置移动到下一个候选中位数时逐步更新距离总和。