Obrazek zmiana RGB

0

Witam,
dodałem obrazek który ma tło przezroczyste, kolor podstawowy: czerwony.
Dodałem również suwak: trackBar i chciałbym, aby przesuwanie suwaka z czerwonego szło ku zielonemu.
Dodam, że obrazek ma nieregularne kształty.
Wygooglałem, coś takiego i naniosłem drobne modyfikacje:

         public static Bitmap MakeGrayscale3(Bitmap original, double R, double G, double B)
        {
            
            //create a blank bitmap the same size as original
            Bitmap newBitmap = new Bitmap(original.Width, original.Height);

            //get a graphics object from the new image
            Graphics g = Graphics.FromImage(newBitmap);

            //create the grayscale ColorMatrix
            ColorMatrix colorMatrix = new ColorMatrix(
               new float[][] 
      {
         new float[] {(float)R, 0, 0, 0, 0},
         new float[] {0, (float)G, 0, 0, 0},
         new float[] {0, 0, (float)B, 0, 0},
         new float[] {0, 0, 0, 1, 0},
         new float[] {0, 0, 0, 0, 1}
      });

            //create some image attributes
            ImageAttributes attributes = new ImageAttributes();

            //set the color matrix attribute
            attributes.SetColorMatrix(colorMatrix);

            //draw the original image on the new image
            //using the grayscale color matrix
            g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height),
               0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes);

            //dispose the Graphics object
            g.Dispose();
            return newBitmap;
        }

Tylko niestety nie bardzo spełnia moje oczekiwania gdyż wartości R G B są przemnażane a więc każde posunięcie suwaka mnoży mi wartość. Chciałbym zrobić tak by przesuwając w prawo będzie mi się kolor zmieniał na zielony a jak uzyskam zielony i zacznę przesuwać w lewo to będziemy uzyskiwać kolor czerwony.
Prosiłbym o pomoc bo już siedzę trochę przy tym i coraz mniej wiem jak to zrobić :/

0

Chciałbym podzielić się moim rozwiązaniem:

        public void ApplyColorFilter(double r, double g, double b)
        {
            Bitmap j = new Bitmap(this.Image);
            byte A, R, G, B;
            Color pixelColor;

            for (int y = 0; y < j.Height; y++)
            {
                for (int x = 0; x < j.Width; x++)
                {
                    pixelColor = j.GetPixel(x, y);
                    A = pixelColor.A;
                    if (r <= 50)
                    {
                        R = (byte)(212 + r * 0.6);
                        G = (byte)(12 + g * 3.22);
                        B = (byte)(12 - b * 0.06);
                    }
                    else
                    {
                        R = (byte)(242 - r * 2.27);
                        G = (byte)(173 - g * 0.61);
                        B = (byte)(9 + b * 0.06);
                    }
                    
                    j.SetPixel(x, y, Color.FromArgb((int)A, (int)R, (int)G, (int)B));
                }
            }
            this.Image = j;
        } 
1
  pixelColor = j.GetPixel(x, y);
...
  j.SetPixel(x, y, Color.FromArgb((int)A, (int)R, (int)G, (int)B));

pewnie działa, ale GetPixel/SetPixel na pewno jest powooooolne…

0

Zgadzam się ;) Ale stosując ten sposób w mojej aplikacji akurat nie jest to jakoś szczególnie zauważalne.
Wilk syty i owca cała :)
A niestety innego rozwiązania nie znalazłem :)

0

Sprawa pierwsza - dlaczego if jest przed pętlą? Po co sprawdzać coś milion razy zamiast raz? Może to nie będzie miało w tym przypadku kluczowego wpływu na wydajność, ale ładniej wygląda.

A szybkie rozwiązanie (ok. 60 razy), będzie wyglądało np. tak:

unsafe private static Bitmap ApplyColorFilter2(Bitmap original, double r, double g, double b)
{
    Bitmap result = new Bitmap(original);
    GraphicsUnit unit = GraphicsUnit.Pixel;
    BitmapData data = result.LockBits(Rectangle.Round(result.GetBounds(ref unit)), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

    byte* scan0 = (byte*)data.Scan0.ToPointer();
    if (r <= 50)
    {
        for (int y = 0; y < data.Height; y++)
        {
            byte* bytes = scan0 + y * data.Stride;
            for (int x = 0; x < data.Width; x++, bytes += 3)
            {
                *(bytes + 2) = (byte)(212 + r * 0.6);
                *(bytes + 1) = (byte)(12 + g * 3.22);
                *bytes = (byte)(12 - b * 0.06);
            }
        }
    }
    else
    {
        for (int y = 0; y < data.Height; y++)
        {
            byte* bytes = scan0 + y * data.Stride;
            for (int x = 0; x < data.Width; x++, bytes += 3)
            {
                *(bytes + 2) = (byte)(242 - r * 2.27);
                *(bytes + 1) = (byte)(173 - g * 0.61);
                *bytes = (byte)(9 + b * 0.06);
            }
        }
    }

    result.UnlockBits(data);
    return result;
}
0
                *(bytes + 2) = (byte)(212 + r * 0.6);
                *(bytes + 1) = (byte)(12 + g * 3.22);
                *bytes = (byte)(12 - b * 0.06);

wskaźniki można indeksować:

                bytes[2] = (byte)(212 + r * 0.6);
                bytes[1] = (byte)(12 + g * 3.22);
                bytes[0] = (byte)(12 - b * 0.06);

1 użytkowników online, w tym zalogowanych: 0, gości: 1