From 42dc1d36235292786322d28340a81c6cb3fd46c0 Mon Sep 17 00:00:00 2001 From: hurter Date: Wed, 31 Aug 2011 16:25:05 +0000 Subject: --- ImageProcessing/Filters.cs | 604 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 604 insertions(+) create mode 100644 ImageProcessing/Filters.cs (limited to 'ImageProcessing/Filters.cs') diff --git a/ImageProcessing/Filters.cs b/ImageProcessing/Filters.cs new file mode 100644 index 0000000..59c6cbd --- /dev/null +++ b/ImageProcessing/Filters.cs @@ -0,0 +1,604 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; +using System.Drawing.Imaging; + +namespace ImageProcessing +{ + public class BitmapFilter + { + static public float GetMedian( float[] array) + { + float[] tempArray = array; + int count = tempArray.Length; + + Array.Sort(tempArray); + + float medianValue = 0; + + if (count % 2 == 0) + { + // count is even, need to get the middle two elements, add them together, then divide by 2 + float middleElement1 = tempArray[(count / 2) - 1]; + float middleElement2 = tempArray[(count / 2)]; + medianValue = (middleElement1 + middleElement2) / 2; + } + else + { + // count is odd, simply get the middle element. + medianValue = tempArray[(count / 2)]; + } + + return medianValue; + } + static public float[] ComputeLocalMean(float[] gray, int width, int height) + { + int kernelWidth = 5; + + float[] tab = new float[width * height]; + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + tab[x + y * width] = ComputeMean(x, y, gray, width, height, kernelWidth); + } + } + return tab; + } + + private static float ComputeMean(int x, int y, float[] gray, int width, int height, int kernelWidth) + { + float mean = 0; + float count = 0; + for (int yy = Math.Max(0, y - kernelWidth); yy < Math.Min(y + kernelWidth, height); yy++) + { + for (int xx = Math.Max(0, x - kernelWidth); xx < Math.Min(x + kernelWidth, width); xx++) + { + mean += gray[xx + yy * width]; + count++; + } + } + mean /= count; + return mean; + } + + + static public float[] HorizontalThreshold(float[] gray, int width, int height) + { + float[] tab = new float[width * height]; + float[] line = new float[width]; + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + line[x] = gray[x + y * width]; + } + float med = GetMedian(line); + for (int x = 0; x < width; x++) + { + float diff = gray[x + y * width] - med; + if (diff < 0) diff = 0; + else + diff = 1; + tab[x + y * width] = diff; + } + } + + return tab; + } + + static public bool Invert(Bitmap b) + { + // GDI+ still lies to us - the return format is BGR, NOT RGB. + 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; + + unsafe + { + byte* p = (byte*)(void*)Scan0; + + int nOffset = stride - b.Width * 3; + int nWidth = b.Width * 3; + + for (int y = 0; y < b.Height; ++y) + { + for (int x = 0; x < nWidth; ++x) + { + p[0] = (byte)(255 - p[0]); + ++p; + } + p += nOffset; + } + } + + b.UnlockBits(bmData); + + return true; + } + + static public Bitmap GenerateBitmap(float[] gray, int width, int height) + { + Bitmap b = new Bitmap(width, height, PixelFormat.Format24bppRgb); + // GDI+ still lies to us - the return format is BGR, NOT RGB. + 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; + + unsafe + { + byte* p = (byte*)(void*)Scan0; + + int nOffset = stride - b.Width * 3; + + for (int y = 0; y < b.Height; ++y) + { + for (int x = 0; x < b.Width; ++x) + { + p[0] = p[1] = p[2] = (byte)(gray[y * b.Width + x]*255); + + p += 3; + + } + p += nOffset; + + } + } + + b.UnlockBits(bmData); + + return b; + } + + static public float GenericScaleF(float input, float i1, float o1, float i2, float o2) + { + if (i2 == i1) return ((o2 + o1) / 2.0f); + float a = (o2 - o1) / (i2 - i1); + float b = o1 - a * i1; + return (a * input + b); + } + + static public ColorRGB[] ColorRGBBitmap(Bitmap b) + { + ColorRGB[] tab = new ColorRGB[b.Width * b.Height]; + + Bitmap des = new Bitmap(b); + // GDI+ still lies to us - the return format is BGR, NOT RGB. + 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; + + unsafe + { + + byte* p = (byte*)(void*)Scan0; + + int nOffset = stride - b.Width * 3; + + for (int y = 0; y < b.Height; ++y) + { + for (int x = 0; x < b.Width; ++x) + { + tab[y * b.Width + x].R = p[2]; + tab[y * b.Width + x].G = p[1]; + tab[y * b.Width + x].B = p[0]; + + p += 3; + + } + p += nOffset; + + } + } + + b.UnlockBits(bmData); + + return tab; + } + + static public ColorHSL[] ColorLSHBitmap(Bitmap b) + { + ColorHSL[] tab = new ColorHSL[b.Width * b.Height]; + + Bitmap des = new Bitmap(b); + // GDI+ still lies to us - the return format is BGR, NOT RGB. + 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; + + unsafe + { + + byte* p = (byte*)(void*)Scan0; + + int nOffset = stride - b.Width * 3; + + byte red, green, blue; + + for (int y = 0; y < b.Height; ++y) + { + for (int x = 0; x < b.Width; ++x) + { + blue = p[0]; + green = p[1]; + red = p[2]; + + + tab[y * b.Width + x] = ColorTools.RGB2HSL( red, green, blue); + + p += 3; + + } + p += nOffset; + + } + } + + b.UnlockBits(bmData); + + return tab; + } + + static public Bitmap GenerateBitmapFromHSL(ColorHSL[] col, int width, int height) + { + Bitmap b = new Bitmap(width, height, PixelFormat.Format24bppRgb); + // GDI+ still lies to us - the return format is BGR, NOT RGB. + 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; + + unsafe + { + byte* p = (byte*)(void*)Scan0; + + int nOffset = stride - b.Width * 3; + + for (int y = 0; y < b.Height; ++y) + { + for (int x = 0; x < b.Width; ++x) + { + ColorHSL hsl = col[y * b.Width + x]; + Color c = ColorTools.HSL2RGB(hsl.H,hsl.S,hsl.L,1); + p[0] = c.B; + p[1] = c.G; + p[2] = c.R; + + p += 3; + + } + p += nOffset; + + } + } + + b.UnlockBits(bmData); + + return b; + } + + static public float[] GrayScaleFloat(Bitmap b) + { + float[] tab = new float[b.Width * b.Height]; + + Bitmap des = new Bitmap(b); + // GDI+ still lies to us - the return format is BGR, NOT RGB. + 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; + + unsafe + { + + byte* p = (byte*)(void*)Scan0; + + int nOffset = stride - b.Width * 3; + + byte red, green, blue; + + for (int y = 0; y < b.Height; ++y) + { + for (int x = 0; x < b.Width; ++x) + { + blue = p[0]; + green = p[1]; + red = p[2]; + + tab[y *b.Width + x] = (float)(.299 * red + .587 * green + .114 * blue)/255.0f; + + p += 3; + + } + p += nOffset; + + } + } + + b.UnlockBits(bmData); + + return tab; + } + + static public Bitmap GrayScaleBitmap(Bitmap b) + { + Bitmap des = new Bitmap(b); + // GDI+ still lies to us - the return format is BGR, NOT RGB. + BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); + BitmapData bmDataDest = des.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); + + int stride = bmData.Stride; + System.IntPtr Scan0 = bmData.Scan0; + System.IntPtr Scan0Dest = bmDataDest.Scan0; + + unsafe + { + byte* p = (byte*)(void*)Scan0; + byte* pDest = (byte*)(void*)Scan0Dest; + + int nOffset = stride - b.Width * 3; + + byte red, green, blue; + + for (int y = 0; y < b.Height; ++y) + { + for (int x = 0; x < b.Width; ++x) + { + blue = p[0]; + green = p[1]; + red = p[2]; + + pDest[0] = pDest[1] = pDest[2] = (byte)(.299 * red + .587 * green + .114 * blue); + + p += 3; + pDest += 3; + } + p += nOffset; + pDest += nOffset; + } + } + + b.UnlockBits(bmData); + des.UnlockBits(bmDataDest); + + return des; + } + + + static public float[] Normalize(float[] grayf, out float min, out float max, out float mean) + { + mean = 0; + min = float.MaxValue; + max = 0; + float[] res = new float[grayf.Length]; + + for (int i = 0; i < grayf.Length; i++) + { + if (grayf[i] > max) max = grayf[i]; + if (grayf[i] < min) min = grayf[i]; + mean += grayf[i]; + } + mean /= grayf.Length; + + for (int i = 0; i < grayf.Length; i++) + { + res[i] = GenericScaleF( grayf[i], min,0,max,1); + } + + return res; + } + + static public bool Brightness(Bitmap b, int nBrightness) + { + if (nBrightness < -255 || nBrightness > 255) + return false; + + // GDI+ still lies to us - the return format is BGR, NOT RGB. + 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; + + int nVal = 0; + + unsafe + { + byte* p = (byte*)(void*)Scan0; + + int nOffset = stride - b.Width * 3; + int nWidth = b.Width * 3; + + for (int y = 0; y < b.Height; ++y) + { + for (int x = 0; x < nWidth; ++x) + { + nVal = (int)(p[0] + nBrightness); + + if (nVal < 0) nVal = 0; + if (nVal > 255) nVal = 255; + + p[0] = (byte)nVal; + + ++p; + } + p += nOffset; + } + } + + b.UnlockBits(bmData); + + return true; + } + + static public bool Contrast(Bitmap b, sbyte nContrast) + { + if (nContrast < -100) return false; + if (nContrast > 100) return false; + + double pixel = 0, contrast = (100.0 + nContrast) / 100.0; + + contrast *= contrast; + + int red, green, blue; + + // GDI+ still lies to us - the return format is BGR, NOT RGB. + 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; + + unsafe + { + byte* p = (byte*)(void*)Scan0; + + int nOffset = stride - b.Width * 3; + + for (int y = 0; y < b.Height; ++y) + { + for (int x = 0; x < b.Width; ++x) + { + blue = p[0]; + green = p[1]; + red = p[2]; + + pixel = red / 255.0; + pixel -= 0.5; + pixel *= contrast; + pixel += 0.5; + pixel *= 255; + if (pixel < 0) pixel = 0; + if (pixel > 255) pixel = 255; + p[2] = (byte)pixel; + + pixel = green / 255.0; + pixel -= 0.5; + pixel *= contrast; + pixel += 0.5; + pixel *= 255; + if (pixel < 0) pixel = 0; + if (pixel > 255) pixel = 255; + p[1] = (byte)pixel; + + pixel = blue / 255.0; + pixel -= 0.5; + pixel *= contrast; + pixel += 0.5; + pixel *= 255; + if (pixel < 0) pixel = 0; + if (pixel > 255) pixel = 255; + p[0] = (byte)pixel; + + p += 3; + } + p += nOffset; + } + } + + b.UnlockBits(bmData); + + return true; + } + + static public bool Gamma(Bitmap b, double red, double green, double blue) + { + if (red < .2 || red > 5) return false; + if (green < .2 || green > 5) return false; + if (blue < .2 || blue > 5) return false; + + byte[] redGamma = new byte[256]; + byte[] greenGamma = new byte[256]; + byte[] blueGamma = new byte[256]; + + for (int i = 0; i < 256; ++i) + { + redGamma[i] = (byte)Math.Min(255, (int)((255.0 * Math.Pow(i / 255.0, 1.0 / red)) + 0.5)); + greenGamma[i] = (byte)Math.Min(255, (int)((255.0 * Math.Pow(i / 255.0, 1.0 / green)) + 0.5)); + blueGamma[i] = (byte)Math.Min(255, (int)((255.0 * Math.Pow(i / 255.0, 1.0 / blue)) + 0.5)); + } + + // GDI+ still lies to us - the return format is BGR, NOT RGB. + 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; + + unsafe + { + byte* p = (byte*)(void*)Scan0; + + int nOffset = stride - b.Width * 3; + + for (int y = 0; y < b.Height; ++y) + { + for (int x = 0; x < b.Width; ++x) + { + p[2] = redGamma[p[2]]; + p[1] = greenGamma[p[1]]; + p[0] = blueGamma[p[0]]; + + p += 3; + } + p += nOffset; + } + } + + b.UnlockBits(bmData); + + return true; + } + + static public bool Color(Bitmap b, int red, int green, int blue) + { + if (red < -255 || red > 255) return false; + if (green < -255 || green > 255) return false; + if (blue < -255 || blue > 255) return false; + + // GDI+ still lies to us - the return format is BGR, NOT RGB. + 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; + + unsafe + { + byte* p = (byte*)(void*)Scan0; + + int nOffset = stride - b.Width * 3; + int nPixel; + + for (int y = 0; y < b.Height; ++y) + { + for (int x = 0; x < b.Width; ++x) + { + nPixel = p[2] + red; + nPixel = Math.Max(nPixel, 0); + p[2] = (byte)Math.Min(255, nPixel); + + nPixel = p[1] + green; + nPixel = Math.Max(nPixel, 0); + p[1] = (byte)Math.Min(255, nPixel); + + nPixel = p[0] + blue; + nPixel = Math.Max(nPixel, 0); + p[0] = (byte)Math.Min(255, nPixel); + + p += 3; + } + p += nOffset; + } + } + + b.UnlockBits(bmData); + + return true; + } + } + +} -- cgit v1.1