如何将位图简化为已知的RGB颜色集

发布于 2025-02-09 08:50:25 字数 748 浏览 3 评论 0 原文

对于一个爱好项目,我将构建一个程序,当给定图像时,位图将创建一个跨拼接模式作为PDF。我将在Mac上使用可可/目标C。

源位图通常是24BPP的图像,但是在可用的数百万颜色中,只有少数作为交叉缝线存在。线程有多种类型。 DMC是最广泛的可用性,几乎它们的整个范围可作为来自各个网站的RGB值可用。 这是一个,例如。

DMC#  Name               R   G   B
----- ------------------ --- --- ---
blanc White              255 255 255
208   Lavender - vy dk   148  91 128
209   Lavender - dk      206 148 186
210   Lavender - md      236 207 225
211   Lavender - lt      243 218 228
      ...etc...

如我所见,我的第一个问题是从图像中的像素从RGB的起点开始,选择了DMC集中可用的最接近的颜色。从数学上找到最近的DMC颜色并确保它也非常合适的颜色的最佳方法是什么?

尽管我将使用可可,但请随时在您发布的任何代码中使用伪代码(甚至Java!)。

For a hobby project I'm going to build a program that when given an image bitmap will create a cross-stitch pattern as a PDF. I'll be using Cocoa/Objective C on a Mac.

The source bitmap will typically be a 24bpp image, but of the millions of colours available, only a few exist as cross-stitch threads. Threads come in various types. DMC is the most widely available, and almost their entire range is available as RGB values from various web sites. Here's one, for instance.

DMC#  Name               R   G   B
----- ------------------ --- --- ---
blanc White              255 255 255
208   Lavender - vy dk   148  91 128
209   Lavender - dk      206 148 186
210   Lavender - md      236 207 225
211   Lavender - lt      243 218 228
      ...etc...

My first problem, as I see it, is from a starting point of the RGB from a pixel in the image choosing the nearest colour available from the DMC set. What's the best way of finding the nearest DMC colour mathematically, and ensuring that it's a close fit as a colour too?

Although I'll be using Cocoa, feel free to use pseudo-code (or even Java!) in any code you post.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

偷得浮生 2025-02-16 08:50:25

使用 lab color Space color Space color Space并找到颜色,并与最近://en.wikipedia.org/wiki/euclidean_distance“ rel =“ nofollow noreferrer”> euclidean距离。在RGB颜色空间中这样做将产生违反直觉的结果。 hsl 颜色空间。)

