summaryrefslogtreecommitdiff
path: root/ImageProcessing/Filters.cs
diff options
context:
space:
mode:
Diffstat (limited to 'ImageProcessing/Filters.cs')
-rw-r--r--ImageProcessing/Filters.cs604
1 files changed, 604 insertions, 0 deletions
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;
+ }
+ }
+
+}