锐化操作,输出对比度不正确

时间:2018-07-22 12:41:45

标签: c# image-processing convolution

看看 this source code 。具有以下内核的3x3 Sharpen滤镜

 0  -1   0 
-1   5  -1 
 0  -1   0

提供以下输出:

enter image description here

我试图使用自己的代码复制结果,这很简单:

public partial class FilterForm : Form
{
    public FilterForm()
    {
        InitializeComponent();

        Bitmap image = (Bitmap)Bitmap.FromFile("lena.jpg");            
        InputPictureBox.Image = image;

        double[,] dImage = ToDouble2d(image);
        double[,] dMask = { { 0,-1, 0, }, 
                            { -1, 5, -1, }, 
                            { 0,-1, 0, }, };

        double[,]dConv = LinearConvolutionSpatial(dImage, dMask);

        Bitmap conv = ToBitmap2d(dConv, PixelFormat.Format32bppArgb);

        OutputPictureBox.Image = conv;
    }

    public double[,] ToDouble2d(Bitmap input)
    {
        int width = input.Width;
        int height = input.Height;

        double[,] array2d = new double[width, height];

        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                Color cl = input.GetPixel(x, y);

                double gray = ((cl.R * 0.3) + (cl.G * 0.59) + (cl.B * 0.11));

                array2d[x, y] = gray / 255.0;
            }
        }

        return array2d;
    }

    public Bitmap ToBitmap2d(double[,] image, PixelFormat pixelFormat)
    {
        int Width = image.GetLength(0);
        int Height = image.GetLength(1);

        Bitmap bmp = new Bitmap(Width, Height, pixelFormat);

        for (int y = 0; y < Height; y++)
        {
            for (int x = 0; x < Width; x++)
            {
                int i = (int)(image[x, y] * 255.0);

                if (i > 255) i = 255;
                if (i < 0) i = 0;

                Color clr = Color.FromArgb(i, i, i);

                bmp.SetPixel(x, y, clr);
            }
        }

        return bmp;
    }

    private double[,] LinearConvolutionSpatial(double[,] paddedImage, double[,] mask)
    {
        int paddedImageWidth = paddedImage.GetLength(0);
        int paddedImageHeight = paddedImage.GetLength(1);

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

        int imageWidth = paddedImageWidth - maskWidth;
        int imageHeight = paddedImageHeight - maskHeight;

        double[,] convolve = new double[imageWidth, imageHeight];

        for (int y = 0; y < imageHeight; y++)
        {
            for (int x = 0; x < imageWidth; x++)
            {
                double sum = Sum(paddedImage, mask, x, y);
                int xxx = x;
                int yyy = y;
                convolve[xxx, yyy] = sum;

                string str = string.Empty;
            }
        }

        Rescale(convolve);

        return convolve;
    }

    double Sum(double[,] paddedImage1, double[,] mask1, int startX, int startY)
    {
        double sum = 0;

        int maskWidth = mask1.GetLength(0);
        int maskHeight = mask1.GetLength(1);

        for (int y = startY; y < (startY + maskHeight); y++)
        {
            for (int x = startX; x < (startX + maskWidth); x++)
            {
                double img = paddedImage1[x, y];
                double msk = mask1[maskWidth - x + startX - 1, maskHeight - y + startY - 1];
                sum = sum + (img * msk);
            }
        }

        return sum;
    }

    void Rescale(double[,] convolve)
    {
        int imageWidth = convolve.GetLength(0);
        int imageHeight = convolve.GetLength(1);

        double minAmp = 0.0;
        double maxAmp = 0.0;

        for (int j = 0; j < imageHeight; j++)
        {
            for (int i = 0; i < imageWidth; i++)
            {
                minAmp = Math.Min(minAmp, convolve[i, j]);
                maxAmp = Math.Max(maxAmp, convolve[i, j]);
            }
        }

        double scale = 1 / (Math.Abs(minAmp) + maxAmp);

        for (int j = 0; j < imageHeight; j++)
        {
            for (int i = 0; i < imageWidth; i++)
            {
                double d = (convolve[i, j] + Math.Abs(minAmp)) * scale;
                convolve[i, j] = d;
            }
        }
    }
}

