Esempio n. 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);
    }
Esempio n. 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);
      }
    }
Esempio n. 3
0
    /*
     * This region is a C++ -> C# conversion from the original sources of Pascal Getreuer <*****@*****.**>
     */
    /// <summary>
    /// Resizes the image to the specified dimensions using the given kernel type.
    /// </summary>
    /// <param name="destWidth">Width of the destination.</param>
    /// <param name="destHeight">Height of the destination.</param>
    /// <param name="interpolationInfo">The interpolation method info.</param>
    /// <param name="centeredGrid">if set to <c>true</c> using a centered grid; otherwise, using top-left aligned.</param>
    /// <returns>
    /// The resized image
    /// </returns>
    private FloatImage _Resize(int destWidth, int destHeight, Kernels.FixedRadiusKernelInfo interpolationInfo, bool centeredGrid) {
      var xScale = (float)destWidth / this.Width;
      var yScale = (float)destHeight / this.Height;
      var xStep = 1 / xScale;
      var yStep = 1 / yScale;
      float xStart, yStart;
      if (centeredGrid) {
        xStart = (xStep - 1) / 2;
        yStart = (yStep - 1) / 2;
      } else {
        xStart = yStart = 0;
      }
      var result = new FloatImage(destWidth, destHeight, this._horizontalOutOfBoundsMode, this._verticalOutOfBoundsMode);

      // prefilter image if necessary
      if (interpolationInfo.PrefilterAlpha != null && interpolationInfo.PrefilterAlpha.Length > 0)
        this._PrefilterImage(interpolationInfo.PrefilterAlpha, interpolationInfo.PrefilterScale);

      // resample
      this._LinScale2D(
        result,
        xStart,
        xStep,
        yStart,
        yStep,
        interpolationInfo.Kernel,
        interpolationInfo.KernelRadius,
        interpolationInfo.KernelNormalize,
        OutOfBoundsUtils.GetHandlerOrCrash(this.HorizontalOutOfBoundsMode),
        OutOfBoundsUtils.GetHandlerOrCrash(this.VerticalOutOfBoundsMode)
      );
      return (result);
    }