Pokaż wyniki od 1 do 5 z 5

Wątek: Proste przetwarzanie obrazu w C#

  1. #1
    Advert Manager Guru overclockingu Reputacja:   (13) Awatar Dawid_S
    Dołączył
    05.2009
    Posty
    6,599

    Proste przetwarzanie obrazu w C#

    Zestaw filtrów operujących na obrazkach, grafikach, zdjęciach itp. w formacie JPG.

    Prawie wszystko jest zrealizowane na wskaźnikach, więc całość charakteryzuje się dość dobrą wydajnością. Projekt stworzony w Microsoft Visual Studio, w języku C#. Niektóre rozwiązania to gotowce ze strony Microsoftu lub for internetowych, ale sporo jest mojego autorstwa.

    Oczywiście nie wrzucam całego projektu, tylko wybrane klasy . Choć i tak jest to większość kodu, który napisałem... Dołączam jedynie plik exe (w archiwum znajdującym się w załączniku pod postem), aby można było zobaczyć jak to działa w praktyce

    Funkcjonalności:
    - wersja okienkowa dla Windows,
    - zaimplementowana obsługa błędów i wyjątków,
    - otwieranie oraz zapisywanie dowolnego obrazu w formacie JPG (można przerobić, że będzie otwierał również inne formaty),
    - inwersja kolorów,
    - greyscale, czyli zmiana kolorów na czarno-białe,
    - wyświetlanie osobno każdego z kanałów modeli barw: RGB, CMYK, YUV,
    - filtr splotowy (gotowe efekty rozmazywania - blur i Gausian blur i wyostrzania - sharp),
    - dowolny (ręcznie ustawiany) filtr splotowy (convolution) dla maski 3x3 oraz 5x5 z częściową obsługą krawędzi,
    - filtr HSL - można zmieniać wartość: Hue, czyli barwy, w zakresie 0-360 stopni; Saturation (nasycenie) z przedziału 0-2; Lightness (jasność) również 0-2
    - wyświetlanie histogramu jasności (dla kanału Y z modelu YUV),
    - progowanie (binaryzacja) dla wyżej opisanego histogramu jasności, czyli wyświetlanie (na czarno) tylko tych pikseli, które charakteryzują się podaną (lub niższą) jasnością (z przedziału 0-255)
    - efektów nie można na siebie nakładać, ponieważ z każdym wybraniem efektu przywracany jest pierwotnie wczytany obraz (można to łatwo zmodyfikować, choć w moim projekcie tego nie przewidywałem)

    Nad kodem zbytnio się nie "rozpieszczałem", więc momentami jest trochę chaotyczny. Wiele elementów potrafię lepiej zaimplementować, ale najzwyczajniej mi się nie chciało, bo sprawdzano poprawność funkcjonowania, a nie jakość kodu (która i tak nie jest najgorsza ).

    Jeśli macie pytania - piszcie!

    Okno z histogramem jasności oraz opcją progowania (binaryzacji). Tablicę brightnessValues zdobędziecie poprzez wywołanie metody ChannelSelector.getBrightnessValues() z odpowiednim parametrem na wejściu. Oryginalna bitmapa jest potrzebna, aby każde przesunięcie suwaka nie powodowało nakładanie na siebie kolejnych wywołań binaryzacji. PictureBox wiadomo po co jest

    Kod:
    public partial class BrightnessHistogramWindow : Form
        {
            private PictureBox pictureBox;
            private Bitmap original;
            private int[] brightnessValues;
    
    
            public BrightnessHistogramWindow(int[] brightnessValues, PictureBox pictureBox, Bitmap original)
            {
                InitializeComponent();
                this.brightnessValues = brightnessValues;
                this.pictureBox = pictureBox;
                this.original = original;
    
    
                binary_trackBar.Value = 0;
                binary_textBox.Text = binary_trackBar.Value.ToString();
    
    
                generateHistogram();
            }
    
    
            private void generateHistogram()
            {
                Pen pen = new Pen(Color.Black, 1);
                Point[] points = new Point[2];
    
    
                Bitmap bitmap = new Bitmap(histogramBox.Width, histogramBox.Height);
                Graphics graphics = Graphics.FromImage(bitmap);
                graphics.FillRectangle(Brushes.White, 0, 0, bitmap.Width, bitmap.Height);
    
    
                double size = brightnessValues.Max() / bitmap.Height;
                float scale;
    
    
                for (int i = 0; i < 256; i++)
                {
                    scale = histogramBox.Height - (float)(brightnessValues[i] / size);
                    graphics.DrawLine(Pens.Black, i, histogramBox.Height, i, scale);
                }
    
    
                max_Label.Text = brightnessValues.Max().ToString();
    
    
                histogramBox.Image = bitmap;
            }
    
    
            private void binary()
            {
                int binaryValue = binary_trackBar.Value;
    
    
                pictureBox.Image = (Bitmap)original.Clone();
                
                Bitmap bitmap = ChannelSelector.getYchannelFor((Bitmap)pictureBox.Image);
    
    
                System.Drawing.Imaging.BitmapData bitmapData;
    
    
                bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    
    
                int stride = bitmapData.Stride;
                int offset = stride - bitmap.Width * 3;
    
    
                System.IntPtr Scan0 = bitmapData.Scan0;
    
    
                unsafe
                {
                    byte* pointer = (byte*)(void*)Scan0;
    
    
                    for (int x = 0; x < bitmap.Height; ++x)
                    {
                        for (int y = 0; y < bitmap.Width; ++y)
                        {
                            if(pointer[0] > binaryValue)
                            {
                                pointer[0] = pointer[1] = pointer[2] = 255;
                            }
                            else if (pointer[0] <= binaryValue)
                            {
                                pointer[0] = pointer[1] = pointer[2] = 0;
                            }
    
    
                            pointer += 3;
                        }
                        pointer += offset;
                    }
                }
    
    
                bitmap.UnlockBits(bitmapData);
    
    
                pictureBox.Image = bitmap;
            }
    
    
            private void binary_scroll(object sender, EventArgs e)
            {
                binary_textBox.Text = binary_trackBar.Value.ToString();
    
    
                binary();
            }
    
    
            private void close_action(object sender, EventArgs e)
            {
                this.Close();
            }
        }
    Tutaj zamieściłem zbiór metod, które pozwalają modyfikować wartości pikseli, co finalnie daje dostęp do funkcji zmieniających bitmapę w pojedynczy kanał wybranego modelu braw. Np. metoda getUChannel() po wrzuceniu odpowiedniego parametru wejściowego, przekształci Bitmapę na wyświetlenie jedynie kanału U z modelu YUV. Uwaga! Metody działają na oryginale, a nie kopii! Zwracanie wartości jest dodatkowe, gdyby ktoś potrzebował kopii to może sobie to zaimplementować.

    Kod:
    class ChannelSelector {
    
    
            static private void changeChannelsValuesUsingRatiosAndExtraValue(Bitmap bitmap, int firstChannelRatio, int secondChannelRatio, int thirdChannelRatio, int extraValue) {
                System.Drawing.Imaging.BitmapData bitmapData;
    
    
                bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    
    
                int stride = bitmapData.Stride;
                int offset = stride - bitmap.Width * 3;
    
    
                System.IntPtr Scan0 = bitmapData.Scan0;
    
    
                unsafe
                {
                    byte* pointer = (byte*)(void*)Scan0;
    
    
                    for (int x = 0; x < bitmap.Height; ++x)
                    {
                        for (int y = 0; y < bitmap.Width; ++y)
                        {
                            pointer[0] = pointer[1] = pointer[2] = (byte)(((thirdChannelRatio * pointer[2] + secondChannelRatio * pointer[1] + firstChannelRatio * pointer[0] + 128) >> 8) + extraValue);
    
    
                            pointer += 3;
                        }
                        pointer += offset;
                    }
                }
    
    
                bitmap.UnlockBits(bitmapData);
            }
    
    
            static private void changeBitmapToSelectedRGBChannel(Bitmap inBitmap, Color inColor)  {
                System.Drawing.Imaging.BitmapData bitmapData;
    
    
                bitmapData = inBitmap.LockBits(new Rectangle(0, 0, inBitmap.Width, inBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    
    
                int stride = bitmapData.Stride;
                int offset = stride - inBitmap.Width * 3;
                int colorNumber = 0;
    
    
                if (inColor == Color.Red)
                {
                    colorNumber = 2;
                }
                else if (inColor == Color.Green)
                {
                    colorNumber = 1;
                }
                else if (inColor == Color.Blue)
                {
                    colorNumber = 0;
                }
    
    
                System.IntPtr Scan0 = bitmapData.Scan0;
    
    
                unsafe
                {
                    byte* pointer = (byte*)(void*)Scan0;
    
    
                    for (int x = 0; x < inBitmap.Height; ++x)
                    {
                        for (int y = 0; y < inBitmap.Width; ++y)
                        {
                            pointer[0] = pointer[1] = pointer[2] = (byte)(pointer[colorNumber]);
    
    
                            pointer += 3;
                        }
                        pointer += offset;
                    }
                }
    
    
                inBitmap.UnlockBits(bitmapData);
            }
    
    
            static private void changeBitmapToSelectedCMYKChannel(Bitmap inBitmap, Color inColor)
            {
                System.Drawing.Imaging.BitmapData bitmapData;
    
    
                bitmapData = inBitmap.LockBits(new Rectangle(0, 0, inBitmap.Width, inBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    
    
                int stride = bitmapData.Stride;
                int offset = stride - inBitmap.Width * 3;
    
    
                System.IntPtr Scan0 = bitmapData.Scan0;
    
    
                unsafe
                {
                    byte* pointer = (byte*)(void*)Scan0;
    
    
                    float cyan, magneta, yellow, black;
    
    
                    for (int y = 0; y < inBitmap.Height; y++)
                    {
                        for (int x = 0; x < inBitmap.Width; x++)
                        {
                            cyan = 1.0f - ((int)pointer[2] / 255.0f);
                            magneta = 1.0f - ((int)pointer[1] / 255.0f);
                            yellow = 1.0f - ((int)pointer[0] / 255.0f);
                            black = Math.Min(cyan, Math.Min(magneta, yellow));
    
    
                            if (black >= 1.0f)
                            {
                                cyan = magneta = yellow = 1.0f;
                            }
                            else
                            {
                                float divider = 1.0f - black;
                                cyan = (cyan - black) / divider;
                                magneta = (magneta - black) / divider;
                                yellow = (yellow - black) / divider;
                            }
    
    
                            if (inColor == Color.Cyan)
                            {
                                pointer[0] = pointer[1] = pointer[2] = (byte)(Math.Round(cyan * 255.0f));
                            }
                            else if (inColor == Color.Magenta)
                            {
                                pointer[0] = pointer[1] = pointer[2] = (byte)(Math.Round(magneta * 255.0f));
                            }
                            else if (inColor == Color.Yellow)
                            {
                                pointer[0] = pointer[1] = pointer[2] = (byte)(Math.Round(yellow * 255.0f));
                            }
                            else if (inColor == Color.Black)
                            {
                                pointer[0] = pointer[1] = pointer[2] = (byte)(Math.Round(black * 255.0f));
                            }
    
    
                            pointer += 3;
                        }
    
    
                        pointer += offset;
                    }
                }
    
    
                inBitmap.UnlockBits(bitmapData);
            }
    
    
            static public Bitmap getYchannelFor(Bitmap inBitmap) {
                Bitmap bitmap = inBitmap;
    
    
                changeChannelsValuesUsingRatiosAndExtraValue(bitmap, 66, 129, 25, 16);
    
    
                return bitmap;
            }
    
    
            static public Bitmap getUchannelFor(Bitmap inBitmap) {
                Bitmap bitmap = inBitmap;
    
    
                changeChannelsValuesUsingRatiosAndExtraValue(bitmap, -38, -74, 112, 128);
    
    
                return bitmap;
            }
    
    
            static public Bitmap getVchannelFor(Bitmap inBitmap) {
                Bitmap bitmap = inBitmap;
    
    
                changeChannelsValuesUsingRatiosAndExtraValue(bitmap, 112, -94, -18, 128);
    
    
                return bitmap;
            }
    
    
            static public Bitmap getRchannelFor(Bitmap inBitmap) {
                Bitmap bitmap = inBitmap;
    
    
                try {
                    changeBitmapToSelectedRGBChannel(bitmap, Color.Red);
                } catch (NullReferenceException exp) {
                    MessageBox.Show(exp.Message.ToString());
                }
    
    
                return bitmap;
            }
    
    
            static public Bitmap getGchannelFor(Bitmap inBitmap) {
                Bitmap bitmap = inBitmap;
    
    
                try {
                    changeBitmapToSelectedRGBChannel(bitmap, Color.Green);
                } catch (NullReferenceException exp) {
                    MessageBox.Show(exp.Message.ToString());
                }
    
    
                return bitmap;
            }
    
    
            static public Bitmap getBchannelFor(Bitmap inBitmap)  {
                Bitmap bitmap = inBitmap;
    
    
                try {
                    changeBitmapToSelectedRGBChannel(bitmap, Color.Blue);
                } catch (NullReferenceException exp) {
                    MessageBox.Show(exp.Message.ToString());
                }
    
    
                return bitmap;
            }
    
    
            static public Bitmap getCchannelFor(Bitmap inBitmap) {
                Bitmap bitmap = inBitmap;
    
    
                try
                {
                    changeBitmapToSelectedCMYKChannel(bitmap, Color.Cyan);
                }
                catch (NullReferenceException exp)
                {
                    MessageBox.Show(exp.Message.ToString());
                }
    
    
                return bitmap;
            }
    
    
            static public Bitmap getMchannelFor(Bitmap inBitmap) {
                Bitmap bitmap = inBitmap;
    
    
                try
                {
                    changeBitmapToSelectedCMYKChannel(bitmap, Color.Magenta);
                }
                catch (NullReferenceException exp)
                {
                    MessageBox.Show(exp.Message.ToString());
                }
    
    
                return bitmap;
            }
    
    
            static public Bitmap getYellowchannelFor(Bitmap inBitmap)
            {
                Bitmap bitmap = inBitmap;
    
    
                try
                {
                    changeBitmapToSelectedCMYKChannel(bitmap, Color.Yellow);
                }
                catch (NullReferenceException exp)
                {
                    MessageBox.Show(exp.Message.ToString());
                }
    
    
                return bitmap;
            }
    
    
            static public Bitmap getKchannelFor(Bitmap inBitmap)
            {
                Bitmap bitmap = inBitmap;
    
    
                try
                {
                    changeBitmapToSelectedCMYKChannel(bitmap, Color.Black);
                }
                catch (NullReferenceException exp)
                {
                    MessageBox.Show(exp.Message.ToString());
                }
    
    
                return bitmap;
            }
    
    
            static public int[] getBrightness(Bitmap inBitmap)
            {
                Bitmap bitmap = (Bitmap)inBitmap.Clone();
    
    
                changeChannelsValuesUsingRatiosAndExtraValue(bitmap, 66, 129, 25, 16);
    
    
                return getBrightnessValues(bitmap);
            }
    
    
            static private int[] getBrightnessValues(Bitmap bitmap)
            {
                System.Drawing.Imaging.BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    
    
                int stride = bitmapData.Stride;
                int offset = stride - bitmap.Width * 3;
    
    
                System.IntPtr Scan0 = bitmapData.Scan0;
    
    
                int[] brightnessValues = new int[256];
    
    
                unsafe
                {
                    byte* pointer = (byte*)(void*)Scan0;
    
    
                    for (int x = 0; x < bitmap.Height; ++x)
                    {
                        for (int y = 0; y < bitmap.Width; ++y)
                        {
                            brightnessValues[pointer[0]]++;
    
    
                            pointer += 3;
                        }
                        pointer += offset;
                    }
                }
    
    
                bitmap.UnlockBits(bitmapData);
    
    
                return brightnessValues;
            }
        }
    Filtr splotowy (convolution), gdzie na początku są macierze 3x3 oraz 5x5, które dalej służą do tworzenia dowolnych masek. W klasie Convolution znajdują się metody publiczne i na dodatek statyczne, które pozwalają na nałożenie efektu na Bitmapę (np. blur, sharp, custom). Bardzo łatwo można dorzucić własne efekty tworząc kolejną metodę i zmieniając jedynie wartości macierzy. Uwaga! Metody działają na oryginale, a nie kopii! Zwracanie wartości jest dodatkowe, gdyby ktoś potrzebował kopii to może sobie to zaimplementować.

    Kod:
     public class ConvolutionMatrix3x3
        {
            public int TopLeft = 0, TopMid = 0, TopRight = 0;
            public int MidLeft = 0, Pixel = 1, MidRight = 0;
            public int BottomLeft = 0, BottomMid = 0, BottomRight = 0;
            public int Factor = 1;
            public int Offset = 0;
    
    
            public void setAll(int inValue)
            {
                TopLeft = TopMid = TopRight = MidLeft = Pixel = MidRight = BottomLeft = BottomMid = BottomRight 
                    = inValue;
            }
        }
    
    
        public class ConvolutionMatrix5x5
        {
            public int[] values = new int[25];
            public int Factor = 1;
            public int Offset = 0;
        }
    
    
        class Convolution
        {
            private static int correctPixelIfOutOfRange(int pixel)
            {
                if (pixel < 0)
                {
                    return 0;
                }
                if (pixel > 255)
                {
                    return 255;
                }
                return pixel;
            }
    
    
            private static Bitmap getConverted(Bitmap inBitmap, ConvolutionMatrix3x3 inMatrix)        {
                if (inMatrix.Factor == 0)
                {
                    throw new ArithmeticException("Divide by zero error!");
                }
    
    
                Bitmap buffer = (Bitmap)inBitmap.Clone();
    
    
                BitmapData bitmapData = inBitmap.LockBits(new Rectangle(0, 0, inBitmap.Width, inBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                BitmapData bitmapSource = buffer.LockBits(new Rectangle(0, 0, buffer.Width, buffer.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    
    
                int stride = bitmapData.Stride;
                int stride2 = stride * 2;
                int offset = stride - inBitmap.Width * 3;
    
    
                int width = inBitmap.Width - 2;
                int height = inBitmap.Height - 2;
    
    
                System.IntPtr Scan0 = bitmapData.Scan0;
                System.IntPtr SrcScan0 = bitmapSource.Scan0;
    
    
                unsafe
                {
                    byte* pointer = (byte*)(void*)Scan0;
                    byte* sourceBitmapPointer = (byte*)(void*)SrcScan0;
    
    
                    int pixel;
    
    
                    for (int y = 0; y < height; ++y)
                    {
                        for (int x = 0; x < width; ++x)
                        {
                            pixel = ((((sourceBitmapPointer[2] * inMatrix.TopLeft) +
                                        (sourceBitmapPointer[5] * inMatrix.TopMid) +
                                        (sourceBitmapPointer[8] * inMatrix.TopRight) +
    
    
                                        (sourceBitmapPointer[2 + stride] * inMatrix.MidLeft) +
                                        (sourceBitmapPointer[5 + stride] * inMatrix.Pixel) +
                                        (sourceBitmapPointer[8 + stride] * inMatrix.MidRight) +
    
    
                                        (sourceBitmapPointer[2 + stride2] * inMatrix.BottomLeft) +
                                        (sourceBitmapPointer[5 + stride2] * inMatrix.BottomMid) +
                                        (sourceBitmapPointer[8 + stride2] * inMatrix.BottomRight)) / inMatrix.Factor) + inMatrix.Offset);
    
    
                            pixel = correctPixelIfOutOfRange(pixel);
    
    
                            pointer[5 + stride] = (byte)pixel;
    
    
                            pixel = ((((sourceBitmapPointer[1] * inMatrix.TopLeft) +
                                        (sourceBitmapPointer[4] * inMatrix.TopMid) +
                                        (sourceBitmapPointer[7] * inMatrix.TopRight) +
    
    
                                        (sourceBitmapPointer[1 + stride] * inMatrix.MidLeft) +
                                        (sourceBitmapPointer[4 + stride] * inMatrix.Pixel) +
                                        (sourceBitmapPointer[7 + stride] * inMatrix.MidRight) +
    
    
                                        (sourceBitmapPointer[1 + stride2] * inMatrix.BottomLeft) +
                                        (sourceBitmapPointer[4 + stride2] * inMatrix.BottomMid) +
                                        (sourceBitmapPointer[7 + stride2] * inMatrix.BottomRight)) / inMatrix.Factor) + inMatrix.Offset);
    
    
                            pixel = correctPixelIfOutOfRange(pixel);
    
    
                            pointer[4 + stride] = (byte)pixel;
    
    
                            pixel = ((((sourceBitmapPointer[0] * inMatrix.TopLeft) +
                                           (sourceBitmapPointer[3] * inMatrix.TopMid) +
                                           (sourceBitmapPointer[6] * inMatrix.TopRight) +
    
    
                                           (sourceBitmapPointer[0 + stride] * inMatrix.MidLeft) +
                                           (sourceBitmapPointer[3 + stride] * inMatrix.Pixel) +
                                           (sourceBitmapPointer[6 + stride] * inMatrix.MidRight) +
    
    
                                           (sourceBitmapPointer[0 + stride2] * inMatrix.BottomLeft) +
                                           (sourceBitmapPointer[3 + stride2] * inMatrix.BottomMid) +
                                           (sourceBitmapPointer[6 + stride2] * inMatrix.BottomRight)) / inMatrix.Factor) + inMatrix.Offset);
    
    
                            pixel = correctPixelIfOutOfRange(pixel);
    
    
                            pointer[3 + stride] = (byte)pixel;
    
    
                            pointer += 3;
                            sourceBitmapPointer += 3;
                        }
    
    
                        pointer += offset;
                        sourceBitmapPointer += offset;
                    }
                }
    
    
                inBitmap.UnlockBits(bitmapData);
                buffer.UnlockBits(bitmapSource);
    
    
                return inBitmap;
            }
    
    
            private static Bitmap getConverted(Bitmap inBitmap, ConvolutionMatrix5x5 inMatrix)
            {
                int[] matrixValues = inMatrix.values;
                int matrixOffset = inMatrix.Offset;
    
    
                if (0 == inMatrix.Factor)
                {
                    throw new ArithmeticException("Divide by zero error!");
                }
    
    
                Bitmap sourceBitmap = (Bitmap)inBitmap.Clone();
    
    
                BitmapData bitmapData = inBitmap.LockBits(new Rectangle(0, 0, inBitmap.Width, inBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                BitmapData sourceBitmapData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
    
    
                int stride = bitmapData.Stride;
                int stride2 = stride * 2;
                int stride3 = stride * 3;
                int stride4 = stride * 4;
    
    
                int length = (int)Math.Sqrt(matrixValues.Length);
    
    
                System.IntPtr Scan0 = bitmapData.Scan0;
                System.IntPtr SrcScan0 = sourceBitmapData.Scan0;
    
    
                unsafe
                {
                    byte* pointer = (byte*)(void*)Scan0;
                    byte* sourceBitmapPointer = (byte*)(void*)SrcScan0;
    
    
                    int width = inBitmap.Width - 4;
                    int height = inBitmap.Height - 4;
    
    
                    int pixel;
    
                    //top
                    for (int y = 0; y < 3; ++y)
                    {
                        for (int x = 3; x < inBitmap.Width - 4; ++x)
                        {
                            pixel = (((sourceBitmapPointer[0 + stride2] * matrixValues[0]) +
                                            (sourceBitmapPointer[4 + stride2] * matrixValues[1]) +
                                            (sourceBitmapPointer[8 + stride2] * matrixValues[2]) +
                                            (sourceBitmapPointer[12 + stride2] * matrixValues[3]) +
                                            (sourceBitmapPointer[16 + stride2] * matrixValues[4]) +
    
    
                                            (sourceBitmapPointer[0 + stride] * matrixValues[5]) +
                                            (sourceBitmapPointer[4 + stride] * matrixValues[6]) +
                                            (sourceBitmapPointer[8 + stride] * matrixValues[7]) +
                                            (sourceBitmapPointer[12 + stride] * matrixValues[8]) +
                                            (sourceBitmapPointer[16 + stride] * matrixValues[9]) +
    
    
                                            (sourceBitmapPointer[0] * matrixValues[10]) +
                                            (sourceBitmapPointer[4] * matrixValues[11]) +
                                            (sourceBitmapPointer[8] * matrixValues[12]) +
                                            (sourceBitmapPointer[12] * matrixValues[13]) +
                                            (sourceBitmapPointer[16] * matrixValues[14]) +
    
    
                                            (sourceBitmapPointer[0 + stride] * matrixValues[15]) +
                                            (sourceBitmapPointer[4 + stride] * matrixValues[16]) +
                                            (sourceBitmapPointer[8 + stride] * matrixValues[17]) +
                                            (sourceBitmapPointer[12 + stride] * matrixValues[18]) +
                                            (sourceBitmapPointer[16 + stride] * matrixValues[19]) +
    
    
                                            (sourceBitmapPointer[0 + stride2] * matrixValues[20]) +
                                            (sourceBitmapPointer[4 + stride2] * matrixValues[21]) +
                                            (sourceBitmapPointer[8 + stride2] * matrixValues[22]) +
                                            (sourceBitmapPointer[12 + stride2] * matrixValues[23]) +
                                            (sourceBitmapPointer[16 + stride2] * matrixValues[24])) / inMatrix.Factor) + matrixOffset;
    
    
                            pixel = correctPixelIfOutOfRange(pixel);
    
    
                            pointer[2] = (byte)pixel;
    
    
                            pixel = (((sourceBitmapPointer[1 + stride2] * matrixValues[0]) +
                                            (sourceBitmapPointer[5 + stride2] * matrixValues[1]) +
                                            (sourceBitmapPointer[9 + stride2] * matrixValues[2]) +
                                            (sourceBitmapPointer[13 + stride2] * matrixValues[3]) +
                                            (sourceBitmapPointer[17 + stride2] * matrixValues[4]) +
    
    
                                            (sourceBitmapPointer[1 + stride] * matrixValues[5]) +
                                            (sourceBitmapPointer[5 + stride] * matrixValues[6]) +
                                            (sourceBitmapPointer[9 + stride] * matrixValues[7]) +
                                            (sourceBitmapPointer[13 + stride] * matrixValues[8]) +
                                            (sourceBitmapPointer[17 + stride] * matrixValues[9]) +
    
    
                                            (sourceBitmapPointer[1] * matrixValues[10]) +
                                            (sourceBitmapPointer[5] * matrixValues[11]) +
                                            (sourceBitmapPointer[9] * matrixValues[12]) +
                                            (sourceBitmapPointer[13] * matrixValues[13]) +
                                            (sourceBitmapPointer[17] * matrixValues[14]) +
    
    
                                            (sourceBitmapPointer[1 + stride] * matrixValues[15]) +
                                            (sourceBitmapPointer[5 + stride] * matrixValues[16]) +
                                            (sourceBitmapPointer[9 + stride] * matrixValues[17]) +
                                            (sourceBitmapPointer[13 + stride] * matrixValues[18]) +
                                            (sourceBitmapPointer[17 + stride] * matrixValues[19]) +
    
    
                                            (sourceBitmapPointer[1 + stride2] * matrixValues[20]) +
                                            (sourceBitmapPointer[5 + stride2] * matrixValues[21]) +
                                            (sourceBitmapPointer[9 + stride2] * matrixValues[22]) +
                                            (sourceBitmapPointer[13 + stride2] * matrixValues[23]) +
                                            (sourceBitmapPointer[17 + stride2] * matrixValues[24])) / inMatrix.Factor) + matrixOffset;
    
    
                            pixel = correctPixelIfOutOfRange(pixel);
    
    
                            pointer[1] = (byte)pixel;
    
    
                            pixel = (((sourceBitmapPointer[2 + stride2] * matrixValues[0]) +
                                            (sourceBitmapPointer[6 + stride2] * matrixValues[1]) +
                                            (sourceBitmapPointer[10 + stride2] * matrixValues[2]) +
                                            (sourceBitmapPointer[14 + stride2] * matrixValues[3]) +
                                            (sourceBitmapPointer[18 + stride2] * matrixValues[4]) +
    
    
                                            (sourceBitmapPointer[2 + stride] * matrixValues[5]) +
                                            (sourceBitmapPointer[6 + stride] * matrixValues[6]) +
                                            (sourceBitmapPointer[10 + stride] * matrixValues[7]) +
                                            (sourceBitmapPointer[14 + stride] * matrixValues[8]) +
                                            (sourceBitmapPointer[18 + stride] * matrixValues[9]) +
    
    
                                            (sourceBitmapPointer[2] * matrixValues[10]) +
                                            (sourceBitmapPointer[6] * matrixValues[11]) +
                                            (sourceBitmapPointer[10] * matrixValues[12]) +
                                            (sourceBitmapPointer[14] * matrixValues[13]) +
                                            (sourceBitmapPointer[18] * matrixValues[14]) +
    
    
                                            (sourceBitmapPointer[2 + stride] * matrixValues[15]) +
                                            (sourceBitmapPointer[6 + stride] * matrixValues[16]) +
                                            (sourceBitmapPointer[10 + stride] * matrixValues[17]) +
                                            (sourceBitmapPointer[14 + stride] * matrixValues[18]) +
                                            (sourceBitmapPointer[18 + stride] * matrixValues[19]) +
    
    
                                            (sourceBitmapPointer[2 + stride2] * matrixValues[20]) +
                                            (sourceBitmapPointer[6 + stride2] * matrixValues[21]) +
                                            (sourceBitmapPointer[10 + stride2] * matrixValues[22]) +
                                            (sourceBitmapPointer[14 + stride2] * matrixValues[23]) +
                                            (sourceBitmapPointer[18 + stride2] * matrixValues[24])) / inMatrix.Factor) + matrixOffset;
    
    
                            pixel = correctPixelIfOutOfRange(pixel);
    
    
                            pointer[0] = (byte)pixel;
    
    
                            pointer += 4;
                            sourceBitmapPointer += 4;
                        }
                        pointer += (length - 1) * 4;
                        sourceBitmapPointer += (length - 1) * 4;
                    }
    
    
                    pointer = (byte*)(void*)Scan0;
                    sourceBitmapPointer = (byte*)(void*)SrcScan0;
    
    
                    for (int y = 0; y < height; y++)
                    {
                        for (int x = 0; x < width; x++)
                        {
                            pixel = (((sourceBitmapPointer[0] * matrixValues[0]) +
                                        (sourceBitmapPointer[4] * matrixValues[1]) +
                                        (sourceBitmapPointer[8] * matrixValues[2]) +
                                        (sourceBitmapPointer[12] * matrixValues[3]) +
                                        (sourceBitmapPointer[16] * matrixValues[4]) +
    
    
                                        (sourceBitmapPointer[0 + stride] * matrixValues[5]) +
                                        (sourceBitmapPointer[4 + stride] * matrixValues[6]) +
                                        (sourceBitmapPointer[8 + stride] * matrixValues[7]) +
                                        (sourceBitmapPointer[12 + stride] * matrixValues[8]) +
                                        (sourceBitmapPointer[16 + stride] * matrixValues[9]) +
    
    
                                        (sourceBitmapPointer[0 + stride2] * matrixValues[10]) +
                                        (sourceBitmapPointer[4 + stride2] * matrixValues[11]) +
                                        (sourceBitmapPointer[8 + stride2] * matrixValues[12]) +
                                        (sourceBitmapPointer[12 + stride2] * matrixValues[13]) +
                                        (sourceBitmapPointer[16 + stride2] * matrixValues[14]) +
    
    
                                        (sourceBitmapPointer[0 + stride3] * matrixValues[15]) +
                                        (sourceBitmapPointer[4 + stride3] * matrixValues[16]) +
                                        (sourceBitmapPointer[8 + stride3] * matrixValues[17]) +
                                        (sourceBitmapPointer[12 + stride3] * matrixValues[18]) +
                                        (sourceBitmapPointer[16 + stride3] * matrixValues[19]) +
    
    
                                        (sourceBitmapPointer[0 + stride4] * matrixValues[20]) +
                                        (sourceBitmapPointer[4 + stride4] * matrixValues[21]) +
                                        (sourceBitmapPointer[8 + stride4] * matrixValues[22]) +
                                        (sourceBitmapPointer[12 + stride4] * matrixValues[23]) +
                                        (sourceBitmapPointer[16 + stride4] * matrixValues[24])) / inMatrix.Factor) + matrixOffset;
    
    
                            pixel = correctPixelIfOutOfRange(pixel);
    
    
                            pointer[8 + stride2] = (byte)pixel;
    
    
                            pixel = (((sourceBitmapPointer[1] * matrixValues[0]) +
                                        (sourceBitmapPointer[5] * matrixValues[1]) +
                                        (sourceBitmapPointer[9] * matrixValues[2]) +
                                        (sourceBitmapPointer[13] * matrixValues[3]) +
                                        (sourceBitmapPointer[17] * matrixValues[4]) +
    
    
                                        (sourceBitmapPointer[1 + stride] * matrixValues[5]) +
                                        (sourceBitmapPointer[5 + stride] * matrixValues[6]) +
                                        (sourceBitmapPointer[9 + stride] * matrixValues[7]) +
                                        (sourceBitmapPointer[13 + stride] * matrixValues[8]) +
                                        (sourceBitmapPointer[17 + stride] * matrixValues[9]) +
    
    
                                        (sourceBitmapPointer[1 + stride2] * matrixValues[10]) +
                                        (sourceBitmapPointer[5 + stride2] * matrixValues[11]) +
                                        (sourceBitmapPointer[9 + stride2] * matrixValues[12]) +
                                        (sourceBitmapPointer[13 + stride2] * matrixValues[13]) +
                                        (sourceBitmapPointer[17 + stride2] * matrixValues[14]) +
    
    
                                        (sourceBitmapPointer[1 + stride3] * matrixValues[15]) +
                                        (sourceBitmapPointer[5 + stride3] * matrixValues[16]) +
                                        (sourceBitmapPointer[9 + stride3] * matrixValues[17]) +
                                        (sourceBitmapPointer[13 + stride3] * matrixValues[18]) +
                                        (sourceBitmapPointer[17 + stride3] * matrixValues[19]) +
    
    
                                        (sourceBitmapPointer[1 + stride4] * matrixValues[20]) +
                                        (sourceBitmapPointer[5 + stride4] * matrixValues[21]) +
                                        (sourceBitmapPointer[9 + stride4] * matrixValues[22]) +
                                        (sourceBitmapPointer[13 + stride4] * matrixValues[23]) +
                                        (sourceBitmapPointer[17 + stride4] * matrixValues[24])) / inMatrix.Factor) + matrixOffset;
    
    
                            pixel = correctPixelIfOutOfRange(pixel);
    
    
                            pointer[9 + stride2] = (byte)pixel;
    
    
                            pixel = (((sourceBitmapPointer[2] * matrixValues[0]) +
                                        (sourceBitmapPointer[6] * matrixValues[1]) +
                                        (sourceBitmapPointer[10] * matrixValues[2]) +
                                        (sourceBitmapPointer[14] * matrixValues[3]) +
                                        (sourceBitmapPointer[18] * matrixValues[4]) +
    
    
                                        (sourceBitmapPointer[2 + stride] * matrixValues[5]) +
                                        (sourceBitmapPointer[6 + stride] * matrixValues[6]) +
                                        (sourceBitmapPointer[10 + stride] * matrixValues[7]) +
                                        (sourceBitmapPointer[14 + stride] * matrixValues[8]) +
                                        (sourceBitmapPointer[18 + stride] * matrixValues[9]) +
    
    
                                        (sourceBitmapPointer[2 + stride2] * matrixValues[10]) +
                                        (sourceBitmapPointer[6 + stride2] * matrixValues[11]) +
                                        (sourceBitmapPointer[10 + stride2] * matrixValues[12]) +
                                        (sourceBitmapPointer[14 + stride2] * matrixValues[13]) +
                                        (sourceBitmapPointer[18 + stride2] * matrixValues[14]) +
    
    
                                        (sourceBitmapPointer[2 + stride3] * matrixValues[15]) +
                                        (sourceBitmapPointer[6 + stride3] * matrixValues[16]) +
                                        (sourceBitmapPointer[10 + stride3] * matrixValues[17]) +
                                        (sourceBitmapPointer[14 + stride3] * matrixValues[18]) +
                                        (sourceBitmapPointer[18 + stride3] * matrixValues[19]) +
    
    
                                        (sourceBitmapPointer[2 + stride4] * matrixValues[20]) +
                                        (sourceBitmapPointer[6 + stride4] * matrixValues[21]) +
                                        (sourceBitmapPointer[10 + stride4] * matrixValues[22]) +
                                        (sourceBitmapPointer[14 + stride4] * matrixValues[23]) +
                                        (sourceBitmapPointer[18 + stride4] * matrixValues[24])) / inMatrix.Factor) + matrixOffset;
    
    
                            pixel = correctPixelIfOutOfRange(pixel);
    
    
                            pointer[10 + stride2] = (byte)pixel;
    
    
                            pointer += 4;
                            sourceBitmapPointer += 4;
                        }
    
    
                        pointer += (length - 1) * 4;
                        sourceBitmapPointer += (length - 1) * 4;
                    }
                }
    
    
                inBitmap.UnlockBits(bitmapData);
                sourceBitmap.UnlockBits(sourceBitmapData);
    
    
                return inBitmap;
            }
    
    
            public static Bitmap getBlurred(Bitmap inBitmap)
            {
                Bitmap bitmap = inBitmap;
    
    
                ConvolutionMatrix3x3 matrix = new ConvolutionMatrix3x3();
    
    
                matrix.setAll(1);
    
    
                matrix.Pixel = 1;
                matrix.Factor = 9;
    
    
                try
                {
                    bitmap = getConverted(bitmap, matrix);
                }
                catch (ArithmeticException e)
                {
                    MessageBox.Show(e.Message.ToString());
                }
    
    
                return bitmap;
            }
    
    
            public static Bitmap getGausianBlurred(Bitmap inBitmap)
            {
                Bitmap bitmap = inBitmap;
    
    
                ConvolutionMatrix3x3 matrix = new ConvolutionMatrix3x3();
    
    
                matrix.TopLeft = 1;
                matrix.TopMid = 2;
                matrix.TopRight = 1;
    
    
                matrix.MidLeft = 2;
                matrix.Pixel = 4;
                matrix.MidRight = 2;
    
    
                matrix.BottomLeft = 1;
                matrix.BottomMid = 2;
                matrix.BottomRight = 1;
    
    
                matrix.Factor = 16;
    
    
                try
                {
                    bitmap = getConverted(bitmap, matrix);
                }
                catch (ArithmeticException e)
                {
                    MessageBox.Show(e.Message.ToString());
                }
    
    
                return bitmap;
            }
    
    
            public static Bitmap getSharpen(Bitmap inBitmap)
            {
                Bitmap bitmap = inBitmap;
    
    
                ConvolutionMatrix3x3 matrix = new ConvolutionMatrix3x3();
    
    
                matrix.TopLeft = 0;
                matrix.TopMid = -1;
                matrix.TopRight = 0;
    
    
                matrix.MidLeft = -1;
                matrix.Pixel = 5;
                matrix.MidRight = -1;
    
    
                matrix.BottomLeft = 0;
                matrix.BottomMid = -1;
                matrix.BottomRight = 0;
    
    
                matrix.Factor = 1;
    
    
                try
                {
                    bitmap = getConverted(bitmap, matrix);
                }
                catch (ArithmeticException e)
                {
                    MessageBox.Show(e.Message.ToString());
                }
    
    
                return bitmap;
            }
    
    
            public static Bitmap custom(Bitmap inBitmap, ConvolutionMatrix3x3 matrix)
            {
                try
                {
                    inBitmap = getConverted(inBitmap, matrix);
                }
                catch (ArithmeticException e)
                {
                    MessageBox.Show(e.Message.ToString());
                }
    
    
                return inBitmap;
            }
    
    
            public static Bitmap custom(Bitmap inBitmap, ConvolutionMatrix5x5 matrix)
            {
                try
                {
                    inBitmap = getConverted(inBitmap, matrix);
                }
                catch (ArithmeticException e)
                {
                    MessageBox.Show(e.Message.ToString());
                }
    
    
                return inBitmap;
            }
        }
    Okno dla "customowego" filtru splotowego z użyciem maski w postaci macierzy 3x3. Jako argument konstruktora wystarczy jedynie PictureBox. Ponownie całość działa na oryginale. Piszę o tym, ponieważ u mnie (wersja załączona) można łatwo cofnąć każdą akcję, ponieważ mam to zaimplementowane w oknie głównym.

    Kod:
    public partial class Custom3x3ConvolutionFilterControl : Form
        {
            private ConvolutionMatrix3x3 matrix;
            private PictureBox picture;
    
    
            public Custom3x3ConvolutionFilterControl(PictureBox picture)
            {
                matrix = new ConvolutionMatrix3x3();
                this.picture = picture;
    
    
                InitializeComponent();
            }
    
    
            private bool isEnteredValuesEmpty()
            {
                if (TopLeft_textBox.Text == null && TopMid_textBox.Text == null && TopRight_textBox.Text == null &&
                    MidLeft_textBox.Text == null && Pixel_textBox.Text == null && MidRight_textBox.Text == null &&
                    BottomLeft_textBox.Text == null && BottomMid_textBox.Text == null && BottomRight_textBox.Text == null &&
                    Factor_textBox.Text == null)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
    
    
            private bool setMatrixValues()
            {
                try
                {
                    matrix.TopLeft = int.Parse(TopLeft_textBox.Text);
                    matrix.TopMid = int.Parse(TopMid_textBox.Text);
                    matrix.TopRight = int.Parse(TopRight_textBox.Text);
    
    
                    matrix.MidLeft = int.Parse(MidLeft_textBox.Text);
                    matrix.Pixel = int.Parse(Pixel_textBox.Text);
                    matrix.MidRight = int.Parse(MidRight_textBox.Text);
    
    
                    matrix.BottomLeft = int.Parse(BottomLeft_textBox.Text);
                    matrix.BottomMid = int.Parse(BottomMid_textBox.Text);
                    matrix.BottomRight = int.Parse(BottomRight_textBox.Text);
    
    
                    matrix.Factor = int.Parse(Factor_textBox.Text);
                    return true;
                } 
                catch(FormatException e)
                {
                    MessageBox.Show(e.Message.ToString() + " Spróbuj ponownie.");
                    return false;
                }
            }
    
    
            private void setImage(Bitmap inBitmap)
            {
                try
                {
                    picture.Image = inBitmap;
                }
                catch (SystemException exp)
                {
                    MessageBox.Show(exp.Message.ToString());
                }
            }
    
    
            private void set_action(object sender, EventArgs e)
            {
                bool isValid = setMatrixValues();
    
    
                if (isValid == true)
                {
                    Bitmap image = Convolution.custom((Bitmap)picture.Image, matrix);
                    setImage(image);
                } 
            }
    
    
            private void close_action(object sender, EventArgs e)
            {
                this.Close();
            }
        }
    Prostsze efekty (inwersja i skala szarości), znów na wskaźnikach. Dostępne są metody publiczne i zarazem statyczne, więc korzystanie z tego jest bardzo proste. Ponownie ostrzegam, że funkcje działają na oryginałach.

    Kod:
    class Effects
        {
            static public Bitmap getInverted(Bitmap inBitmap)
            {
                Bitmap bitmap = inBitmap;
                System.Drawing.Imaging.BitmapData bitmapData;
    
    
                bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    
    
                int stride = bitmapData.Stride;
                int offset = stride - bitmap.Width * 3;
                int width = bitmap.Width * 3;
    
    
                System.IntPtr Scan0 = bitmapData.Scan0;
    
    
                unsafe
                {
                    byte* pointer = (byte*)(void*)Scan0;
    
    
                    for (int y = 0; y < bitmap.Height; ++y)
                    {
                        for (int x = 0; x < width; ++x)
                        {
                            pointer[0] = (byte)(255 - pointer[0]);
                            ++pointer;
                        }
                        pointer += offset;
                    }
                }
    
    
                bitmap.UnlockBits(bitmapData);
    
    
                return bitmap;
            }
    
    
            static public Bitmap getGrayscale(Bitmap inBitmap)
            {
                Bitmap bitmap = inBitmap;
                bitmap = ChannelSelector.getYchannelFor(bitmap);
                return bitmap;
            }
        }
    Otwieranie obrazka z pliku. Tutaj można sobie zaimplementować obsługę innych formatów plików.

    Kod:
    public class FileOpener
        {
            private OpenFileDialog openFileDialog;
            private PictureBox picture;
    
    
            public FileOpener(OpenFileDialog inOpenFileDialog, PictureBox inPicture)
            {
                openFileDialog = inOpenFileDialog;
                picture = inPicture;
            }
    
    
            private void loadFileNamed(string inName)
            {
                try
                {
                    picture.Image = new Bitmap(inName);
                }
                catch (SystemException exp)
                {
                    MessageBox.Show(exp.Message.ToString());
                }
            }
    
    
            private void setOpenFileDialogCheckers(bool state)
            {
                openFileDialog.AddExtension = state;
                openFileDialog.CheckFileExists = state;
                openFileDialog.CheckPathExists = state;
            }
    
    
            static private bool isDialogResultOK(OpenFileDialog inDialog)
            {
                return inDialog.ShowDialog() == DialogResult.OK;
            }
    
    
            public void openFile()
            {
                openFileDialog.Title = "Open Image";
                openFileDialog.Filter = "jpg files (*.jpg)|*.jpg";
    
    
                setOpenFileDialogCheckers(true);
    
    
                if (isDialogResultOK(openFileDialog))
                {
                    loadFileNamed(openFileDialog.FileName);
                }
            }
        }
    Zapisywanie pliku. Ponownie można to rozszerzyć o inne formaty.

    Kod:
    class FileSaver
        {
            private SaveFileDialog saveFileDialog;
            private PictureBox picture;
    
    
            public FileSaver(SaveFileDialog inSaveFileDialog, PictureBox inPicture)
            {
                saveFileDialog = inSaveFileDialog;
                picture = inPicture;
            }
    
    
            static private bool isDialogResultOK(SaveFileDialog inDialog)
            {
                return inDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK;
            }
    
    
            private void saveFileNamedInFormat(string inName, System.Drawing.Imaging.ImageFormat inFormat)
            {
                try
                {
                    picture.Image.Save(inName, inFormat);
                }
                catch (SystemException exp)
                {
                    MessageBox.Show(exp.Message.ToString());
                }
            }
    
    
            public void saveFile()
            {
                saveFileDialog.Title = "Save Image";
                saveFileDialog.Filter = "jpg files (*.jpg)|*.jpg";
    
    
                if (isDialogResultOK(saveFileDialog))
                {
                    saveFileNamedInFormat(saveFileDialog.FileName, System.Drawing.Imaging.ImageFormat.Jpeg);
                }
            }
        }
    Klasa dla filtru HSL. Najważniejsza jest w sumie metoda setHSL, w której przekazywana jest m.in. tablica float'ów, która zawiera kolejne wartości ustawiane na suwakach (w kolejności {H, L, S}). Jeśli komuś kolejność nie odpowiada to można łatwo poprawić w pętli zmieniającej pojedyncze piksele. U mnie jest tak, a nie inaczej, bo robiłem na szybko i się lekko walnąłem . Ale działa
    Ponownie - to śmiga na oryginale Bitmapy, a nie kopii.

    Kod:
    public class HSL
        {
                private float hue;
                private float saturation;
                private float lightness;
    
    
                private HSL() {}
    
    
                public HSL(float hue, float saturation, float lightness)
                {
                    this.hue = hue;
                    this.saturation = saturation;
                    this.lightness = lightness;
                }
    
    
                public float getHue()
                {
                    return hue;
                }
    
    
                public void setHue(float value)
                {
                    hue = (float)(Math.Abs(value) % 360);
                }
    
    
                public float getSaturation()
                {
                    return saturation;
                }
    
    
                public void setSaturation(float value)
                {
                    saturation = (float)Math.Max(Math.Min(1.0, value), 0.0);
                }
    
    
                public float getLightness()
                {
                    return lightness;
                }
    
    
                public void setLightness(float value)
                {
                    lightness = (float)Math.Max(Math.Min(1.0, value), 0.0);
                }
    
    
                public static HSL FromRGB(byte red, byte green, byte blue)
                {
                    return FromRGB(Color.FromArgb(red, green, blue));
                }
    
    
                public static HSL FromRGB(Color color)
                {
                    return new HSL(color.GetHue(), color.GetSaturation(), color.GetBrightness());
                }
    
    
                public Color getRGB()
                {
                    double red = 0, green = 0, blue = 0;
                    double normalisedHue = hue / 360.0;
                    double temp1, temp2;
    
    
                    if (this.lightness == 0)
                    {
                        red = green = blue = 0;
                    }
                    else
                    {
                        if (saturation == 0)
                        {
                            red = green = blue = this.lightness;
                        }
                        else
                        {
                            temp2 = ((this.lightness <= 0.5) ? this.lightness * (1.0 + this.saturation) : this.lightness + this.saturation - (this.lightness * this.saturation));
                            temp1 = 2.0 * this.lightness - temp2;
    
    
                            double[] hueTable = new double[] { normalisedHue + 1.0 / 3.0, normalisedHue, normalisedHue - 1.0 / 3.0 };
                            double[] result = new double[] { 0, 0, 0 };
    
    
                            for (int i = 0; i < 3; ++i)
                            {
                                if (hueTable[i] < 0)
                                {
                                    hueTable[i] += 1.0;
                                }
    
    
                                if (hueTable[i] > 1)
                                {
                                    hueTable[i] -= 1.0;
                                }
    
    
                                if (6.0 * hueTable[i] < 1.0)
                                {
                                    result[i] = temp1 + (temp2 - temp1) * hueTable[i] * 6.0;
                                }
                                else if (2.0 * hueTable[i] < 1.0)
                                {
                                    result[i] = temp2;
                                }
                                else if (3.0 * hueTable[i] < 2.0)
                                {
                                    result[i] = (temp1 + (temp2 - temp1) * ((2.0 / 3.0) - hueTable[i]) * 6.0);
                                }
                                else
                                {
                                    result[i] = temp1;
                                }
                            }
    
    
                            red = result[0];
                            green = result[1];
                            blue = result[2];
                        }
                    }
    
    
                    return Color.FromArgb((int)(255 * red), (int)(255 * green), (int)(255 * blue));
                }
    
    
                public static Bitmap setHSL(Bitmap source, float[] factors)
                {
                    int width = source.Width;
                    int height = source.Height;
    
    
                    Bitmap destination = new Bitmap(width, height, source.PixelFormat);
    
    
                    BitmapData dataSource = source.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
                    BitmapData dataDestination = destination.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    
    
                    int offset = dataSource.Stride - (width * 3);
    
    
                    HSL hsl;
                    Color color;
    
    
                    unsafe
                    {
                        byte* sourcePointer = (byte*)(void*)dataSource.Scan0;
                        byte* destinationPointer = (byte*)(void*)dataDestination.Scan0;
    
    
                        for (int y = 0; y < height; ++y)
                        {
                            for (int x = 0; x < width; ++x)
                            {
                                hsl = HSL.FromRGB(sourcePointer[2], sourcePointer[1], sourcePointer[0]);
    
    
                                hsl.setHue(hsl.getHue() + factors[0]);
                                hsl.setLightness(hsl.getLightness() * factors[1]);
                                hsl.setSaturation(hsl.getSaturation() * factors[2]);
    
    
                                color = hsl.getRGB();
    
    
                                destinationPointer[0] = color.B;
                                destinationPointer[1] = color.G;
                                destinationPointer[2] = color.R;
    
    
                                sourcePointer += 3;
                                destinationPointer += 3;
                            }
    
    
                            destinationPointer += offset;
                            sourcePointer += offset;
                        }
    
    
                        source.UnlockBits(dataSource);
                        destination.UnlockBits(dataDestination);
                    }
    
    
                    return destination;
                }
        }
    Załączone pliki Załączone pliki
    Ostatnio edytowane przez Dawid_S ; 26-01-2014 o 10:25

  2. #2
    Użytkownik Podkręca śrubokrętem Reputacja:   (0)
    Dołączył
    09.2014
    Posty
    1
    Napisałam Ci wiadomość, sprawdz proszę

  3. #3
    Advert Manager Guru overclockingu Reputacja:   (13) Awatar Dawid_S
    Dołączył
    05.2009
    Posty
    6,599
    Ludzie pytają o kody źródłowe całej reszty, dlatego wrzuciłem ponownie na GitHub - https://github.com/dawidsamolyk/SimpleImageProcessing

  4. #4
    Redaktor i Administrator Extreme overclocker Reputacja:   (20) Awatar majkel_94
    Dołączył
    07.2009
    Skąd
    Katowice
    Posty
    3,040
    Cytat Zamieszczone przez Dawid_S Zobacz posta
    Prawie wszystko jest zrealizowane na wskaźnikach, więc całość charakteryzuje się dość dobrą wydajnością.
    Polemizowałbym
    Na pewno wskaźniki pomogły uniknąć bezsensownego kopiowania danych jak to czasem w gotowych klasach bibliotek się dzieje pod maską

    Ale generalnie wszystkie multimedialne obliczenia aż się proszą o SIMD - czy to przez C# API (System.Numerics czy Vector<T>: https://msdn.microsoft.com/en-us/lib...=vs.111).aspx), czy bezpośrednio natywny kod asm, zwłaszcza jak masz kodu niedużo i niezbyt skomplikowanego (wszelkie sploty dyskretne macierzy z obrazkiem czy zamiany palet to proste operacje mnożenia, dodawania, itp.), a jego wykonanie zajmuje najwięcej czasu Wielowątkowość na pewno też pomoże, ale nie każdy ma CPU 8C/16T

    I nie, nie jestem gołosłowny - użycie wskaźników w programie w C z optymalizacją /Ox powinno być szybkie, a co najwyżej było śmiesznie wolne
    Trochę pomogła myśląca optymalizacja - zamiast mnożenie * -1/0/1, to dodaję/odejmuję:
    Kliknij obrazek, aby uzyskać większą wersję

Nazwa:	wykres_c.png
Wyświetleń:	2895
Rozmiar:	72.3 KB
ID:	4340

    No ale z asemblerem i instrukcjami wektorowymi niestety się nie może równać
    Kliknij obrazek, aby uzyskać większą wersję

Nazwa:	wykres_avx2.png
Wyświetleń:	2857
Rozmiar:	81.8 KB
ID:	4342

    Nie zachęcam tutaj do pisania wszystkiego jako natywny kod czy asembler FTW!
    Po prostu warto go użyć jak masz jakieś multimedia, coś co łatwo zrównoleglić grubo- i drobnoziarniście, algorytm jest stosunkowo prosty i nie ma dużo kodu Im więcej warunków i zagnieżdżeń tym trudniej zapanować nad kodem, czasem warto sam algorytm przerobić albo użyć inny

    I nie mów znów, że komputery są szybkie, bla bla bla nie potrzeba optymalizować - jak widzisz 33MPx obrazek jeden rdzeń i7 w C mielił pół sekundy, a cała i7 8 rdzeniami ASM - 3,74ms - skromne 100x szybciej
    | Intel Core i7 2700K @ 4,5 GHz 1,35V | Gigabyte Z68X-UD3H LGA1155 | Kingston Savage 2x8 GB @ 2133 MHz CL9 1.65V |
    | 2x Samgate F3 500GB HD502HJ - Hybrid RAID 0+1 | Kingston HyperX 3K 240GB SATA III | Corsair VS650 |
    | Gigabyte GeForce GTX 970 4GB Gaming G1 @ 1550/7200 MHz | Xonar DX | BitFenix Shinobi | Dell P2414H 24" 1080p AH-IPS |


  5. #5
    Użytkownik Podkręca śrubokrętem Reputacja:   (0)
    Dołączył
    12.2018
    Posty
    2
    Och, to fajna sprawa! Programiści są fajni; D

Podobne wątki

  1. Problem z Radeonem 9100 - Falowanie obrazu!
    Przez tony w dziale Karty graficzne
    Odpowiedzi: 11
    Ostatni post / autor: 14-11-2006, 19:27

Uprawnienia umieszczania postów

  • Nie możesz zakładać nowych tematów
  • Nie możesz pisać wiadomości
  • Nie możesz dodawać załączników
  • Nie możesz edytować swoich postów
  •