Эффект ломографии в gdi+


Я хочу реализовать цветовые фильтры для изображений аналогично эффекту, описанному в этом учебнике

Я на самом деле не получаю цветные матрицы, как момент, и моя математика откровенно ужасна, так что все это немного выше моей головы.

Есть ли у кого-нибудь пример кода для выполнения части фильтрации? У меня уже есть написанный код, который добавит эффект виньетки.

Заранее большое спасибо.

Edit: код должен быть безопасным, как я хочу, чтобы иметь возможность используйте его в обработчиках изображений. Извините, если я не был достаточно ясен раньше.

1 3

1 ответ:

Взгляните на это.

Я думаю, там есть все, что вам нужно.

EDIT

        public static bool Invert(Bitmap b)
        {
            BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            int stride = bmData.Stride;
            System.IntPtr Scan0 = bmData.Scan0;

            // Create the Byte-Array
            int bytes = Math.Abs(bmData.Stride) * b.Height;
            byte[] p = new byte[bytes];

            // Copy RGB values into Byte-Array
            System.Runtime.InteropServices.Marshal.Copy(Scan0, p, 0, bytes);


            int nOffset = stride - b.Width * 3;
            int nWidth = b.Width * 3;

            int i = 0;

            for (int y = 0; y < b.Height; ++y)
            {
                for (int x = 0; x < nWidth; ++x)
                {
                        p[i] = (byte)(255 - p[i]);
                        ++i;
                }
                i += nOffset;
            }

            // Copy RGB back to image
            System.Runtime.InteropServices.Marshal.Copy(p, 0, Scan0, bytes);

            b.UnlockBits(bmData);

            return true;
        }

EDIT

Вот так:

public class Lomography
{

    public static Bitmap getImage(Bitmap bmp)
    {
        using (Graphics g = Graphics.FromImage(bmp))
        {
            using (Bitmap CurveLayer = (Bitmap)bmp.Clone())
            {
                Lomography.SCurve(CurveLayer);
                g.DrawImage(CurveLayer, new Rectangle(0, 0, bmp.Width, bmp.Height));
            }
        }

        using (Graphics g = Graphics.FromImage(bmp))
        {
            using (Bitmap ColorLayer = (Bitmap)bmp.Clone())
            {

                Lomography.Colorize(ColorLayer, -12, 25, -12, Lomography.ColorArea.Shadows);
                g.DrawImage(ColorLayer, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel);
            }
        }

        using (Graphics g = Graphics.FromImage(bmp))
        {
            using (Bitmap ColorLayer = (Bitmap)bmp.Clone())
            {

                Lomography.Colorize(ColorLayer, 12, 12, -25, Lomography.ColorArea.Hightlights);
                g.DrawImage(ColorLayer, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel);
            }
        }

        using (Graphics g = Graphics.FromImage(bmp))
        {
            RectangleF gradient = new RectangleF(-bmp.Width * 0.3f, -bmp.Height * 0.3f, bmp.Width * 1.6f, bmp.Height * 1.6f);

            GraphicsPath gp = new GraphicsPath();
            gp.AddEllipse(gradient);
            using (PathGradientBrush pgb = new PathGradientBrush(gp))
            {
                pgb.CenterColor = Color.Yellow;
                pgb.CenterPoint = new Point(bmp.Width / 2, bmp.Height / 2);
                ColorBlend cb = new ColorBlend(3);

                cb.Colors[0] = Color.Black;
                cb.Colors[1] = Color.Transparent;
                cb.Colors[2] = Color.Transparent;

                cb.Positions[0] = 0f;
                cb.Positions[1] = 0.55f;
                cb.Positions[2] = 1f;

                pgb.InterpolationColors = cb;
                g.FillEllipse(pgb, gradient);
            }
        }
        return bmp;
    }

    public enum ColorArea
    {
        Midtones,
        Shadows,
        Hightlights
    }

