Изменение цвета в изображении с сохранением текстуры - C#

Узнай цену своей работы

Формулировка задачи:

Имеется изображение PNG с прозрачностью. Допустим вот такое Имеется задача менять цвет этого изображения, конкретно отображаемых элементов, не затрагивая прозрачность и не теряя текстуру. При помощи ColorDialog указывать нужный цвет. Тупая замена пикселей на нужный цвет не подходит, ибо теряется текстура. В интернете была найден способ данного преобразования, основанный на переводе цвета в цветовую схему HSV. Конкретнее вот:
В приведенном примере происходит хитрая замена цвета со всеми оттенками. Для удобства используется работа с цветом в формате HSV, т.к. в этом случае гораздо легче выцеплять схожие цвета - они будут попадать в сектор. Представление цвета в HSV: ...пробегаем по всем цветам, смотрим попадает ли HSV аналог этого цвета в нужный сектор и если да - запоминаем его смещение относительно центрального. После этого конструируем новый HSV цвет с таким же смещением относительно зеленого и конвертируем обратно в RGB.
Вот только мне непонятно, как это собственно реализовать. Что значит пробегаем по цветам? То есть это будет таже самая попиксельная замена? И как собственно определять смещение и конструировать новый HSV-цвет? заранее спасибо за пояснения и примеры кода. P.S. ссылка на статью из цитаты http://vhbit.net/blog/2012/07/07/colorcube-color-replacement/

Решение задачи: «Изменение цвета в изображении с сохранением текстуры»

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);
            }
        }

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

6   голосов , оценка 4 из 5
Похожие ответы