如何在python中的列表中组合类似的元素?

时间:2016-12-11 02:47:50

标签: python dictionary image-processing color-palette

作为练习练习,我尝试从图像生成彩色调色板,并使用Python将原始提取的RGB通道转换为调色板。使用列表和词典的组合相当简单,但是我希望能够通过组合相似的颜色通道来限制调色板中的颜色数量,除非它们在图像中都有很大的存在

说我有一个字典,上面有我的RGB值及其数量:

countsR = {"255": 301, "250": 16, "10": 589, "14": 124, "8": 132}

这个托盘需要3位才能索引。理想情况下,我会运行一些函数combine_channels(dd, max_distance),它执行一些可怕的O(N^2)事情,并输出如下内容:

print(combine_channels(countsR, 10))
>>> {"255": 317, "10": 845}

现在只能用一位索引!

如果它可以跟踪哪些东西被替换为什么,也许在另一本词典中也是好的:

countsR, replacements = combine_channels(countsR, 10)
print(replacements)
>>> {"255": ["250"], "10": ["8", "14"]}

关于这可能是什么样子的任何想法?

2 个答案:

答案 0 :(得分:1)

在很多情况下,评论显示有多种不同的分组选项。一个简单的选择是以数字顺序形成组来迭代通道,并且如果通道不能适合现有组,则创建一个新组。它不会导致最大距离,但它将保证生成最小数量的组:

def combine_channels(channels, dist):
    result = {}
    replacements = {}
    groups = []
    group = []
    key = None

    # Iterate through channels in ascending numerical order
    for channel, count in sorted((int(k), v) for k, v in channels.items()):
        # Add new group in case that channel doesn't fit to current group
        if group and channel - key > dist:
            groups.append((key, group))
            group = []
            key = None

        # Add channel to group
        group.append((channel, count))

        # Pick a new key in case there's none or current channel is within
        # dist from first channel in the group
        if key is None or channel - group[0][0] <= dist:
            key = channel

    # Add last group in case it exists
    if group:
        groups.append((key, group))

    for key, group in groups:
        result[key] = sum(x[1] for x in group)
        replacements[key] = [x[0] for x in group if x[0] != key]

    return result, replacements

countsR1 = {"255": 301, "250": 16, "10": 589, "14": 124, "8": 132}
countsR2 = {"0": 10, "11": 20, "7": 30, "19": 40, "25": 50}
countsR3 = {"0": 5, "11": 10}
print(combine_channels(countsR1, 10))
print(combine_channels(countsR2, 10))
print(combine_channels(countsR3, 10))

输出:

({14: 845, 255: 317}, {14: [8, 10], 255: [250]})
({25: 90, 7: 60}, {25: [19], 7: [0, 11]})
({0: 5, 11: 10}, {0: [], 11: []})

上面的时间复杂度是 O(n log n),因为使用了排序。

答案 1 :(得分:0)

以下是我提出的建议:

def combine_channels(lst, max_dist):
    colors = list(set(lst)) # unique colors
    counts = dict()
    replacements = dict()
    all_repl = []

    for el in lst:
        counts[el] = counts.get(el, 0) + 1

    N = len(colors)
    dists = np.zeros((N, N))
    for i in range(N - 1):
        for j in range(i + 1, N):
            dist = abs(colors[i] - colors[j])
            dists[i, j] = dist
            if(dist < max_dist):
                if(colors[i] in all_repl or colors[j] in all_repl):
                    continue
                else:
                    if(counts.get(colors[i], 0) > counts.get(colors[j], 0)):
                        winner = colors[i]
                        loser = colors[j]
                    else:
                        winner = colors[j]
                        loser = colors[i]
                counts[winner] += counts.get(loser, 0)
                counts[loser] = 0
                if winner not in replacements:
                    replacements[winner] = list()
                replacements[winner].append(loser)
                all_repl.append(loser)
                if loser not in replacements:
                    continue
                else:
                    replacements[winner] = replacements[winner].extend(replacements[loser])
                    replacements.pop(loser, None)              
    print(replacements)

可能有许多更有效的方法,它不能满足最大距离要求,但它有效!