    public static bool Colorize(Bitmap b, int red, int green, int blue, ColorArea ca)
    {
        if (red < -255 || red > 255) return false;
        if (green < -255 || green > 255) return false;
        if (blue < -255 || blue > 255) return false;

        BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

        int bytes = Math.Abs(bmData.Stride) * b.Height;
        int stride = bmData.Stride;
        System.IntPtr Scan0 = bmData.Scan0;

        byte[] p = new byte[bytes];
        System.Runtime.InteropServices.Marshal.Copy(Scan0, p, 0, bytes);

        int i = 0;

        int nOffset = stride - b.Width * 3;
        int nPixel;

        for (int y = 0; y < b.Height; ++y)
        {
            for (int x = 0; x < b.Width; ++x)
            {
                int pdif = (p[i + 2] + p[i + 1] + p[i]) / 3;

                int newred = p[i + 2];
                int newgreen = p[i + 1];
                int newblue = p[i];


                if (ca == ColorArea.Shadows)
                {
                    float multi = (1 - newred / 255);
                    newred += (int)(red * multi);

                    multi = (1 - newgreen / 255);
                    newgreen += (int)(green * multi);

                    multi = (1 - newblue / 255);
                    newblue += (int)(blue * multi);
                }

                if (ca == ColorArea.Hightlights)
                {
                    float multi = (newred / 255);
                    newred += (int)(red * multi);

                    multi = (newgreen / 255);
                    newgreen += (int)(green * multi);

                    multi = (newblue / 255);
                    newblue += (int)(blue * multi);
                }

                if (ca == ColorArea.Midtones)
                {

                    float multi = 0;

                    if (newred > 127)
                        multi = 127f / newred;
                    else
                        multi = newred / 127f;
                    newred += (int)(red * multi);


                    if (newgreen > 127)
                        multi = 127f / newgreen;
                    else
                        multi = newgreen / 127f;
                    newgreen += (int)(green * multi);

                    if (newblue > 127)
                        multi = 127f / newblue;
                    else
                        multi = newblue / 127f;

                    newblue += (int)(blue * multi);
                }


                nPixel = newred;
                nPixel = Math.Max(nPixel, 0);
                p[i + 2] = (byte)Math.Min(255, nPixel);

                nPixel = newgreen;
                nPixel = Math.Max(nPixel, 0);
                p[i + 1] = (byte)Math.Min(255, nPixel);

                nPixel = newblue;
                nPixel = Math.Max(nPixel, 0);
                p[i + 0] = (byte)Math.Min(255, nPixel);

                i += 3;
            }
            i += nOffset;
        }



        System.Runtime.InteropServices.Marshal.Copy(p, 0, Scan0, bytes);
        b.UnlockBits(bmData);

        return true;
    }

    public static bool SCurve(Bitmap b)
    {

        BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

        int bytes = Math.Abs(bmData.Stride) * b.Height;
        int stride = bmData.Stride;
        System.IntPtr Scan0 = bmData.Scan0;

        byte[] p = new byte[bytes];
        System.Runtime.InteropServices.Marshal.Copy(Scan0, p, 0, bytes);

        int i = 0;

        int nOffset = stride - b.Width * 3;
        int nPixel;

        Point[] points = GetCoordinates();

        for (int y = 0; y < b.Height; ++y)
        {
            for (int x = 0; x < b.Width; ++x)
            {
                int hue = (p[i] == 255) ? 255 : -1;
                int hue1 = (p[i + 1] == 255) ? 255 : -1;
                int hue2 = (p[i + 2] == 255) ? 255 : -1;

                int p2 = p[i + 2];

                foreach (var point in points)
                {
                    if (hue2 == -1 && point.X >= p[i + 2])
                        hue2 = point.Y;

                    if (hue1 == -1 && point.X >= p[i + 1])
                        hue1 = point.Y;

                    if (hue == -1 && point.X >= p[i])
                        hue = point.Y;

                    if (hue != -1 && hue1 != -1 && hue2 != -1)
                        break;
                }

                nPixel = hue2;
                nPixel = Math.Max(nPixel, 0);
                p[i + 2] = (byte)Math.Min(255, nPixel);

                nPixel = hue1;
                nPixel = Math.Max(nPixel, 0);
                p[i + 1] = (byte)Math.Min(255, nPixel);

                nPixel = hue;
                nPixel = Math.Max(nPixel, 0);
                p[i + 0] = (byte)Math.Min(255, nPixel);

                i += 3;
            }
            i += nOffset;
        }



        System.Runtime.InteropServices.Marshal.Copy(p, 0, Scan0, bytes);
        b.UnlockBits(bmData);

        return true;
    }

    private static Point[] GetCoordinates()
    {
        List<Point> points = new List<Point>();
        int height = 255;
        int width = 255;

        double y0 = height;
        double y1 = height;
        double y2 = height * 0.75d;
        double y3 = height * 0.5d;

        double x0 = 0;
        double x1 = width * 0.25d;
        double x2 = width * 0.35d;
        double x3 = width * 0.5d;

        for (int i = 0; i < 1000; i++)
        {
            double t = i / 1000d;
            double xt = (-x0 + 3 * x1 - 3 * x2 + x3) * (t * t * t) + 3 * (x0 - 2 * x1 + x2) * (t * t) + 3 * (-x0 + x1) * t + x0;
            double yt = (-y0 + 3 * y1 - 3 * y2 + y3) * (t * t * t) + 3 * (y0 - 2 * y1 + y2) * (t * t) + 3 * (-y0 + y1) * t + y0;


            points.Add(new Point((int)xt, 255 - (int)yt));

        }

        y0 = height * 0.5d;
        y1 = height * 0.25d;
        y2 = 0;
        y3 = 0;

        x0 = width * 0.5d;
        x1 = width * 0.65d;
        x2 = width * 0.75d;
        x3 = width;

        for (int i = 0; i < 1000; i++)
        {
            double t = i / 1000d;

            double xt = (-x0 + 3 * x1 - 3 * x2 + x3) * (t * t * t) + 3 * (x0 - 2 * x1 + x2) * (t * t) + 3 * (-x0 + x1) * t + x0;
            double yt = (-y0 + 3 * y1 - 3 * y2 + y3) * (t * t * t) + 3 * (y0 - 2 * y1 + y2) * (t * t) + 3 * (-y0 + y1) * t + y0;

            points.Add(new Point((int)xt, 255 - (int)yt));
        }
        return points.ToArray();
    }

}
Поиграйте немного с цветами и кривой, чтобы получить оптимальный результат. Точки На кривой вычисляются с помощью 2 кубических кривых Безье в координатах GetCoordinates. первый прогон получает точки для кривой Нижнего Лева. второй прогон получает верхнее право точки.

