首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何从图像中生成突出颜色的调色板?

如何从图像中生成突出颜色的调色板?
EN

Stack Overflow用户
提问于 2011-04-29 03:22:39
回答 6查看 12.1K关注 0票数 22

我正在尝试弄清楚如何对图像中的所有像素进行采样并从中生成调色板,类似于thisthis。我甚至不知道从哪里开始。有谁能给我指个方向吗?

__EDIT:__

这就是我到目前为止得到的结论:

按照joe_coolish的建议,我使用这个Pixelate函数来获取较大的块部分。它工作得很好,给了我一个很好的颜色样本(这是来自windows样本水母图片):

现在,如果有人能帮我找出5种最明显的颜色(最深的蓝色,最亮的蓝色,橙色,灰色和桃色),我会永远爱你。我真的不明白如何将颜色平均或添加在一起。我也不知道如何区分一种颜色在程序上是否相似,在你的解释中有很多数字和变量,我试图弄清楚什么对谁做了什么。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2011-04-29 03:51:11

涉及代码的答案向您展示了如何获得完整的调色板。如果你想获得像你发布的网站一样的平均颜色,这就是我的方法。

源映像:

首先,我会应用一个低通滤波器(有点像高斯模糊)来平均颜色。

这样你就限制了整个调色板。从那里我会把屏幕分成N个块(N是你想要的调色板中的像素总数)

从那里,针对每个块并迭代每个像素,获得该块的平均像素并将其添加到您的调色板索引中。结果如下所示:

这样你的调色板是有限的,你可以得到不同区域的平均颜色。您可以在代码中完成所有这些工作,如果您需要一些帮助,请让我知道,我会发布一些。这只是高级的“我会做什么”。

票数 27
EN

Stack Overflow用户

发布于 2011-04-29 03:29:02

首先,取图片中的像素:(假设为using System.Drawing.Imaging;using System.Runtime.InteropServices)

代码语言:javascript
复制
Bitmap b = new Bitmap(myImage);
BitmapData bd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, ImageFormat.Format32Bpp);
int[] arr = new int[bd.Width * bd.Height - 1];
Marshal.Copy(bd.Scan0, arr, 0, arr.Length);
b.UnlockBits(bd);

然后你可以创建你的调色板:

代码语言:javascript
复制
var distinctColors = arr.Distinct();

可选:消除相似的颜色,直到您有您喜欢的调色板大小。下面是你如何做到这一点(尽管这绝对不是最有效或最准确的方法,只是最简单的):

代码语言:javascript
复制
var dc = distinctColors.toArray(); // int dc[] = distinctColors.toArray() is what it used to be
int cmIndex1 = -1;
int cmIndex2 = -1;
int cmDiff = -1;
for (int i = 0; i < dc.length; i++) {
    Color c1 = Color.FromArgb(dc[i]);
    for (int j = i + 1; j < dc.length; j++) {
        Color c2 = Color.FromArgb(dc[j]);
        // Note: you might want to include alpha below
        int diff = Math.Abs(c1.R - c2.R) + Math.Abs(c1.G - c2.G) + Math.Abs(c1.B - c2.B);
        if (cmDiff < 0 || diff < cmDiff) {
            cmIndex1 = i;
            cmIndex2 = j;
            cmDiff = diff;
        }
    }
}
// Remove the colors, replace with average, repeat until you have the desired number of colors
票数 6
EN

Stack Overflow用户

发布于 2011-04-29 03:39:20

在任何丰富的图像中,你的大多数颜色在某种程度上都是独一无二的。因此,获取不同的颜色可能不会帮助你实现目标。

我建议检查图像中每个像素的HSV值。我将给您留下无数个以HSV值数组的形式检索图像的在线示例。

使用HSV值,您可以通过创建256个色调计数的整数数组,计算图像数据中的色调直方图,来计算突出色调的群集。您可以通过查找具有高计数和的4-6个连续色调的群集来确定突出色调。

在选择了几个突出的色调之后,将这些色调的像素细分为另一个测量饱和度的直方图,并挑选出突出的簇,依此类推。

粗略示例

下面的代码做了一些尝试来帮助识别突出的色调。很可能还有其他很棒的方法可以做到这一点;然而,这可能会提供一些想法。

首先,我以Color对象数组的形式获取所有图像颜色,如下所示:

代码语言:javascript
复制
private static Color[] GetImageData(Image image)
{
    using (var b = new Bitmap(image))
    {
        var bd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
        byte[] arr = new byte[bd.Width * bd.Height * 3];
        Color[] colors = new Color[bd.Width * bd.Height];
        Marshal.Copy(bd.Scan0, arr, 0, arr.Length);
        b.UnlockBits(bd);

        for (int i = 0; i < colors.Length; i++)
        {
            var start = i*3;
            colors[i] = Color.FromArgb(arr[start], arr[start + 1], arr[start + 2]);
        }

        return colors;
    }
}

您可以考虑验证我在Color.FromArgb方法调用中以正确的顺序获得了RGB的顺序。

接下来,我保留了一个转换为HSV的实用方法。在我的示例中,我将只处理色调,但这里有一个完整的转换工作示例:

代码语言:javascript
复制
private static void ColorToHSV(Color color, out int hue, out int saturation, out int value)
{
    int max = Math.Max(color.R, Math.Max(color.G, color.B));
    int min = Math.Min(color.R, Math.Min(color.G, color.B));

    hue = (int)(color.GetHue() * 256f / 360f);
    saturation = (max == 0) ? 0 : (int)(1d - (1d * min / max));
    value = (int)(max / 255d);
}

最后,我构建色调直方图,定义一个色调宽度(比如9个色调),将计数汇总在一起,然后将计数报告给控制台。

代码语言:javascript
复制
private static void ProcessImage(Color[] imagecolors)
{
    var hues = new int[256];
    var hueclusters = new int[256];
    int hue, saturation, value;

    // build hue histogram.
    foreach (var color in imagecolors) {
        ColorToHSV(color, out hue, out saturation, out value);
        hues[hue]++;
    }

    // calculate counts for clusters of colors.
    for (int i = 0; i < 256; i++) {
        int huecluster = 0;
        for (int count = 0, j = i; count < 9; count++, j++) {
            huecluster += hues[j % 256];
        }

        hueclusters[(i + 5) % 256] = huecluster;
    }

    // Print clusters on the console
    for (int i = 0; i < 256; i++) {
        Console.WriteLine("Hue {0}, Score {1}.", i, hueclusters[i]);
    }
}

我没有尝试过过滤到选择哪个色调的。您可能需要考虑一些启发式方法,而不是盲目地选择数量最多的前几个,因为您可能希望选择在颜色光谱上有些分离的色调。我没有时间进一步探讨这一点,但我希望这能为您提供一些关于可以考虑的策略的见解。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5823854

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档