Example #1
0
    /// <summary>
    /// Create scanline interpolation filter to be applied with ScaleScan
    /// This routine creates a scalescanfilter for 1-D interpolation of samples at
    /// the locations
    ///    XStart + n*XStep, n = 0, ..., DestWidth - 1,
    /// where the pixels of the source are logically located at the integers.  Half-
    /// sample even symmetric extension is used to handle the boundaries.
    /// </summary>
    /// <param name="destWidth">width after interpolation</param>
    /// <param name="xstart">leftmost sampling location (in input coordinates)</param>
    /// <param name="xstep">the length between successive samples (in input coordinates)</param>
    /// <param name="srcWidth">width of the input</param>
    /// <param name="kernel">interpolation kernel function to use</param>
    /// <param name="kernelRadius">kernel support radius</param>
    /// <param name="kernelNormalize">if set to <c>true</c> filter rows are normalized to sum to 1</param>
    /// <param name="boundary">boundary handling</param>
    /// <returns></returns>
    /// 
    /// 
    private static ScaleScanFilter _MakeScaleScanFilter(int destWidth, float xstart, float xstep, int srcWidth, Kernels.FixedRadiusKernelMethod kernel, float kernelRadius, bool kernelNormalize, OutOfBoundsUtils.OutOfBoundsHandler boundary) {
      Contract.Requires(kernel != null);

      var kernelWidth = (int)Math.Ceiling(2 * kernelRadius);
      var filterWidth = (srcWidth < kernelWidth) ? srcWidth : kernelWidth;
      var filterCoeff = new float[filterWidth * destWidth];
      var filterPos = new short[destWidth];

      var result = new ScaleScanFilter {
        Coeff = filterCoeff,
        Pos = filterPos,
        Width = filterWidth
      };

      var maxPos = srcWidth - filterWidth;

      var coeffIndex = 0;
      for (var destX = 0; destX < destWidth; destX++) {
        var srcX = xstart + xstep * destX;
        var pos = (int)Math.Ceiling(srcX - kernelRadius);

        if (pos < 0 || maxPos < pos) {
          filterPos[destX] = (short)(pos < 0 ? 0 : pos > maxPos ? maxPos : pos);

          for (var n = 0; n < filterWidth; n++)
            filterCoeff[coeffIndex + n] = 0;

          for (var n = 0; n < kernelWidth; n++) {
            var index = pos + n;
            if (index < 0 || index >= srcWidth)
              index = boundary(index, srcWidth,index<0);

            filterCoeff[coeffIndex + index - filterPos[destX]]
              += (float) kernel(srcX - index);
          }
        } else {
          filterPos[destX] = (short)pos;

          for (var n = 0; n < filterWidth; n++)
            filterCoeff[coeffIndex + n] = (float)kernel(srcX - (pos + n));
        }

        if (kernelNormalize)	/* Normalize */ {
          var sum = 0f;

          for (var n = 0; n < filterWidth; n++)
            sum += filterCoeff[coeffIndex + n];

          for (var n = 0; n < filterWidth; n++)
            filterCoeff[coeffIndex + n] /= sum;
        }

        coeffIndex += filterWidth;
      }

      return (result);
    }
Example #2
0
    /// <summary>
    /// Scale image with a compact support interpolation kernel
    /// This is a generic linear interpolation routine to scale an image using any
    /// compactly supported interpolation kernel.  The kernel is applied separably
    /// along both dimensions.  Half-sample even symmetric extension is used to
    /// handle the boundaries.
    /// 
    /// The interpolation is computed so that Dest[m + DestWidth*n] is the
    /// interpolation of Src at sampling location
    ///     (XStart + m*XStep, YStart + n*YStep)
    /// for m = 0, ..., DestWidth - 1, n = 0, ..., DestHeight - 1, where the
    /// pixels of Src are located at the integers.
    /// 
    /// The implementation follows the approach taken in ffmpeg's swscale library.
    /// First a "scanline filter" is constructed, a sparse matrix such that
    /// multiplying with a row of the input image produces an interpolated row in
    /// the output image.  Similarly a second matrix is constructed for
    /// interpolating columns.  The interpolation itself is then essentially two
    /// sparse matrix times dense matrix multiplies.
    /// </summary>
    /// <param name="destination">pointer to memory for holding the interpolated image</param>
    /// <param name="xStart">leftmost sampling location (in input coordinates)</param>
    /// <param name="xStep">the length between successive samples (in input coordinates)</param>
    /// <param name="yStart">uppermost sampling location (in input coordinates)</param>
    /// <param name="yStep">the length between successive samples (in input coordinates)</param>
    /// <param name="kernel">interpolation kernel function to use</param>
    /// <param name="kernelRadius">kernel support radius</param>
    /// <param name="kernelNormalize">if set to <c>true</c> filter rows are normalized to sum to 1</param>
    /// <param name="horizontalOutOfBoundsHandler">The horizontal out of bounds handler.</param>
    /// <param name="verticalOutOfBoundsHandler">The vertical out of bounds handler.</param>
    private void _LinScale2D(FloatImage destination, float xStart, float xStep, float yStart, float yStep, Kernels.FixedRadiusKernelMethod kernel, float kernelRadius, bool kernelNormalize, OutOfBoundsUtils.OutOfBoundsHandler horizontalOutOfBoundsHandler, OutOfBoundsUtils.OutOfBoundsHandler verticalOutOfBoundsHandler) {
      Contract.Requires(destination != null);
      Contract.Requires(kernel != null);
      Contract.Requires(!(kernelRadius < 0));

      var srcWidth = this.Width;
      var srcHeight = this.Height;

      var destHeight = destination.Height;
      var destWidth = destination.Width;

      var buffer = new float[srcWidth * destHeight];
      var hFilter = _MakeScaleScanFilter(destWidth, xStart, xStep, srcWidth, kernel, kernelRadius, kernelNormalize, horizontalOutOfBoundsHandler);
      var vFilter = _MakeScaleScanFilter(destHeight, yStart, yStep, srcHeight, kernel, kernelRadius, kernelNormalize, verticalOutOfBoundsHandler);

      foreach (var plane in new[] {
        Tuple.Create(this._redPlane,destination._redPlane),
        Tuple.Create(this._greenPlane,destination._greenPlane),
        Tuple.Create(this._bluePlane,destination._bluePlane),
        Tuple.Create(this._alphaPlane,destination._alphaPlane),
      }) {
        for (var x = 0; x < srcWidth; x++)
          _ScaleScan(buffer, x, srcWidth, destHeight, plane.Item1, x, srcWidth, vFilter);

        for (var y = 0; y < destHeight; y++)
          _ScaleScan(plane.Item2, y * destWidth, 1, destWidth, buffer, y * srcWidth, 1, hFilter);
      }
    }
Example #3
0
    private static float _GetValueFromPlane(float[] plane, int x, int y, int width, int height, OutOfBoundsUtils.OutOfBoundsHandler horizontalOutOfBoundsHandler, OutOfBoundsUtils.OutOfBoundsHandler verticalOutOfBoundsHandler) {
      if (x < 0 || x >= width)
        x = horizontalOutOfBoundsHandler(x, width,x<0);

      if (y < 0 || y >= height)
        y = verticalOutOfBoundsHandler(y, height,y<0);
      
      return (plane[y * width + x]);
    }