Интересно ... :)
Вы не только идентифицируете ближайшие цвета, но и захотите уменьшить количество используемых цветов. Вы же не хотите, чтобы в конечном итоге вышивка вышивалась сотнями разных цветов ...
Я собрал код, который делает это на базовом уровне. (Извините, что это на C #, я надеюсь, что в любом случае это может быть полезно.)
Конечно, прежде чем метод заработает, необходимо внести некоторые дополнительные изменения. Метод GetDistance оценивает важность оттенка, насыщенности и яркости по отношению друг к другу, и, конечно же, важно найти лучший баланс между ними, чтобы найти наиболее близкий цвет.
Также многое можно сделать с помощью метода уменьшения палитры. В этом примере я просто выбрал наиболее часто используемые цвета, но вы, вероятно, захотите взвесить, насколько похожи цвета в палитре. Это можно сделать, выбрав наиболее часто используемый цвет, уменьшив количество оставшихся цветов в списке в зависимости от расстояния до выбранного цвета, а затем пересчитав список.
Класс Hsl, содержащий цвет DMC, может вычислять расстояние до другого цвета и находить ближайший цвет в списке цветов:
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);
person
Guffa
schedule
08.03.2009