对于一个爱好项目,我将构建一个程序,当给定图像位图时,将创建一个十字绣图案作为PDF。我将在Mac上使用Cocoa / Objective C.
源位图通常是24bpp图像,但是在可用的数百万种颜色中,只有少数存在作为十字绣线程。线程有各种类型。 DMC是最广泛使用的,几乎整个范围都可以从各种网站获得RGB值。例如Here's one。
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颜色的最佳方法,并确保它也适合作为颜色?
虽然我将使用Cocoa,但您可以在发布的任何代码中使用伪代码(甚至是Java!)。
答案 0 :(得分:10)
使用LAB色彩空间,找到最近的euclidean distance颜色。在RGB颜色空间中执行此操作将产生反直觉的结果。 (或使用HSL色彩空间。)
因此,只需迭代每个像素,找到所选颜色空间内距离最近的颜色。请注意,对于某些颜色空间(例如使用 hue 的那些颜色空间),必须计算循环的距离。
(大多数颜色都围绕着实际选择调色板,但在你的情况下已经处理过,所以你不能使用更流行的量化技术。)
另外,请查看this question。
要在Cocoa中查找HSB色调,看起来您可以使用getHue method declared in NSColor.h。
但是,如果您只是使用这种技术将图像转换为十字绣设计,实际拼接它将非常困难。它将充满单像素色域,有点挫败了十字绣的目的。
答案 1 :(得分:3)
这称为color quantization,并且有许多算法可用。
一个非常基本的方法是将RGB颜色视为空间中的点,并使用颜色之间的普通旧欧几里德距离来确定它们的“接近”程度。这具有缺点,因为人眼在该空间中的不同位置处具有不同的灵敏度,因此这种距离不会与人类感知颜色的方式很好地对应。您可以使用各种加权方案来改善这种情况。
答案 2 :(得分:2)
有趣的......:)
您不仅要识别最近的颜色,还要减少使用的颜色数量。您不希望最终得到使用数百种不同颜色的拼接图案......
我把一些在基本级别上执行此操作的代码放在一起。 (对不起,这是在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颜色列表,加载图像,计算颜色,缩小调色板并转换图像。你当然也想在某处保存简化调色板中的信息。
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);
答案 3 :(得分:1)
从netpbm
实用程序集
ppmquant
应用程序的源代码
答案 4 :(得分:1)
其他人已经指出了各种颜色量化技术。可以使用诸如马尔可夫随机场之类的技术来试图惩罚用于在相邻像素位置处切换线色的系统。有一些通用的多标签MRF库,包括Boykov's。
要使用其中之一,数据元素将是输入颜色,标签将是线程颜色的集合,数据术语可能类似于bzlm建议的LAB空间中的欧几里德距离,并且邻域术语将是惩罚切换线色。
答案 5 :(得分:-1)
根据颜色操作正确性的相关性,请记住考虑color space。虽然我对此有所研究,但由于我的摄影爱好,我对所有事情仍然感到困惑。
但是,如前所述,尽可能使用LAB,因为(afaik)它的颜色空间不可知,而所有其他方法(RGB / HSL / CMYK)在没有定义颜色空间的情况下(理论上)没有任何意义。
例如,RGB只有三个百分比值(0-255 =&gt; 0-100%,具有8位颜色深度)。因此,如果你有一个(0,255,0)的RGB三元组,它会转换为“只有绿色,尽可能多的绿色”。所以,问题是“红色是红色的?”。这是一个颜色空间回答的问题 - sRGB 100%-green不像AdobeRGB 100%-green那样绿。它甚至不是hue!对不起,如果这是事情的偏离方面