user366312
user366312

Reputation: 17006

Blurred rather than Sharpened

I am using the following Kernel,

  double[,] kernel = new double[,]  { { -1, -1, -1, }, 
                                        { -1,  9, -1, }, 
                                        { -1, -1, -1, }, };

The following code seems to be blurring the input image, rather than Sharpening.

What could have been the issue here?

Here is the entire VS2013 solution.

The original image,

enter image description here

The resulting blurred image,

enter image description here

I have written the following code to Sharpen an image,

    public static Bitmap FftSharpen(Bitmap image, double [,] mask)
    {
        if (image.PixelFormat == PixelFormat.Format8bppIndexed)
        {
            Bitmap imageClone = (Bitmap)image.Clone();
            double[,] maskClone = (double[,])mask.Clone();

            Complex[,] cPaddedImage = ImageDataConverter.ToComplex(imageClone);
            Complex[,] cPaddedMask = ImageDataConverter.ToComplex(maskClone);
            Complex[,] cConvolved = Convolution.Convolve(cPaddedImage, cPaddedMask);

            return ImageDataConverter.ToBitmap(cConvolved);
        }
        else
        {
            throw new Exception("not a grascale");
        }
    }

.

.

P.S.

The following is my convolution code,

public static class Convolution
{
    public static Complex[,] Convolve(Complex[,] image, Complex[,] mask)
    {
        Complex[,] convolve = null;

        int imageWidth = image.GetLength(0);
        int imageHeight = image.GetLength(1);

        int maskWidth = mask.GetLength(0);
        int maskeHeight = mask.GetLength(1);

        if (imageWidth == maskWidth && imageHeight == maskeHeight)
        {
            FourierTransform ftForImage = new FourierTransform(image); ftForImage.ForwardFFT();
            FourierTransform ftForMask = new FourierTransform(mask); ftForMask.ForwardFFT();

            Complex[,] fftImage = ftForImage.FourierImageComplex;
            Complex[,] fftKernel = ftForMask.FourierImageComplex;

            Complex[,] fftConvolved = new Complex[imageWidth, imageHeight];


            for (int j = 0; j < imageHeight; j++)
            {
                for (int i = 0; i < imageWidth; i++)
                {
                    fftConvolved[i, j] = fftImage[i, j] * fftKernel[i, j];
                }
            }

            FourierTransform ftForConv = new FourierTransform();

            ftForConv.InverseFFT(fftConvolved);

            convolve = ftForConv.GrayscaleImageComplex;

            Rescale(convolve);

            convolve = FourierShifter.FFTShift(convolve);
        }
        else
        {
            throw new Exception("padding needed");
        }

        return convolve;
    }

    //Rescale values between 0 and 255.
    private static void Rescale(Complex[,] convolve)
    {
        int imageWidth = convolve.GetLength(0);
        int imageHeight = convolve.GetLength(1);

        double maxAmp = 0.0;
        for (int j = 0; j < imageHeight; j++)
        {
            for (int i = 0; i < imageWidth; i++)
            {
                maxAmp = Math.Max(maxAmp, convolve[i, j].Magnitude);
            }
        }
        double scale = 255.0 / maxAmp;

        for (int j = 0; j < imageHeight; j++)
        {
            for (int i = 0; i < imageWidth; i++)
            {
                convolve[i, j] = new Complex(convolve[i, j].Real * scale, convolve[i, j].Imaginary * scale);
                maxAmp = Math.Max(maxAmp, convolve[i, j].Magnitude);
            }
        }
    }
}

Upvotes: 2

Views: 175

Answers (1)

SleuthEye
SleuthEye

Reputation: 14577

Similarly to your other question, the kernel is obtained from an unsigned Bitmap which result in the effective kernel

255 255 255
255  9  255
255 255 255

instead of the expected

-1 -1 -1
-1  9 -1
-1 -1 -1

A solution would again be to convert the bitmap to signed values. Alternatively, since the code provided in this question also supports the numerical kernel to be provided directly to FftSharpen, you could pad _numericalKernel with:

public class MatrixPadder
{
  public static double[,] Pad(double[,] image, int newWidth, int newHeight)
  {
    int width = image.GetLength(0);
    int height = image.GetLength(1);
    /*
     It is always guaranteed that,

          width < newWidth

              and

          height < newHeight                  
     */
    if ((width < newWidth && height < newHeight)
          || (width < newWidth && height == newHeight)
          || (width == newWidth && height < newHeight))
    {
      double[,] paddedImage = new double[newWidth, newHeight];

      int startPointX = (int)Math.Ceiling((double)(newWidth - width) / (double)2) - 1;
      int startPointY = (int)Math.Ceiling((double)(newHeight - height) / (double)2) - 1;

      for (int y = startPointY; y < (startPointY + height); y++)
      {
        for (int x = startPointX; x < (startPointX + width); x++)
        {
          int xxx = x - startPointX;
          int yyy = y - startPointY;

          paddedImage[x, y] = image[xxx, yyy];
        }
      }

      return paddedImage;
    }
    else if (width == newWidth && height == newHeight)
    {
      return image;
    }
    else
    {
      throw new Exception("Pad() -- threw an exception");
    }
  }
}

which you could call from filterButton_Click using:

if (_convolutionType == ConvolutionType.FFT)
{
  double[,] paddedmask = MatrixPadder.Pad(_numericalKernel,
                                          _paddedImage.Width,
                                          _paddedImage.Height);
  sharpened = SharpenFilter.FftSharpen(_paddedImage, paddedmask);
}

Also adjusting the Rescale function as shown in my other answer should then give you the desired sharpened image:

Sharpened

Upvotes: 2

Related Questions