Изменение цвета в изображении с сохранением текстуры - C#
Формулировка задачи:
Имеется изображение PNG с прозрачностью. Допустим вот такое
Имеется задача менять цвет этого изображения, конкретно отображаемых элементов, не затрагивая прозрачность и не теряя текстуру. При помощи ColorDialog указывать нужный цвет. Тупая замена пикселей на нужный цвет не подходит, ибо теряется текстура. В интернете была найден способ данного преобразования, основанный на переводе цвета в цветовую схему HSV. Конкретнее вот:
Вот только мне непонятно, как это собственно реализовать. Что значит пробегаем по цветам? То есть это будет таже самая попиксельная замена? И как собственно определять смещение и конструировать новый HSV-цвет?
заранее спасибо за пояснения и примеры кода.
P.S. ссылка на статью из цитаты http://vhbit.net/blog/2012/07/07/colorcube-color-replacement/
В приведенном примере происходит хитрая замена цвета со всеми оттенками. Для удобства используется работа с цветом в формате HSV, т.к. в этом случае гораздо легче выцеплять схожие цвета - они будут попадать в сектор.
Представление цвета в HSV:
...пробегаем по всем цветам, смотрим попадает ли HSV аналог этого цвета в нужный сектор и если да - запоминаем его смещение относительно центрального. После этого конструируем новый HSV цвет с таким же смещением относительно зеленого и конвертируем обратно в RGB.
Решение задачи: «Изменение цвета в изображении с сохранением текстуры»
textual
Листинг программы
private void button1_Click(object sender, EventArgs e) { float hue = hueBar.Value; float saturation = saturBar.Value / 100f; float brightness = brightBar.Value / 100f; var result = ColorizeBitmap(bmp, hue, saturation, brightness, Colorizer); pictureBox1.Image = result; } private Color Colorizer(Color from, float hue, float saturation, float brightness) { float oHue, oSatur, oBright; ColorToHSV(from, out oHue, out oSatur, out oBright); return ColorFromHSV(hue, (oSatur * saturation) + (1 - saturation), (oBright * brightness) + (1 - brightness)); } private unsafe Bitmap ColorizeBitmap(Bitmap source, float hue, float saturation, float brightness, Func<Color, float, float, float, Color> func) { var result = new Bitmap(source); BitmapData data = result.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, source.PixelFormat); int PixelSize = 4; for (int y = 0; y < data.Height; y++) { byte* row = (byte*)data.Scan0 + (y * data.Stride); for (int x = 0; x < data.Width; x++) { byte* r = &row[x * PixelSize + 2]; byte* g = &row[x * PixelSize + 1]; byte* b = &row[x * PixelSize]; Color newColor = func(Color.FromArgb(*r, *g, *b), hue, saturation, brightness); *b = newColor.B; *g = newColor.G; *r = newColor.R; } } result.UnlockBits(data); return result; } public static void ColorToHSV(Color color, out float hue, out float saturation, out float 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 = color.GetHue(); saturation = (max == 0) ? 0 : 1f - (1f * min / max); value = max / 255f; } public static Color ColorFromHSV(double hue, double saturation, double value) { int hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6; double f = hue / 60 - Math.Floor(hue / 60); value = value * 255; int v = Convert.ToInt32(value); int p = Convert.ToInt32(value * (1 - saturation)); int q = Convert.ToInt32(value * (1 - f * saturation)); int t = Convert.ToInt32(value * (1 - (1 - f) * saturation)); switch (hi) { case 0: return Color.FromArgb(255, v, t, p); case 1: return Color.FromArgb(255, q, v, p); case 2: return Color.FromArgb(255, p, v, t); case 3: return Color.FromArgb(255, p, q, v); case 4: return Color.FromArgb(255, t, p, v); default: return Color.FromArgb(255, v, p, q); } }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д