/// <summary> /// Generates the quantized result. /// </summary> /// <param name="image">The image.</param> /// <param name="colorCount">The color count.</param> /// <param name="width">Width of image</param> /// <param name="height">Height of image</param> /// <param name="destPixels">Pixel values are written here. Must provide width*height memory.</param> /// <param name="padMultiple4">True to write zero padding to make row bytes multiple of 4</param> /// <returns>Receives colors</returns> private unsafe uint[] GenerateResult(uint *image, int colorCount, int width, int height, byte *destPixels, bool padMultiple4) { uint[] palette = new uint[colorCount]; // rows must be a multiple of 4, hence padding up to 3 bytes for 8-bit indexed pixels int widthMod4 = width % 4; int widthZeros = widthMod4 != 0 ? 4 - widthMod4 : 0; for (int k = 0; k < colorCount; k++) { this.Mark(ref this.cube[k], (byte)k); float weight = WuAlphaColorQuantizer.Volume(ref this.cube[k], this.vwt); if (weight != 0) { uint a = (byte)(WuAlphaColorQuantizer.Volume(ref this.cube[k], this.vma) / weight); uint r = (byte)(WuAlphaColorQuantizer.Volume(ref this.cube[k], this.vmr) / weight); uint g = (byte)(WuAlphaColorQuantizer.Volume(ref this.cube[k], this.vmg) / weight); uint b = (byte)(WuAlphaColorQuantizer.Volume(ref this.cube[k], this.vmb) / weight); palette[k] = (a << 24) | (r << 16) | (g << 8) | b; } else { palette[k] = 0xFF000000; } } for (int ri = 0; ri < height; ri++) { for (int ci = 0; ci < width; ci++) { uint pix = image[0]; uint a = ((pix & 0xFF000000) >> 24) >> (8 - WuAlphaColorQuantizer.IndexAlphaBits); uint r = ((pix & 0x00FF0000) >> 16) >> (8 - WuAlphaColorQuantizer.IndexBits); uint g = ((pix & 0x0000FF00) >> 8) >> (8 - WuAlphaColorQuantizer.IndexBits); uint b = (pix & 0x000000FF) >> (8 - WuAlphaColorQuantizer.IndexBits); int ind = WuAlphaColorQuantizer.GetIndex((int)r + 1, (int)g + 1, (int)b + 1, (int)a + 1); destPixels[0] = this.tag[ind]; destPixels++; image++; } // write additional zero bytes if requested if (padMultiple4) { for (int c = 0; c < widthZeros; c++) { destPixels[0] = 0x00; destPixels++; } } } return(palette); }
/// <summary> /// Computes the weighted variance of a box. /// </summary> /// <param name="c">The cube.</param> /// <returns>The result.</returns> private float Variance(ref Box c) { float dr = WuAlphaColorQuantizer.Volume(ref c, this.vmr); float dg = WuAlphaColorQuantizer.Volume(ref c, this.vmg); float db = WuAlphaColorQuantizer.Volume(ref c, this.vmb); float da = WuAlphaColorQuantizer.Volume(ref c, this.vma); float xx = this.m2[WuAlphaColorQuantizer.GetIndex(c.R1, c.G1, c.B1, c.A1)] - this.m2[WuAlphaColorQuantizer.GetIndex(c.R1, c.G1, c.B1, c.A0)] - this.m2[WuAlphaColorQuantizer.GetIndex(c.R1, c.G1, c.B0, c.A1)] + this.m2[WuAlphaColorQuantizer.GetIndex(c.R1, c.G1, c.B0, c.A0)] - this.m2[WuAlphaColorQuantizer.GetIndex(c.R1, c.G0, c.B1, c.A1)] + this.m2[WuAlphaColorQuantizer.GetIndex(c.R1, c.G0, c.B1, c.A0)] + this.m2[WuAlphaColorQuantizer.GetIndex(c.R1, c.G0, c.B0, c.A1)] - this.m2[WuAlphaColorQuantizer.GetIndex(c.R1, c.G0, c.B0, c.A0)] - this.m2[WuAlphaColorQuantizer.GetIndex(c.R0, c.G1, c.B1, c.A1)] + this.m2[WuAlphaColorQuantizer.GetIndex(c.R0, c.G1, c.B1, c.A0)] + this.m2[WuAlphaColorQuantizer.GetIndex(c.R0, c.G1, c.B0, c.A1)] - this.m2[WuAlphaColorQuantizer.GetIndex(c.R0, c.G1, c.B0, c.A0)] + this.m2[WuAlphaColorQuantizer.GetIndex(c.R0, c.G0, c.B1, c.A1)] - this.m2[WuAlphaColorQuantizer.GetIndex(c.R0, c.G0, c.B1, c.A0)] - this.m2[WuAlphaColorQuantizer.GetIndex(c.R0, c.G0, c.B0, c.A1)] + this.m2[WuAlphaColorQuantizer.GetIndex(c.R0, c.G0, c.B0, c.A0)]; return(xx - (((dr * dr) + (dg * dg) + (db * db) + (da * da)) / WuAlphaColorQuantizer.Volume(ref c, this.vwt))); }
/// <summary> /// Builds a 3-D color histogram of <c>counts, r/g/b, c^2</c>. /// </summary> /// <param name="image">The image.</param> /// <param name="width">Width of image</param> /// <param name="height">Height of image</param> private unsafe void Build3DHistogram(uint *image, int width, int height) { int pixels = width * height; for (int i = 0; i < pixels; i++) { uint pix = image[i]; int a = (int)((pix & 0xFF000000) >> 24); int r = (int)((pix & 0x00FF0000) >> 16); int g = (int)((pix & 0x0000FF00) >> 8); int b = (int)(pix & 0x000000FF); int inr = r >> (8 - WuAlphaColorQuantizer.IndexBits); int ing = g >> (8 - WuAlphaColorQuantizer.IndexBits); int inb = b >> (8 - WuAlphaColorQuantizer.IndexBits); int ina = a >> (8 - WuAlphaColorQuantizer.IndexAlphaBits); int ind = WuAlphaColorQuantizer.GetIndex((int)inr + 1, (int)ing + 1, (int)inb + 1, (int)ina + 1); this.vwt[ind]++; this.vmr[ind] += r; this.vmg[ind] += g; this.vmb[ind] += b; this.vma[ind] += a; this.m2[ind] += (r * r) + (g * g) + (b * b) + (a * a); } }
/// <summary> /// Computes the weighted variance of a box. /// </summary> /// <param name="cube">The cube.</param> /// <returns>The result.</returns> private double Variance(Box cube) { double dr = WuAlphaColorQuantizer.Volume(cube, this.vmr); double dg = WuAlphaColorQuantizer.Volume(cube, this.vmg); double db = WuAlphaColorQuantizer.Volume(cube, this.vmb); double da = WuAlphaColorQuantizer.Volume(cube, this.vma); double xx = this.m2[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B1, cube.A1)] - this.m2[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B1, cube.A0)] - this.m2[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B0, cube.A1)] + this.m2[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B0, cube.A0)] - this.m2[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B1, cube.A1)] + this.m2[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B1, cube.A0)] + this.m2[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B0, cube.A1)] - this.m2[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B0, cube.A0)] - this.m2[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B1, cube.A1)] + this.m2[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B1, cube.A0)] + this.m2[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B0, cube.A1)] - this.m2[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B0, cube.A0)] + this.m2[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B1, cube.A1)] - this.m2[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B1, cube.A0)] - this.m2[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0, cube.A1)] + this.m2[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0, cube.A0)]; return(xx - (((dr * dr) + (dg * dg) + (db * db) + (da * da)) / WuAlphaColorQuantizer.Volume(cube, this.vwt))); }
private static int Top(ref Box cube, int direction, int position, int[] moment) { switch (direction) { // Red case 3: return(moment[WuAlphaColorQuantizer.GetIndex(position, cube.G1, cube.B1, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(position, cube.G1, cube.B1, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(position, cube.G1, cube.B0, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(position, cube.G1, cube.B0, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(position, cube.G0, cube.B1, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(position, cube.G0, cube.B1, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(position, cube.G0, cube.B0, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(position, cube.G0, cube.B0, cube.A0)]); // Green case 2: return(moment[WuAlphaColorQuantizer.GetIndex(cube.R1, position, cube.B1, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, position, cube.B1, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, position, cube.B0, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R1, position, cube.B0, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, position, cube.B1, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, position, cube.B1, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, position, cube.B0, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, position, cube.B0, cube.A0)]); // Blue case 1: return(moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, position, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, position, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, position, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, position, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, position, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, position, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, position, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, position, cube.A0)]); // Alpha case 0: return(moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B1, position)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B0, position)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B1, position)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B0, position)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B1, position)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B0, position)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B1, position)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0, position)]); default: throw new ArgumentOutOfRangeException("direction"); } }
/// <summary> /// Computes part of Volume(cube, moment) that doesn't depend on r1, g1, or b1 (depending on direction). /// </summary> /// <param name="cube">The cube.</param> /// <param name="direction">The direction.</param> /// <param name="moment">The moment.</param> /// <returns>The result.</returns> private static long Bottom(Box cube, int direction, long[] moment) { switch (direction) { // Red case 3: return(-moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B1, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B1, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B0, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B0, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B1, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B1, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0, cube.A0)]); // Green case 2: return(-moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B1, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B1, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B0, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B0, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B1, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B1, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0, cube.A0)]); // Blue case 1: return(-moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B0, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B0, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B0, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B0, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B0, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B0, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0, cube.A0)]); // Alpha case 0: return(-moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B1, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B0, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B1, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B0, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B1, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B0, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B1, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0, cube.A0)]); default: throw new ArgumentOutOfRangeException(nameof(direction)); } }
/// <summary> /// Marks a color space tag. /// </summary> /// <param name="c">The cube.</param> /// <param name="label">A label.</param> private void Mark(ref Box c, byte label) { for (int r = c.R0 + 1; r <= c.R1; r++) { for (int g = c.G0 + 1; g <= c.G1; g++) { for (int b = c.B0 + 1; b <= c.B1; b++) { for (int a = c.A0 + 1; a <= c.A1; a++) { this.tag[WuAlphaColorQuantizer.GetIndex(r, g, b, a)] = label; } } } } }
private static float Volume(ref Box cube, int[] moment) { return((float)(moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B1, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B1, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B0, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B0, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B1, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B1, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B0, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B0, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B1, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B1, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B0, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B0, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B1, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B1, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0, cube.A0)])); }
/// <summary> /// Computes sum over a box of any given statistic. /// </summary> /// <param name="cube">The cube.</param> /// <param name="moment">The moment.</param> /// <returns>The result.</returns> private static double Volume(Box cube, long[] moment) { return(moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B1, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B1, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B0, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B0, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B1, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B1, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B0, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B0, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B1, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B1, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B0, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B0, cube.A0)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B1, cube.A1)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B1, cube.A0)] - moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0, cube.A1)] + moment[WuAlphaColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0, cube.A0)]); }
/// <summary> /// Generates the quantized result. /// </summary> /// <param name="image">The image.</param> /// <param name="colorCount">The color count.</param> /// <returns>The result.</returns> private ColorQuantizerResult GenerateResult(byte[] image, int colorCount) { var quantizedImage = new ColorQuantizerResult(image.Length / 4, colorCount); for (int k = 0; k < colorCount; k++) { this.Mark(ref this.cube[k], (byte)k); float weight = WuAlphaColorQuantizer.Volume(ref this.cube[k], this.vwt); if (weight != 0) { quantizedImage.Palette[(k * 4) + 3] = (byte)(WuAlphaColorQuantizer.Volume(ref this.cube[k], this.vma) / weight); quantizedImage.Palette[(k * 4) + 2] = (byte)(WuAlphaColorQuantizer.Volume(ref this.cube[k], this.vmr) / weight); quantizedImage.Palette[(k * 4) + 1] = (byte)(WuAlphaColorQuantizer.Volume(ref this.cube[k], this.vmg) / weight); quantizedImage.Palette[k * 4] = (byte)(WuAlphaColorQuantizer.Volume(ref this.cube[k], this.vmb) / weight); } else { quantizedImage.Palette[(k * 4) + 3] = 0xff; quantizedImage.Palette[(k * 4) + 2] = 0; quantizedImage.Palette[(k * 4) + 1] = 0; quantizedImage.Palette[k * 4] = 0; } } for (int i = 0; i < image.Length / 4; i++) { int a = image[(i * 4) + 3] >> (8 - WuAlphaColorQuantizer.IndexAlphaBits); int r = image[(i * 4) + 2] >> (8 - WuAlphaColorQuantizer.IndexBits); int g = image[(i * 4) + 1] >> (8 - WuAlphaColorQuantizer.IndexBits); int b = image[i * 4] >> (8 - WuAlphaColorQuantizer.IndexBits); int ind = WuAlphaColorQuantizer.GetIndex(r + 1, g + 1, b + 1, a + 1); quantizedImage.Bytes[i] = this.tag[ind]; } return(quantizedImage); }
/// <summary> /// Builds a 3-D color histogram of <c>counts, r/g/b, c^2</c>. /// </summary> /// <param name="image">The image.</param> private void Build3DHistogram(byte[] image) { for (int i = 0; i < image.Length; i += 4) { int a = image[i + 3]; int r = image[i + 2]; int g = image[i + 1]; int b = image[i]; int inr = r >> (8 - WuAlphaColorQuantizer.IndexBits); int ing = g >> (8 - WuAlphaColorQuantizer.IndexBits); int inb = b >> (8 - WuAlphaColorQuantizer.IndexBits); int ina = a >> (8 - WuAlphaColorQuantizer.IndexAlphaBits); int ind = WuAlphaColorQuantizer.GetIndex(inr + 1, ing + 1, inb + 1, ina + 1); this.vwt[ind]++; this.vmr[ind] += r; this.vmg[ind] += g; this.vmb[ind] += b; this.vma[ind] += a; this.m2[ind] += (r * r) + (g * g) + (b * b) + (a * a); } }
/// <summary> /// Converts the histogram into moments so that we can rapidly calculate /// the sums of the above quantities over any desired box. /// </summary> private void Get3DMoments() { for (int r = 1; r < WuAlphaColorQuantizer.IndexCount; r++) { Array.Clear(this.volume, 0, WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(this.volumeR, 0, WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(this.volumeG, 0, WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(this.volumeB, 0, WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(this.volumeA, 0, WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(this.volume2, 0, WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount); for (int g = 1; g < WuAlphaColorQuantizer.IndexCount; g++) { Array.Clear(this.area, 0, WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(this.areaR, 0, WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(this.areaG, 0, WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(this.areaB, 0, WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(this.areaA, 0, WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(this.area2, 0, WuAlphaColorQuantizer.IndexAlphaCount); for (int b = 1; b < WuAlphaColorQuantizer.IndexCount; b++) { int line = 0; int lineR = 0; int lineG = 0; int lineB = 0; int lineA = 0; float line2 = 0; for (int a = 1; a < WuAlphaColorQuantizer.IndexAlphaCount; a++) { int ind1 = WuAlphaColorQuantizer.GetIndex(r, g, b, a); line += this.vwt[ind1]; lineR += this.vmr[ind1]; lineG += this.vmg[ind1]; lineB += this.vmb[ind1]; lineA += this.vma[ind1]; line2 += this.m2[ind1]; this.area[a] += line; this.areaR[a] += lineR; this.areaG[a] += lineG; this.areaB[a] += lineB; this.areaA[a] += lineA; this.area2[a] += line2; int inv = (b * WuAlphaColorQuantizer.IndexAlphaCount) + a; this.volume[inv] += this.area[a]; this.volumeR[inv] += this.areaR[a]; this.volumeG[inv] += this.areaG[a]; this.volumeB[inv] += this.areaB[a]; this.volumeA[inv] += this.areaA[a]; this.volume2[inv] += this.area2[a]; int ind2 = ind1 - WuAlphaColorQuantizer.GetIndex(1, 0, 0, 0); this.vwt[ind1] = this.vwt[ind2] + this.volume[inv]; this.vmr[ind1] = this.vmr[ind2] + this.volumeR[inv]; this.vmg[ind1] = this.vmg[ind2] + this.volumeG[inv]; this.vmb[ind1] = this.vmb[ind2] + this.volumeB[inv]; this.vma[ind1] = this.vma[ind2] + this.volumeA[inv]; this.m2[ind1] = this.m2[ind2] + this.volume2[inv]; } } } } }
/// <summary> /// Converts the histogram into moments so that we can rapidly calculate /// the sums of the above quantities over any desired box. /// </summary> private void Get3DMoments() { long[] volume = new long[WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount]; long[] volumeR = new long[WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount]; long[] volumeG = new long[WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount]; long[] volumeB = new long[WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount]; long[] volumeA = new long[WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount]; double[] volume2 = new double[WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount]; long[] area = new long[WuAlphaColorQuantizer.IndexAlphaCount]; long[] areaR = new long[WuAlphaColorQuantizer.IndexAlphaCount]; long[] areaG = new long[WuAlphaColorQuantizer.IndexAlphaCount]; long[] areaB = new long[WuAlphaColorQuantizer.IndexAlphaCount]; long[] areaA = new long[WuAlphaColorQuantizer.IndexAlphaCount]; double[] area2 = new double[WuAlphaColorQuantizer.IndexAlphaCount]; for (int r = 1; r < WuAlphaColorQuantizer.IndexCount; r++) { Array.Clear(volume, 0, WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(volumeR, 0, WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(volumeG, 0, WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(volumeB, 0, WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(volumeA, 0, WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(volume2, 0, WuAlphaColorQuantizer.IndexCount * WuAlphaColorQuantizer.IndexAlphaCount); for (int g = 1; g < WuAlphaColorQuantizer.IndexCount; g++) { Array.Clear(area, 0, WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(areaR, 0, WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(areaG, 0, WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(areaB, 0, WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(areaA, 0, WuAlphaColorQuantizer.IndexAlphaCount); Array.Clear(area2, 0, WuAlphaColorQuantizer.IndexAlphaCount); for (int b = 1; b < WuAlphaColorQuantizer.IndexCount; b++) { long line = 0; long lineR = 0; long lineG = 0; long lineB = 0; long lineA = 0; double line2 = 0; for (int a = 1; a < WuAlphaColorQuantizer.IndexAlphaCount; a++) { int ind1 = WuAlphaColorQuantizer.GetIndex(r, g, b, a); line += this.vwt[ind1]; lineR += this.vmr[ind1]; lineG += this.vmg[ind1]; lineB += this.vmb[ind1]; lineA += this.vma[ind1]; line2 += this.m2[ind1]; area[a] += line; areaR[a] += lineR; areaG[a] += lineG; areaB[a] += lineB; areaA[a] += lineA; area2[a] += line2; int inv = (b * WuAlphaColorQuantizer.IndexAlphaCount) + a; volume[inv] += area[a]; volumeR[inv] += areaR[a]; volumeG[inv] += areaG[a]; volumeB[inv] += areaB[a]; volumeA[inv] += areaA[a]; volume2[inv] += area2[a]; int ind2 = ind1 - WuAlphaColorQuantizer.GetIndex(1, 0, 0, 0); this.vwt[ind1] = this.vwt[ind2] + volume[inv]; this.vmr[ind1] = this.vmr[ind2] + volumeR[inv]; this.vmg[ind1] = this.vmg[ind2] + volumeG[inv]; this.vmb[ind1] = this.vmb[ind2] + volumeB[inv]; this.vma[ind1] = this.vma[ind2] + volumeA[inv]; this.m2[ind1] = this.m2[ind2] + volume2[inv]; } } } } }