Введите описание изображения здесь

EDIT

Вы также можете использовать этот Пример проекта, чтобы получить оптимальные цвета и кривую. (вы можете перетащить точки для кривой)

Введите описание изображения здесь

EDIT Чтобы ускорить процесс, загружайте координаты кривизны после изменения кривой, а не в функцию SCurve. Сохраните координаты кривой в массиве int (int[256]). Теперь вам не нужно петлять и искать точки, просто получите его из массива: hue = y = points[x]

    public bool SCurve(Bitmap b)
    {
        BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

        int bytes = Math.Abs(bmData.Stride) * b.Height;
        int stride = bmData.Stride;
        System.IntPtr Scan0 = bmData.Scan0;

        byte[] p = new byte[bytes];
        System.Runtime.InteropServices.Marshal.Copy(Scan0, p, 0, bytes);

        int i = 0;

        int nOffset = stride - b.Width * 3;
        int nPixel;

        int[] points = GetCoordinates();
        if (points == null)
            return false;

        for (int y = 0; y < b.Height; ++y)
        {
            for (int x = 0; x < b.Width; ++x)
            {
                if (state == State.Abort)
                {
                    b.UnlockBits(bmData);
                    return false;
                }

                int hue = points[p[i]];
                int hue1 = points[p[i + 1]];
                int hue2 = points[p[i + 2]];

                int p2 = p[i + 2];



                nPixel = hue2;
                nPixel = Math.Max(nPixel, 0);
                p[i + 2] = (byte)Math.Min(255, nPixel);

                nPixel = hue1;
                nPixel = Math.Max(nPixel, 0);
                p[i + 1] = (byte)Math.Min(255, nPixel);

                nPixel = hue;
                nPixel = Math.Max(nPixel, 0);
                p[i + 0] = (byte)Math.Min(255, nPixel);

                i += 3;

            }
            i += nOffset;
        }



        System.Runtime.InteropServices.Marshal.Copy(p, 0, Scan0, bytes);
        b.UnlockBits(bmData);
        return true;
    }

    private int[] GetCoordinates()
    {
        int[] points = new int[256];

        int height = 255;
        int width = 255;

        double y0 = height;
        double y1 = height * (curve1.p1.Y / (double)curve1.Height);
        double y2 = height * (curve1.p1.Y / (double)curve1.Height);
        double y3 = height * 0.5d;

        double x0 = 0;
        double x1 = width * (curve1.p1.X / (double)curve1.Width);
        double x2 = width * (curve1.p2.X / (double)curve1.Width);
        double x3 = width * 0.5d;

        for (int i = 0; i < 1000; i++)
        {
            double t = i / 1000d;
            double xt = (-x0 + 3 * x1 - 3 * x2 + x3) * (t * t * t) + 3 * (x0 - 2 * x1 + x2) * (t * t) + 3 * (-x0 + x1) * t + x0;
            double yt = (-y0 + 3 * y1 - 3 * y2 + y3) * (t * t * t) + 3 * (y0 - 2 * y1 + y2) * (t * t) + 3 * (-y0 + y1) * t + y0;


            points[(int)xt] = 255 - (int)yt;
        }

        y0 = height * 0.5d;
        y1 = height * (curve1.p3.Y / (double)curve1.Height); ;
        y2 = height * (curve1.p4.Y / curve1.Height);
        y3 = 0;

        x0 = width * 0.5d;
        x1 = width * (curve1.p3.X / (double)curve1.Width);
        x2 = width * (curve1.p4.X / (double)curve1.Width);
        x3 = width;

        for (int i = 0; i < 1000; i++)
        {
            double t = i / 1000d;

            double xt = (-x0 + 3 * x1 - 3 * x2 + x3) * (t * t * t) + 3 * (x0 - 2 * x1 + x2) * (t * t) + 3 * (-x0 + x1) * t + x0;
            double yt = (-y0 + 3 * y1 - 3 * y2 + y3) * (t * t * t) + 3 * (y0 - 2 * y1 + y2) * (t * t) + 3 * (-y0 + y1) * t + y0;

            points[(int)xt] = 255 - (int)yt;
        }

        points[255] = (int)(255 - y3);

        return points;
    }