/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> public unsafe void Apply(BitmapData bmData) { byte *p = (byte *)bmData.Scan0.ToPointer(); int width = bmData.Width, height = bmData.Height, stride = bmData.Stride; float z = 1 - s; Parallel.For(0, height, y => { YUV nYUV, iYUV; RGB rgb; int nR, nG, nB, iR, iG, iB; int x, ystride, k, luma; ystride = y * stride; for (x = 0; x < width; x++) { k = ystride + x * 4; iR = p[k + 2]; iG = p[k + 1]; iB = p[k]; luma = RGB.HDTV(iR, iG, iB); nYUV = YUV.FromRGB(luma, luma, luma); iYUV = YUV.FromRGB(color.R, color.G, color.B); rgb = AddColor(nYUV, iYUV).ToRGB; nR = rgb.Red; nG = rgb.Green; nB = rgb.Blue; p[k + 2] = Maths.Byte(nR * s + iR * z); p[k + 1] = Maths.Byte(nG * s + iG * z); p[k] = Maths.Byte(nB * s + iB * z); } } ); return; }
/// <summary> /// Process frame. /// </summary> /// <param name="bmData">Bitmap data</param> /// <param name="bmSrc">Bitmap data</param> private unsafe double ProcessFrameWithFilter(BitmapData bmData, BitmapData bmSrc) { byte *dst = (byte *)bmData.Scan0.ToPointer(); byte *src = (byte *)bmSrc.Scan0.ToPointer(); int width = bmData.Width, height = bmData.Height; double variance = 0.0; for (int x = 0; x < width; x++) { int y, k; for (y = 0; y < height; y++, dst += 4, src += 4) { for (k = 0; k < 3; k++) { var difference = Math.Abs(dst[k] - src[k]); dst[k] = Maths.Byte(difference); } var summary = RGB.Average(dst[2], dst[1], dst[0]); if (summary > Threshold) { variance++; } } } ; return(variance / (width * height)); }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> private unsafe void ApplyRGB(BitmapData bmData) { byte *p = (byte *)bmData.Scan0.ToPointer(); int width = bmData.Width, height = bmData.Height, stride = bmData.Stride; float length = values.Length - 1; Parallel.For(0, height, y => { int x, ystride, k; RGB rgb; ystride = y * stride; for (x = 0; x < width; x++) { k = ystride + x * 4; rgb = new RGB(p[k + 2], p[k + 1], p[k]); rgb.Red = Maths.Byte(values[rgb.Red] * length); rgb.Green = Maths.Byte(values[rgb.Green] * length); rgb.Blue = Maths.Byte(values[rgb.Blue] * length); p[k + 2] = rgb.Red; p[k + 1] = rgb.Green; p[k] = rgb.Blue; } } ); return; }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> public unsafe void Apply(BitmapData bmData) { int width = bmData.Width, height = bmData.Height, stride = bmData.Stride; int widthToProcess = Math.Min(width, texture.GetLength(1)); int heightToProcess = Math.Min(height, texture.GetLength(0)); float z = 1.0f - this.depth; byte *p = (byte *)bmData.Scan0.ToPointer(); Parallel.For(0, heightToProcess, y => { int x, ystride, k; byte red, green, blue; float t; ystride = y * stride; for (x = 0; x < widthToProcess; x++) { k = ystride + x * 4; red = p[k + 2]; green = p[k + 1]; blue = p[k]; t = texture[y, x]; p[k + 2] = Maths.Byte((z * red) + (this.depth * red) * t); p[k + 1] = Maths.Byte((z * green) + (this.depth * green) * t); p[k] = Maths.Byte((z * blue) + (this.depth * blue) * t); } } ); return; }
/// <summary> /// /// </summary> /// <param name="red"></param> /// <param name="green"></param> /// <param name="blue"></param> /// <param name="table"></param> /// <returns></returns> private Color GetColor(int red, int green, int blue, float[] table) { byte r = Maths.Byte(table[red]); byte g = Maths.Byte(table[green]); byte b = Maths.Byte(table[blue]); return(Color.FromArgb(r, g, b)); }
/// <summary> /// Converts an RGB structure to a color image. /// </summary> /// <param name="array">RGBA structure array</param> /// <param name="bmData">Bitmap data</param> public unsafe static void FromRGB(this float[][,] array, BitmapData bmData) { // matrices float[,] x = array[0]; float[,] y = array[1]; float[,] z = array[2]; // params int width = x.GetLength(1), height = x.GetLength(0); int stride = bmData.Stride; byte *p = (byte *)bmData.Scan0.ToPointer(); // alpha bool alpha = array.Length == 4; if (alpha) { float[,] a = array[3]; Parallel.For(0, height, j => { int i, k, jstride = j * stride; for (i = 0; i < width; i++) { // shift: k = jstride + i * 4; // recording model: p[k + 0] = Maths.Byte(x[j, i] * 255.0f); p[k + 1] = Maths.Byte(y[j, i] * 255.0f); p[k + 2] = Maths.Byte(z[j, i] * 255.0f); p[k + 3] = Maths.Byte(a[j, i] * 255.0f); } }); } else { Parallel.For(0, height, j => { int i, k, jstride = j * stride; for (i = 0; i < width; i++) { // shift: k = jstride + i * 4; // recording model: p[k + 0] = Maths.Byte(x[j, i] * 255.0f); p[k + 1] = Maths.Byte(y[j, i] * 255.0f); p[k + 2] = Maths.Byte(z[j, i] * 255.0f); p[k + 3] = (byte)255; } }); } return; }
/// <summary> /// Corrects color saturation. /// </summary> /// <param name="red">Red </param> /// <param name="green">Green</param> /// <param name="blue">Blue</param> /// <param name="s">Saturation</param> /// <returns>RGB structure</returns> public static sRGB Saturation(float red, float green, float blue, float s) { float max = Maths.Max(red, green, blue); // Result color: return(new sRGB( Maths.Byte(blue + (blue - max) * s), Maths.Byte(green + (green - max) * s), Maths.Byte(red + (red - max) * s))); }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> public unsafe void Apply(BitmapData bmData) { byte *p = (byte *)bmData.Scan0.ToPointer(); int y, x, width = bmData.Width, height = bmData.Height; for (y = 0; y < height; y++) { for (x = 0; x < width; x++, p += 4) { p[0] = p[1] = p[2] = Maths.Byte(cr * p[2] + cg * p[1] + cb * p[0]); } } return; }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> /// <param name="bmMax">Bitmap data</param> /// <param name="bmMin">Bitmap data</param> private unsafe void ApplyRGB(BitmapData bmData, BitmapData bmMax, BitmapData bmMin) { byte *p = (byte *)bmData.Scan0.ToPointer(); byte *pMax = (byte *)bmMax.Scan0.ToPointer(); byte *pMin = (byte *)bmMin.Scan0.ToPointer(); int width = bmData.Width, height = bmData.Height, stride = bmData.Stride; float required = 1.0f - this.contrast; Parallel.For(0, height, j => { int i, k, k1, k2, q, v, jstride = j * stride; float mag, max, min; float num1, num2, num3; for (i = 0; i < width; i++) { k = jstride + i * 4; k1 = k + 1; k2 = k + 2; // Local function: for (q = 0; q < 3; q++) { v = k + q; mag = p[v] / 255.0f; max = pMax[v] / 255.0f; min = pMin[v] / 255.0f; num1 = max - min; if (num1 < required) { num2 = min + (required - num1) * min / (num1 - 1f); min = Maths.Float(num2); max = Maths.Float(num2 + required); } num1 = max - min; num3 = mag - min; if (num1 > 0) { p[v] = Maths.Byte(255 * num3 / num1); } } // end local function. } } ); }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> public unsafe void Apply(BitmapData bmData) { byte *p = (byte *)bmData.Scan0.ToPointer(); int y, x, width = bmData.Width, height = bmData.Height; int stride = bmData.Stride; for (y = 0; y < height; y++) { for (x = 0; x < width; x++, p += 4) { p[2] = Maths.Byte(p[2] + generator.Next(-amount, amount)); p[1] = Maths.Byte(p[1] + generator.Next(-amount, amount)); p[0] = Maths.Byte(p[0] + generator.Next(-amount, amount)); } } }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> /// <param name="bmSrc">Bitmap data</param> public unsafe void Apply(BitmapData bmData, BitmapData bmSrc) { byte *p = (byte *)bmData.Scan0.ToPointer(); byte *pSrc = (byte *)bmSrc.Scan0.ToPointer(); int y, x, width = bmData.Width, height = bmData.Height; for (x = 0; x < width; x++) { for (y = 0; y < height; y++, p += 4, pSrc += 4) { p[2] = Maths.Byte(a * p[2] + b * pSrc[2]); p[1] = Maths.Byte(a * p[1] + b * pSrc[1]); p[0] = Maths.Byte(a * p[0] + b * pSrc[0]); } } return; }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> public unsafe void Apply(BitmapData bmData) { byte *p = (byte *)bmData.Scan0.ToPointer(); int width = bmData.Width, height = bmData.Height; int stride = bmData.Stride; // filter color float rf = color.R / 255.0f; float gf = color.G / 255.0f; float bf = color.B / 255.0f; // do job Parallel.For(0, height, y => { // bitmap color float lm; float rb; float gb; float bb; int x, ystride, k; ystride = y * stride; for (x = 0; x < width; x++) { k = ystride + x * 4; // luma lm = RGB.Average(p[k + 2], p[k + 1], p[k]) / 255.0f; // blending rb = this.blendf(lm, rf) * 255.0f; gb = this.blendf(lm, gf) * 255.0f; bb = this.blendf(lm, bf) * 255.0f; // recording p[k + 2] = Maths.Byte(rb * s + p[k + 2] * (1.0f - s)); p[k + 1] = Maths.Byte(gb * s + p[k + 1] * (1.0f - s)); p[k] = Maths.Byte(bb * s + p[k] * (1.0f - s)); } }); return; }
/// <summary> /// Converts a matrix of channel values to a monochrome Bitmap. /// </summary> /// <param name="m">Matrix</param> /// <param name="bmData">Bitmap data</param> public unsafe static void FromGrayscale(this float[,] m, BitmapData bmData) { int width = m.GetLength(1), height = m.GetLength(0); int stride = bmData.Stride; byte *p = (byte *)bmData.Scan0.ToPointer(); Parallel.For(0, height, j => { int i, k, jstride = j * stride; for (i = 0; i < width; i++) { k = jstride + i * 4; p[k + 2] = p[k + 1] = p[k] = Maths.Byte(m[j, i] * 255.0f); p[k + 3] = 255; } }); return; }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> public unsafe void Apply(BitmapData bmData) { int[] H = Statistics.Histogram(bmData); byte *p = (byte *)bmData.Scan0.ToPointer(); int y, x, width = bmData.Width, height = bmData.Height; float[] table = Statistics.Equalize(H); float length = table.Length - 1; for (y = 0; y < height; y++) { for (x = 0; x < width; x++, p += 4) { p[2] = Maths.Byte(table[p[2]] * length); p[1] = Maths.Byte(table[p[1]] * length); p[0] = Maths.Byte(table[p[0]] * length); } } return; }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> public unsafe void Apply(BitmapData bmData) { // rebuild? if (rebuild == true) { this.Rebuild(); this.rebuild = false; } byte *p = (byte *)bmData.Scan0.ToPointer(); int y, x, height = bmData.Height, width = bmData.Width; float length = values.Length - 1; for (y = 0; y < height; y++) { for (x = 0; x < width; x++, p += 4) { p[3] = Maths.Byte(values[p[3]] * length); } } return; }
/// <summary> /// Returns a matrix whose values belong to the interval [0, 255]. /// </summary> /// <param name="m">Matrix</param> /// <returns>Matrix</returns> public static float[][] ToByte(this float[][] m) { int r0 = m.GetLength(0), r1; float[][] H = new float[r0][]; float[] v; int i, j; for (i = 0; i < r0; i++) { v = m[i]; r1 = v.GetLength(0); for (j = 0; j < r1; j++) { H[i][j] = Maths.Byte(v[j]); } } return(H); }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> /// <param name="bmSrc">Bitmap data</param> private unsafe void ApplyRGB(BitmapData bmData, BitmapData bmSrc) { byte *p = (byte *)bmData.Scan0.ToPointer(), pSrc = (byte *)bmSrc.Scan0.ToPointer(); int width = bmData.Width, height = bmData.Height, stride = bmData.Stride; float length = values.GetLength(0) - 1; Parallel.For(0, height, j => { int i, k, k1, k2, jstride = j * stride; for (i = 0; i < width; i++) { k = jstride + i * 4; k1 = k + 1; k2 = k + 2; p[k2] = Maths.Byte(this.values[p[k2], pSrc[k2]] * length); p[k1] = Maths.Byte(this.values[p[k1], pSrc[k1]] * length); p[k] = Maths.Byte(this.values[p[k], pSrc[k]] * length); } } ); }
/// <summary> /// Converts ushort matrix into Bitmap. /// </summary> /// <param name="depth">Matrix</param> /// <returns>Bitmap</returns> public unsafe static Bitmap ToBitmap(this ushort[,] depth) { var width = depth.GetLength(1); var height = depth.GetLength(0); var rectangle = new Rectangle(0, 0, width, height); var bitmap = new Bitmap(width, height); var bmData = bitmap.LockBits(rectangle, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); var dst = (byte *)bmData.Scan0.ToPointer(); var stride = bmData.Stride; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { var k = x * 3 + y * stride; dst[k + 0] = dst[k + 1] = dst[k + 2] = Maths.Byte((float)depth[y, x] / byte.MaxValue); } } bitmap.Unlock(bmData); return(bitmap); }
/// <summary> /// Converts a matrix of channel values to a monochrome Bitmap. /// </summary> /// <param name="m">Matrix</param> /// <returns>Bitmap</returns> public unsafe static Bitmap FromGrayscale(this float[,] m) { int width = m.GetLength(1), height = m.GetLength(0); Bitmap bitmap = new Bitmap(width, height); BitmapData bmData = BitmapFormat.Lock32bpp(bitmap); int stride = bmData.Stride; byte * p = (byte *)bmData.Scan0.ToPointer(); Parallel.For(0, height, j => { int i, k, jstride = j * stride; for (i = 0; i < width; i++) { k = jstride + i * 4; p[k + 2] = p[k + 1] = p[k] = Maths.Byte(m[j, i] * 255.0f); p[k + 3] = 255; } }); BitmapFormat.Unlock(bitmap, bmData); return(bitmap); }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> /// <param name="bmSrc">Bitmap data</param> private unsafe void ApplyGrayscale(BitmapData bmData, BitmapData bmSrc) { byte *p = (byte *)bmData.Scan0.ToPointer(), pSrc = (byte *)bmSrc.Scan0.ToPointer(); int width = bmData.Width, height = bmData.Height, stride = bmData.Stride; float length = values.GetLength(0) - 1; Parallel.For(0, height, j => { int i, k, lumax, lumay, jstride = j * stride; for (i = 0; i < width; i++) { k = jstride + i * 4; lumax = RGB.Average(p[k + 2], p[k + 1], p[k]); lumay = RGB.Average(pSrc[k + 2], pSrc[k + 1], pSrc[k]); p[k + 2] = p[k + 1] = p[k] = Maths.Byte(this.values[lumax, lumay] * length); } }); return; }
/// <summary> /// Flat-field filter. /// </summary> /// <param name="bmData">Bitmap data</param> /// <param name="bmSrc">Bitmap data</param> private unsafe void flatfield(BitmapData bmData, BitmapData bmSrc) { byte *p = (byte *)bmData.Scan0.ToPointer(); byte *pSrc = (byte *)bmSrc.Scan0.ToPointer(); int width = bmData.Width, height = bmData.Height, stride = bmData.Stride; this.globalmeans(bmSrc); // calculating medians. Parallel.For(0, height, y => { int x, ystride, k; ystride = y * stride; for (x = 0; x < width; x++) { k = ystride + x * 4; if (pSrc[k + 2] != 0) { p[k + 2] = Maths.Byte(p[k + 2] * mR / pSrc[k + 2]); } if (pSrc[k + 1] != 0) { p[k + 1] = Maths.Byte(p[k + 1] * mR / pSrc[k + 1]); } if (pSrc[k] != 0) { p[k] = Maths.Byte(p[k] * mR / pSrc[k]); } } } ); return; }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> private unsafe void ApplyGrayscale(BitmapData bmData) { byte *p = (byte *)bmData.Scan0.ToPointer(); int width = bmData.Width, height = bmData.Height, stride = bmData.Stride; float length = values.Length - 1; Parallel.For(0, height, y => { int x, ystride, k; int luma; ystride = y * stride; for (x = 0; x < width; x++) { k = ystride + x * 4; luma = RGB.Average(p[k + 2], p[k + 1], p[k]); p[k + 2] = p[k + 1] = p[k] = Maths.Byte(values[luma] * length); } } ); return; }
/// <summary> /// Converts an YCbCr structure to a color image. /// </summary> /// <param name="array">YCbCr structure array</param> /// <returns>Bitmap</returns> public unsafe static Bitmap FromYCbCr(this float[][,] array) { // matrices float[,] x = array[0]; float[,] y = array[1]; float[,] z = array[2]; // params int width = x.GetLength(1), height = x.GetLength(0); Bitmap bitmap = new Bitmap(width, height); BitmapData bmData = BitmapFormat.Lock32bpp(bitmap); int stride = bmData.Stride; byte * p = (byte *)bmData.Scan0.ToPointer(); // alpha bool alpha = array.Length == 4; if (alpha) { float[,] a = array[3]; Parallel.For(0, height, j => { RGB rgb; int i, k, jstride = j * stride; for (i = 0; i < width; i++) { // shift: k = jstride + i * 4; rgb = new YCbCr(x[j, i], y[j, i], z[j, i]).ToRGB; // recording model: p[k + 0] = rgb.Blue; p[k + 1] = rgb.Green; p[k + 2] = rgb.Red; p[k + 3] = Maths.Byte(a[j, i] * 255.0f); } }); } else { Parallel.For(0, height, j => { RGB rgb; int i, k, jstride = j * stride; for (i = 0; i < width; i++) { // shift: k = jstride + i * 4; rgb = new YCbCr(x[j, i], y[j, i], z[j, i]).ToRGB; // recording model: p[k + 0] = rgb.Blue; p[k + 1] = rgb.Green; p[k + 2] = rgb.Red; p[k + 3] = (byte)255; } }); } BitmapFormat.Unlock(bitmap, bmData); return(bitmap); }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> /// <param name="bmSrc">Bitmap data</param> private unsafe void ApplyHorizontal(BitmapData bmData, BitmapData bmSrc) { #region Data int width = bmData.Width, height = bmData.Height, stride = bmData.Stride; byte *src = (byte *)bmSrc.Scan0.ToPointer(); byte *dst = (byte *)bmData.Scan0.ToPointer(); int h = rw >= width ? width - 1 : rw; int v = h >> 1; int dl = width - v; #endregion Parallel.For(0, height, y => { float r = 0; float g = 0; float b = 0; int p, q, w, x; int yy = y * stride; for (p = yy, x = 0; x < h; x++, p += 4) { r += src[p + 2]; g += src[p + 1]; b += src[p + 0]; } for (p = yy, x = 0; x < v; x++, p += 4) { dst[p + 2] = Maths.Byte(r / h); dst[p + 1] = Maths.Byte(g / h); dst[p + 0] = Maths.Byte(b / h); } for ( x = v, p = yy + (x - v) * 4, q = yy + (x + 0) * 4, w = yy + (x + v) * 4; x < dl; x++, p += 4, q += 4, w += 4) { r = r - src[p + 2] + src[w + 2]; g = g - src[p + 1] + src[w + 1]; b = b - src[p + 0] + src[w + 0]; dst[q + 2] = Maths.Byte(r / h); dst[q + 1] = Maths.Byte(g / h); dst[q + 0] = Maths.Byte(b / h); } for ( x = dl, p = (x - v) * 4 + yy, q = (x + 0) * 4 + yy; x < width; x++, p += 4, q += 4) { r = r - src[p + 2] + src[q + 2]; g = g - src[p + 1] + src[q + 1]; b = b - src[p + 0] + src[q + 0]; dst[q + 2] = Maths.Byte(r / h); dst[q + 1] = Maths.Byte(g / h); dst[q + 0] = Maths.Byte(b / h); } }); }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> /// <param name="bmSrc">Bitmap data</param> private unsafe void ApplyVertical(BitmapData bmData, BitmapData bmSrc) { #region Data int width = bmData.Width, height = bmData.Height, stride = bmData.Stride; byte *src = (byte *)bmSrc.Scan0.ToPointer(); byte *dst = (byte *)bmData.Scan0.ToPointer(); int h = rh >= height ? height - 1 : rh; int v = h >> 1; int dl = height - v; #endregion Parallel.For(0, width, x => { float r = 0; float g = 0; float b = 0; int p, w, q, y; int xx = x * 4; for (p = xx, y = 0; y < h; y++, p += stride) { r += src[p + 2]; g += src[p + 1]; b += src[p + 0]; } for (p = xx, y = 0; y < v; y++, p += stride) { dst[p + 2] = Maths.Byte(r / h); dst[p + 1] = Maths.Byte(g / h); dst[p + 0] = Maths.Byte(b / h); } for ( y = v, p = xx + (y - v) * stride, q = xx + (y + 0) * stride, w = xx + (y + v) * stride; y < dl; y++, p += stride, q += stride, w += stride) { r = r - src[p + 2] + src[w + 2]; g = g - src[p + 1] + src[w + 1]; b = b - src[p + 0] + dst[w + 0]; dst[q + 2] = Maths.Byte(r / h); dst[q + 1] = Maths.Byte(g / h); dst[q + 0] = Maths.Byte(b / h); } for ( y = dl, p = xx + (y - v) * stride, q = xx + (y + 0) * stride; y < height; y++, p += stride, q += stride) { r = r - src[p + 2] + src[q + 2]; g = g - src[p + 1] + src[q + 1]; b = b - src[p + 0] + src[q + 0]; dst[q + 2] = Maths.Byte(r / h); dst[q + 1] = Maths.Byte(g / h); dst[q + 0] = Maths.Byte(b / h); } }); return; }
/// <summary> /// /// </summary> /// <param name="rError"></param> /// <param name="gError"></param> /// <param name="bError"></param> /// <param name="ptr"></param> protected unsafe void Diffuse(int rError, int gError, int bError, byte *ptr) { float edR; // error diffusion float edG; // error diffusion float edB; // error diffusion // do error diffusion to right-standing neighbors float[] row = matrix[0]; int jI, jP, i, k, jC, n; int length = matrix.Length; for (jI = 1, jP = 4, jC = 0, k = row.Length; jC < k; jI++, jC++, jP += 4) { if (x + jI >= width) { break; } edR = ptr[jP + 2] + (rError * row[jC]) / summary; ptr[jP + 2] = Maths.Byte(edR); edG = ptr[jP + 1] + (gError * row[jC]) / summary; ptr[jP + 1] = Maths.Byte(edG); edB = ptr[jP + 0] + (bError * row[jC]) / summary; ptr[jP + 0] = Maths.Byte(edB); } // do error diffusion to bottom neigbors for (i = 1, n = length; i < n; i++) { if (y + i >= height) { break; } // move pointer to next image line ptr += stride; // get coefficients of the row row = matrix[i]; // process the row for (jC = 0, k = row.Length, jI = -(k >> 1), jP = -(k >> 1) * 4; jC < k; jI++, jC++, jP += 4) { if (x + jI >= width) { break; } if (x + jI < 0) { continue; } edR = ptr[jP + 2] + (rError * row[jC]) / summary; ptr[jP + 2] = Maths.Byte(edR); edG = ptr[jP + 1] + (gError * row[jC]) / summary; ptr[jP + 1] = Maths.Byte(edG); edB = ptr[jP + 0] + (bError * row[jC]) / summary; ptr[jP + 0] = Maths.Byte(edB); } } }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> public unsafe void Apply(BitmapData bmData) { int width = bmData.Width, height = bmData.Height, stride = bmData.Stride; byte *p = (byte *)bmData.Scan0.ToPointer(); // channel subtraction if (Channel == RGBA.Red) { Parallel.For(0, height, y => { int x, ystride, k; ystride = y * stride; for (x = 0; x < width; x++) { k = ystride + x * 4; var luma = RGB.PAL(p[k + 2], p[k + 1], p[k]); var diff = p[k + 2] - luma; p[k] = p[k + 1] = p[k + 2] = Maths.Byte(127.5f + diff); } }); } else if (Channel == RGBA.Green) { Parallel.For(0, height, y => { int x, ystride, k; ystride = y * stride; for (x = 0; x < width; x++) { k = ystride + x * 4; var luma = RGB.PAL(p[k + 2], p[k + 1], p[k]); var diff = p[k + 1] - luma; p[k] = p[k + 1] = p[k + 2] = Maths.Byte(127.5f + diff); } }); } else { Parallel.For(0, height, y => { int x, ystride, k; ystride = y * stride; for (x = 0; x < width; x++) { k = ystride + x * 4; var luma = RGB.PAL(p[k + 2], p[k + 1], p[k]); var diff = p[k] - luma; p[k] = p[k + 1] = p[k + 2] = Maths.Byte(127.5f + diff); } }); } // histogram processing int[] hist = Statistics.Histogram(bmData); int n = hist.Length; int z = n / 2; int[] lef = new int[z]; int[] rig = new int[z]; for (int i = 0; i < z; i++) { lef[i] = hist[i]; rig[i] = hist[i + z]; } _ = Statistics.Max(lef, out int index1); _ = Statistics.Max(rig, out int index2); index2 += z; int count = index2 - index1; int[] center = new int[count]; for (int i = 0; i < count; i++) { center[i] = hist[i + index1]; } _ = Statistics.Min(center, out int threshold); threshold += index1; // creating mask Parallel.For(0, height, y => { int x, ystride, k; ystride = y * stride; for (x = 0; x < width; x++) { k = ystride + x * 4; p[k] = p[k + 1] = p[k + 2] = (p[k] >= threshold) ? (byte)0 : (byte)255; } }); return; }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> /// <param name="bmSrc">Bitmap data</param> public unsafe void Apply(BitmapData bmData, BitmapData bmSrc) { #region Data if (this.l0 != this.l1 && this.bilateral == true) { throw new Exception("Matrix must be squared"); } int width = bmData.Width, height = bmData.Height, stride = bmData.Stride; byte *src = (byte *)bmSrc.Scan0.ToPointer(); byte *dst = (byte *)bmData.Scan0.ToPointer(); #endregion if (!this.bilateral) { Parallel.For(0, height, y => { float red, green, blue, div, k; int x, i, j, ir, jr, yr, xr; int ystride, v; byte *p; yr = y - radius0; ystride = y * stride; for (x = 0; x < width; x++) { xr = x - radius1; v = ystride + x * 4; red = green = blue = div = 0; #region Convolution filtering for (i = 0; i < l0; i++) { ir = yr + i; if (ir < 0) { continue; } if (ir >= height) { break; } for (j = 0; j < l1; j++) { jr = xr + j; if (jr < 0) { continue; } if (jr >= width) { break; } k = kernel[i][j]; if (k != 0) { p = &src[ir * stride + jr * 4]; div += k; red += k * p[2]; green += k * p[1]; blue += k * p[0]; } } } #endregion #region Divider and offset if (div != 0) { red /= div; green /= div; blue /= div; } if (offset != 0) { red += offset; green += offset; blue += offset; } #endregion #region Recording pixel dst[v + 2] = Maths.Byte(red); dst[v + 1] = Maths.Byte(green); dst[v] = Maths.Byte(blue); #endregion } }); } else { Parallel.For(0, height, y => { float red1, green1, blue1, div1, k1; float red2, green2, blue2, div2, k2; int x, i, j, ir, jr, yr, xr; int ystride, v; byte *p; yr = y - radius0; ystride = y * stride; for (x = 0; x < width; x++) { xr = x - radius1; v = ystride + x * 4; red1 = green1 = blue1 = div1 = 0; red2 = green2 = blue2 = div2 = 0; #region Convolution filtering for (i = 0; i < l0; i++) { ir = yr + i; if (ir < 0) { continue; } if (ir >= height) { break; } for (j = 0; j < l1; j++) { jr = xr + j; if (jr < 0) { continue; } if (jr >= width) { break; } k1 = kernel[i][j]; k2 = kernel[j][i]; p = &src[ir * stride + jr * 4]; div1 += k1; div2 += k2; red1 += k1 * p[2]; green1 += k1 * p[1]; blue1 += k1 * p[0]; red2 += k2 * p[2]; green2 += k2 * p[1]; blue2 += k2 * p[0]; } } #endregion #region Divider and offset if (div1 != 0) { red1 /= div1; green1 /= div1; blue1 /= div1; } if (div2 != 0) { red2 /= div2; green2 /= div2; blue2 /= div2; } if (offset != 0) { red1 += offset; green1 += offset; blue1 += offset; red2 += offset; green2 += offset; blue2 += offset; } #endregion #region Recording pixel dst[v + 2] = Maths.Byte(G(red1, red2)); dst[v + 1] = Maths.Byte(G(green1, green2)); dst[v] = Maths.Byte(G(blue1, blue2)); #endregion } }); } return; }
/// <summary> /// Apply filter. /// </summary> /// <param name="bmData">Bitmap data</param> /// <param name="bmSrc">Bitmap data</param> public unsafe void Apply(BitmapData bmData, BitmapData bmSrc) { #region Data int width = bmData.Width, height = bmData.Height, stride = bmData.Stride; byte *src = (byte *)bmSrc.Scan0.ToPointer(); byte *dst = (byte *)bmData.Scan0.ToPointer(); #endregion Parallel.For(0, height, y => { int[] H = new int[256]; int[] cdf = new int[256]; int n = l0 * l1; int brightness; float dn = 255.0f / n; int x, i, j, ir, jr, yr, xr, irstride; int ystride, v; byte *p; yr = y - rw; ystride = y * stride; for (x = 0; x < width; x++) { xr = x - rh; v = ystride + x * 4; #region Convolution filtering for (i = 0; i < l0; i++) { ir = yr + i; if (ir < 0) { continue; } if (ir >= height) { break; } irstride = ir * stride; for (j = 0; j < l1; j++) { jr = xr + j; if (jr < 0) { continue; } if (jr >= width) { break; } p = &src[irstride + jr * 4]; brightness = (p[2] + p[1] + p[0]) / 3; H[brightness]++; } } #endregion #region Density function cdf[0] = H[0]; for (i = 1; i < 256; i++) { cdf[i] = H[i] + cdf[i - 1]; } #endregion #region Recording pixel dst[v + 2] = Maths.Byte(cdf[src[v + 2]] * dn); dst[v + 1] = Maths.Byte(cdf[src[v + 1]] * dn); dst[v] = Maths.Byte(cdf[src[v]] * dn); #endregion #region Clear data Array.Clear(H, 0, 256); Array.Clear(cdf, 0, 256); #endregion } } ); return; }
/// <summary> /// Local laplacian filter. /// </summary> /// <param name="input">Input data</param> /// <param name="radius">Radius</param> /// <param name="sigma">Sigma</param> /// <param name="factor">Factor</param> /// <param name="n">Number of steps</param> /// <param name="levels">Levels</param> /// <returns>Output data</returns> internal static void llfilter(float[] input, int radius, float sigma, float factor, int n, int levels) { // exception if (factor == 0) { return; } // data int height = input.GetLength(0); int y, level, length = 256; float step = 1.0f / n; float min = 0.0f, max = 1.0f; // pyramids int n_levels = (int)Math.Min((Math.Log(height) / Math.Log(2)), levels); LaplacianPyramidTransform lpt = new LaplacianPyramidTransform(n_levels, radius); GaussianPyramidTransform gpt = new GaussianPyramidTransform(n_levels, radius); float[][] input_gaussian_pyr = gpt.Forward(input); float[][] output_laplace_pyr = lpt.Forward(input_gaussian_pyr); float[][] temp_laplace_pyr; float[] I_temp, I_gaus, I_outp; float[] T; // do job for (float i = min; i <= max; i += step) { height = input.GetLength(0); I_temp = new float[height]; T = Rem(sigma, factor, i, length); // remapping function for (y = 0; y < height; y++) { I_temp[y] = T[Maths.Byte(input[y] * (length - 1))]; } temp_laplace_pyr = lpt.Forward(I_temp); T = Rec(i, step, length); // pyramid reconstruction for (level = 0; level < n_levels; level++) { I_gaus = input_gaussian_pyr[level]; I_temp = temp_laplace_pyr[level]; I_outp = output_laplace_pyr[level]; height = I_outp.GetLength(0); for (y = 0; y < height; y++) { I_outp[y] += T[Maths.Byte(I_gaus[y] * (length - 1))] * I_temp[y]; } output_laplace_pyr[level] = I_outp; } } // backward transform I_outp = lpt.Backward(output_laplace_pyr); height = input.GetLength(0); for (y = 0; y < height; y++) { input[y] = I_outp[y]; } return; }