public static ResamplingFilter Create(ResamplingFilters filter) { ResamplingFilter resamplingFilter = null; switch (filter) { case ResamplingFilters.Box: resamplingFilter = new BoxFilter(); break; case ResamplingFilters.Triangle: resamplingFilter = new TriangleFilter(); break; case ResamplingFilters.Hermite: resamplingFilter = new HermiteFilter(); break; case ResamplingFilters.Bell: resamplingFilter = new BellFilter(); break; case ResamplingFilters.CubicBSpline: resamplingFilter = new CubicBSplineFilter(); break; case ResamplingFilters.Lanczos3: resamplingFilter = new Lanczos3Filter(); break; case ResamplingFilters.Mitchell: resamplingFilter = new MitchellFilter(); break; case ResamplingFilters.Cosine: resamplingFilter = new CosineFilter(); break; case ResamplingFilters.CatmullRom: resamplingFilter = new CatmullRomFilter(); break; case ResamplingFilters.Quadratic: resamplingFilter = new QuadraticFilter(); break; case ResamplingFilters.QuadraticBSpline: resamplingFilter = new QuadraticBSplineFilter(); break; case ResamplingFilters.CubicConvolution: resamplingFilter = new CubicConvolutionFilter(); break; case ResamplingFilters.Lanczos8: resamplingFilter = new Lanczos8Filter(); break; } return(resamplingFilter); }
/// <summary> /// Resamples input array to a new array using current resampling filter. /// </summary> /// <param name="input">Input array.</param> /// <param name="nWidth">Width of the output array.</param> /// <param name="nHeight">Height of the output array.</param> /// <returns>Output array.</returns> public ushort[][,] Resample(ushort[][,] input, int nWidth, int nHeight) { if (input == null || input.Length == 0 || nWidth <= 1 || nHeight <= 1) { return(null); } ResamplingFilter filter = ResamplingFilter.Create(this.filter); int width = input[0].GetLength(0); int height = input[0].GetLength(1); int planes = input.Length; this.covered = 0; this.total = (nWidth + height); // create bitmaps ushort[][,] work = new ushort[planes][, ]; ushort[][,] output = new ushort[planes][, ]; int c = 0; for (c = 0; c < planes; c++) { work[c] = new ushort[nWidth, height]; output[c] = new ushort[nWidth, nHeight]; } double xScale = ((double)nWidth / width); double yScale = ((double)nHeight / height); ContributorEntry[] contrib = new ContributorEntry[nWidth]; double wdth = 0, center = 0, weight = 0, intensity = 0; int left = 0, right = 0, i = 0, j = 0, k = 0; // horizontal downsampling if (xScale < 1.0) { // scales from bigger to smaller width wdth = (filter.defaultFilterRadius / xScale); for (i = 0; i < nWidth; i++) { contrib[i].n = 0; contrib[i].p = new Contributor[(int)Math.Floor(2 * wdth + 1)]; contrib[i].wsum = 0; center = ((i + 0.5) / xScale); left = (int)(center - wdth); right = (int)(center + wdth); for (j = left; j <= right; j++) { weight = filter.GetValue((center - j - 0.5) * xScale); if ((weight == 0) || (j < 0) || (j >= width)) { continue; } contrib[i].p[contrib[i].n].pixel = j; contrib[i].p[contrib[i].n].weight = weight; contrib[i].wsum += weight; contrib[i].n++; } if (aborting) { goto End; } } } else { // horizontal upsampling // scales from smaller to bigger width for (i = 0; i < nWidth; i++) { contrib[i].n = 0; contrib[i].p = new Contributor[(int)Math.Floor(2 * filter.defaultFilterRadius + 1)]; contrib[i].wsum = 0; center = ((i + 0.5) / xScale); left = (int)Math.Floor(center - filter.defaultFilterRadius); right = (int)Math.Ceiling(center + filter.defaultFilterRadius); for (j = left; j <= right; j++) { weight = filter.GetValue(center - j - 0.5); if ((weight == 0) || (j < 0) || (j >= width)) { continue; } contrib[i].p[contrib[i].n].pixel = j; contrib[i].p[contrib[i].n].weight = weight; contrib[i].wsum += weight; contrib[i].n++; } if (aborting) { goto End; } } } // filter horizontally from input to work for (c = 0; c < planes; c++) { for (k = 0; k < height; k++) { for (i = 0; i < nWidth; i++) { intensity = 0; for (j = 0; j < contrib[i].n; j++) { weight = contrib[i].p[j].weight; if (weight == 0) { continue; } intensity += (input[c][contrib[i].p[j].pixel, k] * weight); } //work[c][i, k] = (ushort)Math.Min(Math.Max(intensity / contrib[i].wsum, UInt16.MinValue), UInt16.MaxValue); work[c][i, k] = (ushort)Math.Min(Math.Max(intensity / contrib[i].wsum + 0.5, UInt16.MinValue), UInt16.MaxValue); } if (aborting) { goto End; } this.covered++; } } // pre-calculate filter contributions for a column contrib = new ContributorEntry[nHeight]; // vertical downsampling if (yScale < 1.0) { // scales from bigger to smaller height wdth = (filter.defaultFilterRadius / yScale); for (i = 0; i < nHeight; i++) { contrib[i].n = 0; contrib[i].p = new Contributor[(int)Math.Floor(2 * wdth + 1)]; contrib[i].wsum = 0; center = ((i + 0.5) / yScale); left = (int)(center - wdth); right = (int)(center + wdth); for (j = left; j <= right; j++) { weight = filter.GetValue((center - j - 0.5) * yScale); if ((weight == 0) || (j < 0) || (j >= height)) { continue; } contrib[i].p[contrib[i].n].pixel = j; contrib[i].p[contrib[i].n].weight = weight; contrib[i].wsum += weight; contrib[i].n++; } if (aborting) { goto End; } } } else { // vertical upsampling // scales from smaller to bigger height for (i = 0; i < nHeight; i++) { contrib[i].n = 0; contrib[i].p = new Contributor[(int)Math.Floor(2 * filter.defaultFilterRadius + 1)]; contrib[i].wsum = 0; center = ((i + 0.5) / yScale); left = (int)(center - filter.defaultFilterRadius); right = (int)(center + filter.defaultFilterRadius); for (j = left; j <= right; j++) { weight = filter.GetValue(center - j - 0.5); if ((weight == 0) || (j < 0) || (j >= height)) { continue; } contrib[i].p[contrib[i].n].pixel = j; contrib[i].p[contrib[i].n].weight = weight; contrib[i].wsum += weight; contrib[i].n++; } if (aborting) { goto End; } } } // filter vertically from work to output for (c = 0; c < planes; c++) { for (k = 0; k < nWidth; k++) { for (i = 0; i < nHeight; i++) { intensity = 0; for (j = 0; j < contrib[i].n; j++) { weight = contrib[i].p[j].weight; if (weight == 0) { continue; } intensity += (work[c][k, contrib[i].p[j].pixel] * weight); } //output[c][k, i] = (ushort)Math.Min(Math.Max(intensity, UInt16.MinValue), UInt16.MaxValue); output[c][k, i] = (ushort)Math.Min(Math.Max(intensity / contrib[i].wsum + 0.5, UInt16.MinValue), UInt16.MaxValue); } if (aborting) { goto End; } this.covered++; } } End :; work = null; return(output); }