Lomography effect in gdi+
I'm looking to implement colour filters to images in a similar way to the effect done in this tutorial
I do开发者_如何学Pythonn't really get colour matrices as the moment and my maths is quite frankly appalling so it's all a bit above my head.
Does anyone have any example code for how to do the filtering part? I already have code written that will add a vignette effect.
Many thanks in advance.
edit: The code needs to be safe as I want to be able to use it in imagehandlers. Sorry if I wasn't clear enough before.
Have a look at this.
I Think there is everything you need.
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
There you go:
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();
}
}
Play a little with the Colors and the curve to get the optimal result.
The Points in the curve are Calculated with 2 cubic bezier curves in GetCoordinates. the first run gets the points for the lowerleft curve. the second run gets the upperright points.
EDIT
You can also use this sample project to get the optimal colors and curve. (you can drag the points for the curve)
EDIT To speed things up load the CurveCoordinates once the Curve changed, not in the SCurve function. Save the Curve Coordinates in an int array (int[256]). Now you don't have to loop and search the points, just get it from the array: 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;
}
精彩评论