Эффект ломографии в gdi+
Я хочу реализовать цветовые фильтры для изображений аналогично эффекту, описанному в этом учебнике
Я на самом деле не получаю цветные матрицы, как момент, и моя математика откровенно ужасна, так что все это немного выше моей головы.
Есть ли у кого-нибудь пример кода для выполнения части фильтрации? У меня уже есть написанный код, который добавит эффект виньетки.
Заранее большое спасибо.
Edit: код должен быть безопасным, как я хочу, чтобы иметь возможность используйте его в обработчиках изображений. Извините, если я не был достаточно ясен раньше.
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
Вот так:
Поиграйте немного с цветами и кривой, чтобы получить оптимальный результат. Точки На кривой вычисляются с помощью 2 кубических кривых Безье в координатах GetCoordinates. первый прогон получает точки для кривой Нижнего Лева. второй прогон получает верхнее право точки.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(); } }
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; }