但是,我面临的问题是,我的输出具有不同的对比度

enter image description here

enter image description here

我应该处理哪些要点?

2 个答案:

答案 0 :(得分:1)

上面的某些代码具有最小/最大效果,并平衡直方图。

从此行中删除标准化位:

 array2d[x, y] = gray;// / 255.0;

在此段中,我删除了255的比例缩放乘数:

public Bitmap ToBitmap2d(double[,] image, PixelFormat pixelFormat)
{
    int Width = image.GetLength(0);
    int Height = image.GetLength(1);

    Bitmap bmp = new Bitmap(Width, Height, pixelFormat);

    for (int y = 0; y < Height; y++)
    {
        for (int x = 0; x < Width; x++)
        {
            int i = (int)(image[x, y] * 1);

            if (i > 255) i = 255;
            if (i < 0) i = 0;

            Color clr = Color.FromArgb(i, i, i);

            bmp.SetPixel(x, y, clr);
        }
    }

    return bmp;
}

我还从该函数中删除了比例因子:

void Rescale(double[,] convolve)
{
    int imageWidth = convolve.GetLength(0);
    int imageHeight = convolve.GetLength(1);

    double minAmp = 0.0;
    double maxAmp = 255.0;

    for (int j = 0; j < imageHeight; j++)
    {
        for (int i = 0; i < imageWidth; i++)
        {
            minAmp = Math.Min(minAmp, convolve[i, j]);
            maxAmp = Math.Max(maxAmp, convolve[i, j]);
         }
     }

     double scale = 1 / (Math.Abs(minAmp) + maxAmp);

     for (int j = 0; j < imageHeight; j++)
     {
         for (int i = 0; i < imageWidth; i++)
         {
             double d = (convolve[i, j]);// + Math.Abs(minAmp)) * scale;
             convolve[i, j] = d;
         }
     }
 }

在进行了这些更改之后,似乎可以正常工作。

答案 1 :(得分:1)

我从this link找到了解决方案。主要线索是引入offsetfactor

  • factor 是内核中所有值的总和。
  • 偏移量是一个任意值,用于进一步固定输出。

给定链接中提供了以下源代码:

    private void SafeImageConvolution(Bitmap image, ConvMatrix fmat) 
    { 
        //Avoid division by 0 
        if (fmat.Factor == 0) 
            return; 

        Bitmap srcImage = (Bitmap)image.Clone(); 

        int x, y, filterx, filtery; 
        int s = fmat.Size / 2; 
        int r, g, b; 
        Color tempPix; 

        for (y = s; y < srcImage.Height - s; y++) 
        { 
            for (x = s; x < srcImage.Width - s; x++) 
            { 
                r = g = b = 0; 

                // Convolution 
                for (filtery = 0; filtery < fmat.Size; filtery++) 
                { 
                    for (filterx = 0; filterx < fmat.Size; filterx++) 
                    { 
                        tempPix = srcImage.GetPixel(x + filterx - s, y + filtery - s); 

                        r += fmat.Matrix[filtery, filterx] * tempPix.R; 
                        g += fmat.Matrix[filtery, filterx] * tempPix.G; 
                        b += fmat.Matrix[filtery, filterx] * tempPix.B; 
                    } 
                } 

                r = Math.Min(Math.Max((r / fmat.Factor) + fmat.Offset, 0), 255); 
                g = Math.Min(Math.Max((g / fmat.Factor) + fmat.Offset, 0), 255); 
                b = Math.Min(Math.Max((b / fmat.Factor) + fmat.Offset, 0), 255); 

                image.SetPixel(x, y, Color.FromArgb(r, g, b)); 
            } 
        } 
    }