(或使用 hsl > 您选择的颜色空间内最接近距离的颜色。请注意,对于某些颜色空间,必须计算距离循环(例如那些使用 hue )。

(大多数颜色Quanization围绕着实际选择调色板,但是在您的情况下已经得到了解决,因此您不能使用更流行的量化技术。)

另外,请查看

要在可可中找到HSB色调,看起来您可以使用在nscolor.h.h 中声明。

但是,如果您只使用此技术将图像转换为跨缝制设计,那么将其实际缝制非常困难。将充满单像素颜色字段,这是一种失败交叉缝合的目的。

Use the LAB color space and find the color with the nearest euclidean distance. Doing this in the RGB color space will yield counter-intuitive results. (Or use the HSL color space.)

So just iterate over each pixel and find the color with the closest distance within the color space you choose. Note that the distance must be computed circularly for some color spaces (e.g. those employing hue).

(Most color quanization revolves around actually choosing a palette, but that has already been taken care of in your case, so you can't use the more popular quantization techniques.)

Also, check out this question.

To find the HSB hue in Cocoa, it looks like you can use the getHue method declared in NSColor.h.

However, if you just convert an image to a cross-stitch design using this technique, it will be very hard to actually stitch it. It will be full of single-pixel color fields, which sort of defeats the purpose of cross-stitching.

她如夕阳 2025-02-16 08:50:25

这称为颜色量化,并且有许多算法可用。

一个非常基本的是将RGB颜色视为空间的点,并在颜色之间使用普通的旧欧几里得距离来弄清它们的“接近”。这具有缺点,因为人眼在这个空间的不同地方具有不同的敏感性,因此这样的距离与人类对颜色的看法不太吻合。您可以使用各种加权方案来改善这种情况。

This is called color quantization, and there are many algorithms available.

One very basic is to just treat RGB colors as points in space, and use plain old Euclidian distance between colors to figure out how "close" they are. This has drawbacks, since human eyes have different sensitivity at different places in this space, so such a distance would not correspond well to how humans perceive the colors. You can use various weighting schemes to improve that situation.

人心善变 2025-02-16 08:50:25

相互构造... :)

您不仅可以识别最近的颜色,还需要减少所使用的颜色数量。您不想最终获得使用数百种不同颜色的缝合图案……

我将一些代码汇总在一起,以基本的层面进行此操作。 (对不起,它在C#中,我希望它无论如何都可以有用。)

当然,在该方法运行良好之前,需要进行进一步的调整。 GetDistance方法加权了色相,饱和度和亮度相互影响的重要性,找到最佳平衡当然很重要,对于找到最接近的颜色。

减少调色板的方法也可以做很多事情。在示例中,我刚选择了最常用的颜色,但是您可能想在调色板中的颜色相似。这可以通过选择最常用的颜色,根据列出的颜色的距离来减少列表中其余颜色的计数,然后求解列表。

具有DMC颜色的HSL类,可以计算到另一种颜色的距离,并在颜色列表中找到最近的颜色:

public class Hsl {

    public string DmcNumber { get; private set; }
    public Color Color { get; private set; }
    public float Hue { get; private set; }
    public float Saturation { get; private set; }
    public float Brightness { get; private set; }
    public int Count { get; set; }

    public Hsl(Color c) {
        DmcNumber = "unknown";
        Color = c;
        Hue = c.GetHue();
        Saturation = c.GetSaturation();
        Brightness = c.GetBrightness();
        Count = 0;
    }

    public Hsl(string dmc, int r, int g, int b)
        : this(Color.FromArgb(r, g, b))
    {
        DmcNumber = dmc;
    }

    private static float AngleDifference(float a1, float a2) {
        float a = Math.Abs(a1 - a2);
        if (a > 180f) {
            a = 360f - a;
        }
        return a / 180f;
    }

    public float GetDistance(Hsl other) {
        return
            AngleDifference(Hue, other.Hue) * 3.0f +
            Math.Abs(Saturation - other.Saturation) +
            Math.Abs(Brightness - other.Brightness) * 4.0f;
    }

    public Hsl GetNearest(IEnumerable<Hsl> dmcColors) {
        Hsl nearest = null;
        float nearestDistance = float.MaxValue;
        foreach (Hsl dmc in dmcColors) {
            float distance = GetDistance(dmc);
            if (distance < nearestDistance) {
                nearestDistance = distance;
                nearest = dmc;
            }
        }
        return nearest;
    }

}

此代码设置DMC颜色的(大量减少)DMC颜色列表,加载图像,计算颜色,计数颜色,减少调色板并转换图像。当然,您还希望将信息从减少的调色板中保存。

Hsl[] dmcColors = {
    new Hsl("blanc", 255, 255, 255),
    new Hsl("310", 0, 0, 0),
    new Hsl("317", 167, 139, 136),
    new Hsl("318", 197, 198, 190),
    new Hsl("322", 81, 109, 135),
    new Hsl("336", 36, 73, 103),
    new Hsl("413", 109, 95, 95),
    new Hsl("414", 167, 139, 136),
    new Hsl("415", 221, 221, 218),
    new Hsl("451", 179, 151, 143),
    new Hsl("452", 210, 185, 175),
    new Hsl("453", 235, 207, 185),
    new Hsl("503", 195, 206, 183),
    new Hsl("504", 206, 221, 193),
    new Hsl("535", 85, 85, 89)
};

Bitmap image = (Bitmap)Image.FromFile(@"d:\temp\pattern.jpg");

// count colors used
List<Hsl> usage = new List<Hsl>();
for (int y = 0; y < image.Height; y++) {
    for (int x = 0; x < image.Width; x++) {
        Hsl color = new Hsl(image.GetPixel(x, y));
        Hsl nearest = color.GetNearest(dmcColors);
        int index = usage.FindIndex(h => h.Color.Equals(nearest.Color));
        if (index != -1) {
            usage[index].Count++;
        } else {
            nearest.Count = 1;
            usage.Add(nearest);
        }
    }
}

// reduce number of colors by picking the most used
Hsl[] reduced = usage.OrderBy(c => -c.Count).Take(5).ToArray();

// convert image
for (int y = 0; y < image.Height; y++) {
    for (int x = 0; x < image.Width; x++) {
        Hsl color = new Hsl(image.GetPixel(x, y));
        Hsl nearest = color.GetNearest(reduced);
        image.SetPixel(x, y, nearest.Color);
    }
}

image.Save(@"d:\temp\pattern.png", System.Drawing.Imaging.ImageFormat.Png);

Interresting... :)

You would not only identify the nearest colors, you would also want to reduce the number of colors used. You don't want to end up with a stitching pattern that uses hundreds of different colors...

I put together some code that does this on a basic level. (Sorry that it's in C#, I hope that it can be somewhat useful anyway.)

There is some further tweaking that needs to be done before the method works well, of course. The GetDistance method weights the importance of hue, saturation and brightness against each other, finding the best balance between those is of course important in order to find the color that looks closest.

There is also a lot that can be done with the method of reducing the palette. In the example I just picked the most used colors, but you probably want to weight in how alike the colors are in the palette. This can be done by picking the most used color, reduce the count for the remaining colors in the list depending on the distance to the picked color, and then resort the list.

The Hsl class that holds a DMC color, can calculate the distance to another color, and find the nearest color in a list of colors:

public class Hsl {

    public string DmcNumber { get; private set; }
    public Color Color { get; private set; }
    public float Hue { get; private set; }
    public float Saturation { get; private set; }
    public float Brightness { get; private set; }
    public int Count { get; set; }

    public Hsl(Color c) {
        DmcNumber = "unknown";
        Color = c;
        Hue = c.GetHue();
        Saturation = c.GetSaturation();
        Brightness = c.GetBrightness();
        Count = 0;
    }

    public Hsl(string dmc, int r, int g, int b)
        : this(Color.FromArgb(r, g, b))
    {
        DmcNumber = dmc;
    }

    private static float AngleDifference(float a1, float a2) {
        float a = Math.Abs(a1 - a2);
        if (a > 180f) {
            a = 360f - a;
        }
        return a / 180f;
    }

    public float GetDistance(Hsl other) {
        return
            AngleDifference(Hue, other.Hue) * 3.0f +
            Math.Abs(Saturation - other.Saturation) +
            Math.Abs(Brightness - other.Brightness) * 4.0f;
    }

    public Hsl GetNearest(IEnumerable<Hsl> dmcColors) {
        Hsl nearest = null;
        float nearestDistance = float.MaxValue;
        foreach (Hsl dmc in dmcColors) {
            float distance = GetDistance(dmc);
            if (distance < nearestDistance) {
                nearestDistance = distance;
                nearest = dmc;
            }
        }
        return nearest;
    }

}

This code sets up a (heavily reduced) list of DMC colors, loads an image, counts the colors, reduces the palette and converts the image. You would of course also want to save the information from the reduced palette somewhere.

Hsl[] dmcColors = {
    new Hsl("blanc", 255, 255, 255),
    new Hsl("310", 0, 0, 0),
    new Hsl("317", 167, 139, 136),
    new Hsl("318", 197, 198, 190),
    new Hsl("322", 81, 109, 135),
    new Hsl("336", 36, 73, 103),
    new Hsl("413", 109, 95, 95),
    new Hsl("414", 167, 139, 136),
    new Hsl("415", 221, 221, 218),
    new Hsl("451", 179, 151, 143),
    new Hsl("452", 210, 185, 175),
    new Hsl("453", 235, 207, 185),
    new Hsl("503", 195, 206, 183),
    new Hsl("504", 206, 221, 193),
    new Hsl("535", 85, 85, 89)
};

Bitmap image = (Bitmap)Image.FromFile(@"d:\temp\pattern.jpg");

// count colors used
List<Hsl> usage = new List<Hsl>();
for (int y = 0; y < image.Height; y++) {
    for (int x = 0; x < image.Width; x++) {
        Hsl color = new Hsl(image.GetPixel(x, y));
        Hsl nearest = color.GetNearest(dmcColors);
        int index = usage.FindIndex(h => h.Color.Equals(nearest.Color));
        if (index != -1) {
            usage[index].Count++;
        } else {
            nearest.Count = 1;
            usage.Add(nearest);
        }
    }
}

// reduce number of colors by picking the most used
Hsl[] reduced = usage.OrderBy(c => -c.Count).Take(5).ToArray();

// convert image
for (int y = 0; y < image.Height; y++) {
    for (int x = 0; x < image.Width; x++) {
        Hsl color = new Hsl(image.GetPixel(x, y));
        Hsl nearest = color.GetNearest(reduced);
        image.SetPixel(x, y, nearest.Color);
    }
}

image.Save(@"d:\temp\pattern.png", System.Drawing.Imaging.ImageFormat.Png);
靑春怀旧 2025-02-16 08:50:25

get the source for the ppmquant application from the netpbm set of utilities

盛装女皇 2025-02-16 08:50:25

其他人指出了颜色量化的各种技术。可以使用Markov随机字段之类的技术来尝试对相邻像素位置切换线程颜色的系统进行惩罚。那里有一些通用的多标签MRF库,包括 boykov's

要使用其中之一,数据元素将是输入颜色,标签将是一组线程颜色,数据项可能是BZLM建议的实验室空间中的欧几里得距离,而邻里条款将对切换罚款线颜色。

Others have pointed out various techniques for color quantization. It's possible to use techniques like Markov Random Fields to try to penalize the system for switching thread colors at neighboring pixel locations. There are some generic multi-label MRF libraries out there including Boykov's.

To use one of these, the data elements would be the input colors, the labels would be the set of thread colors, the data terms could be something like the Euclidean distance in LAB space suggested by bzlm, and the neighborhood terms would penalize for switching thread colors.

善良天后 2025-02-16 08:50:25

根据您的颜色操作的正确性的相关性,请记住 color Space 。由于我的摄影爱好,我已经研究了这一点,但我仍然对所有事情有些困惑。

但是,如前所述,请尽可能多地使用实验室,因为(AFAIK)它是颜色空间不可知的,而所有其他方法(RGB/HSL/CMYK)没有(理论上)没有定义的色彩空间。

例如,RGB仅为三个百分比值(0-255 =&gt; 0-100%,具有8位颜色深度)。因此,如果您的RGB-三曲线为(0,255,0),则将其翻译成“只有绿色,并且尽可能多地”。因此,问题是“红色有多红?”。这是一个颜色空间答案的问题 - srgb srgb 100%-Green不如绿色 adobergb 100%-Green。它甚至都不一样 hue

对不起,如果这到达了事物的外面

Depending on the relevance of the correctness of your color operations, remember to take color spaces into account. While I have studied this somewhat, due to my photography hobby, I'm still a bit confused about everything.

But, as previously mentioned, use LAB as much as possible, because (afaik) it's color space agnostic, while all other methods (RGB/HSL/CMYK) mean nothing (in theory) without a defined color space.

RGB, for example, is just three percentage values (0-255 => 0-100%, with 8-bit color depth). So, if you have an RGB-triplet of (0,255,0), it translates to "only green, and as much of it as possible". So, the question is "how red is red?". This is the question that a color space answers - sRGB 100%-green is not as green as AdobeRGB 100%-green. It's not even the same hue!

Sorry if this went to the offtopic side of things

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文