Ejemplo n.º 1
0
    /// <summary>
    /// Applies the a filter kernel to the specified image.
    /// </summary>
    /// <param name="image">The image.</param>
    /// <param name="kernel">The filter kernel. (Needs to be square.)</param>
    /// <param name="wrapMode">The texture address mode.</param>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="image"/> or <paramref name="kernel"/> is <see langword="null"/>.
    /// </exception>
    /// <exception cref="ArgumentException">
    /// <paramref name="kernel"/> is non-square.
    /// </exception>
    public static void Convolve(Image image, float[,] kernel, TextureAddressMode wrapMode)
    {
      if (image == null)
        throw new ArgumentNullException("image");
      if (kernel == null)
        throw new ArgumentNullException("kernel");
      if (kernel.GetLength(0) != kernel.GetLength(1))
        throw new ArgumentException("Filter kernel needs to be square.", "kernel");

      int width = image.Width;
      int height = image.Height;
      int kernelSize = kernel.GetLength(0);
      int kernelOffset = kernelSize / 2;

      var tmpImage = new Image(width, height, image.Format);
      Buffer.BlockCopy(image.Data, 0, tmpImage.Data, 0, image.Data.Length);

      // ReSharper disable AccessToDisposedClosure
      using (var tempImage4F = new ImageAccessor(tmpImage))
      using (var image4F = new ImageAccessor(image))
      {

        for (int y = 0; y < height; y++)
#else
        Parallel.For(0, height, y =>

        {
          for (int x = 0; x < width; x++)
          {
            // Apply 2D kernel at (x, y).
            Vector4 color = new Vector4();
            for (int row = 0; row < kernelSize; row++)
            {
              int srcY = y + row - kernelOffset;
              for (int column = 0; column < kernelSize; column++)
              {
                int srcX = x + column - kernelOffset;
                color += kernel[row, column] * tempImage4F.GetPixel(srcX, srcY, wrapMode);
              }
            }

            image4F.SetPixel(x, y, color);
          }
        }

        );

      }
      // ReSharper restore AccessToDisposedClosure
    }
Ejemplo n.º 2
0
    private static void Resize2D(Image srcImage, Image dstImage, bool alphaTransparency, TextureAddressMode wrapMode, PolyphaseKernel kernelX, PolyphaseKernel kernelY)
    {
      var tmpImage = new Image(dstImage.Width, srcImage.Height, srcImage.Format);

      // ReSharper disable AccessToDisposedClosure
      using (var srcImage4F = new ImageAccessor(srcImage))
      using (var tmpImage4F = new ImageAccessor(tmpImage))
      using (var dstImage4F = new ImageAccessor(dstImage))
      {
        // Resize horizontally: srcImage --> tmpImage
        {
          float scale = (float)tmpImage4F.Width / srcImage4F.Width;
          float inverseScale = 1.0f / scale;


          for (int y = 0; y < tmpImage4F.Height; y++)
#else
          Parallel.For(0, tmpImage4F.Height, y =>

          {
            // Apply polyphase kernel horizontally.
            for (int x = 0; x < tmpImage4F.Width; x++)
            {
              float center = (x + 0.5f) * inverseScale;

              int left = (int)Math.Floor(center - kernelX.Width);
              int right = (int)Math.Ceiling(center + kernelX.Width);
              Debug.Assert(right - left <= kernelX.WindowSize);

              float totalRgbWeights = 0.0f;
              Vector4 sum = new Vector4();
              for (int i = 0; i < kernelX.WindowSize; i++)
              {
                Vector4 color = srcImage4F.GetPixel(left + i, y, wrapMode);

                //if (Numeric.IsNaN(color.X) || Numeric.IsNaN(color.Y) || Numeric.IsNaN(color.Z) || Numeric.IsNaN(color.W)
                //   || color.X < 0 || color.Y < 0 || color.Z < 0 || color.W < 0
                //   || color.X > 1 || color.Y > 1 || color.Z > 1 || color.W > 1)
                //  Debugger.Break();

                const float alphaEpsilon = 1.0f / 256.0f;
                float alpha = alphaTransparency ? color.W + alphaEpsilon : 1.0f;

                float weight = kernelX.Weights[x, i];
                float rgbWeight = weight * alpha;
                totalRgbWeights += rgbWeight;

                sum.X += color.X * rgbWeight;
                sum.Y += color.Y * rgbWeight;
                sum.Z += color.Z * rgbWeight;
                sum.W += color.W * weight;

                //if (Numeric.IsNaN(sum.X) || Numeric.IsNaN(sum.Y) || Numeric.IsNaN(sum.Z) || Numeric.IsNaN(sum.W)
                //   || sum.X < 0 || sum.Y < 0 || sum.Z < 0 || sum.W < 0
                //   || sum.X > 1 || sum.Y > 1 || sum.Z > 1 || sum.W > 1)
                //  Debugger.Break();
              }

              float f = 1 / totalRgbWeights;
              sum.X *= f;
              sum.Y *= f;
              sum.Z *= f;

              //if (Numeric.IsNaN(sum.X) || Numeric.IsNaN(sum.Y) || Numeric.IsNaN(sum.Z) || Numeric.IsNaN(sum.W)
              //   || sum.X < 0 || sum.Y < 0 || sum.Z < 0 || sum.W < 0
              //   || sum.X > 1 || sum.Y > 1 || sum.Z > 1 || sum.W > 1)
              //  Debugger.Break();

              tmpImage4F.SetPixel(x, y, sum);
            }
          }

          );

        }

        // Resize vertically: tmpImage --> dstImage
        {
          float scale = (float)dstImage4F.Height / tmpImage4F.Height;
          float inverseScale = 1.0f / scale;


          for (int x = 0; x < dstImage4F.Width; x++)
#else
          Parallel.For(0, dstImage4F.Width, x =>

          {
            // Apply polyphase kernel vertically.
            for (int y = 0; y < dstImage4F.Height; y++)
            {
              float center = (y + 0.5f) * inverseScale;

              int left = (int)Math.Floor(center - kernelY.Width);
              int right = (int)Math.Ceiling(center + kernelY.Width);
              Debug.Assert(right - left <= kernelY.WindowSize);

              float totalRgbWeights = 0.0f;
              Vector4 sum = new Vector4();
              for (int i = 0; i < kernelY.WindowSize; i++)
              {
                Vector4 color = tmpImage4F.GetPixel(x, left + i, wrapMode);

                const float alphaEpsilon = 1.0f / 256.0f;
                float alpha = alphaTransparency ? color.W + alphaEpsilon : 1.0f;

                float weight = kernelY.Weights[y, i];
                float rgbWeight = weight * alpha;
                totalRgbWeights += rgbWeight;

                sum.X += color.X * rgbWeight;
                sum.Y += color.Y * rgbWeight;
                sum.Z += color.Z * rgbWeight;
                sum.W += color.W * weight;
              }

              float f = 1 / totalRgbWeights;
              sum.X *= f;
              sum.Y *= f;
              sum.Z *= f;

              dstImage4F.SetPixel(x, y, sum);
            }
          }

          );

        }
      }
      // ReSharper restore AccessToDisposedClosure
    }