Пример #1
0
            public ContributorEntry[] PrecomputeResample(double scale, int srcWidth, int destWidth)
            {
                // all variables are named as if we're scaling horizontally for the sake of readability, but the results work for both orientations
                var    dest = new ContributorEntry[destWidth];     // one entry for every pixel in the resulting (destination) row of pixels
                double r    = scale < 1 ? Radius / scale : Radius; // filter radius in terms of source image pixels
                double s    = scale < 1 ? scale : 1;               // filter scale relative to source pixels

                for (int destX = 0; destX < destWidth; destX++)
                {
                    dest[destX].SrcPixelCount = 0;
                    dest[destX].SrcPixel      = new Contributor[(int)Math.Floor(2 * r + 1)];
                    double center   = (destX + 0.5) / scale;
                    int    srcFromX = (int)Math.Floor(center - r);
                    int    srcToX   = (int)Math.Ceiling(center + r);

                    for (int srcX = srcFromX; srcX <= srcToX; srcX++)
                    {
                        double weight = GetValue((center - srcX - 0.5) * s);

                        if ((weight == 0) || (srcX < 0) || (srcX >= srcWidth))
                        {
                            continue;
                        }

                        dest[destX].SrcPixel[dest[destX].SrcPixelCount].Coord  = srcX;
                        dest[destX].SrcPixel[dest[destX].SrcPixelCount].Weight = weight;
                        dest[destX].SrcPixelCount++;
                    }
                }
                return(dest);
            }
Пример #2
0
        /// <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);
              }

              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);
              }

              if (aborting)
            goto End;

              this.covered++;
            }
              }

              End:;

              work = null;

              return output;
        }
Пример #3
0
    /// <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 + 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 / contrib[i].wsum + 0.5, UInt16.MinValue), UInt16.MaxValue);
                }

                if (aborting)
                {
                    goto End;
                }

                this.covered++;
            }
        }

        End :;

        work = null;

        return(output);
    }