繁体   English   中英

从高斯模糊图像中去除黑色边框

[英]Removing black border from Gaussian blurred image

我正在尝试基于http://softwarebydefault.com/2013/06/08/calculating-gaussian-kernels/上的文章和示例,为我的图书馆实现高斯模糊方法

由于某种原因,我在生成的图像周围不断出现黑色边框,这会侵蚀原始图像,如下所示。

带有黑色边框的模糊的图像

边界厚度随着高斯核长度的增加而增加。 该图像是使用15x15的矩阵生成的。

任何人都可以对发生的事情有所了解吗?

我的代码; 抱歉的长度:

加工方法。

/// <summary>
/// Processes the image.
/// </summary>
/// <param name="factory">The the current instance of the
///  <see cref="T:ImageProcessor.ImageFactory" /> class containing
/// the image to process.</param>
/// <returns>
/// The processed image from the current instance of the
/// <see cref="T:ImageProcessor.ImageFactory" /> class.
/// </returns>
public Image ProcessImage(ImageFactory factory)
{
    Bitmap newImage = null;
    Bitmap image = (Bitmap)factory.Image;

    try
    {
        double[,] filterMatrix = this.Calculate((int)this.DynamicParameter, 10);

        // We could implement factor and bias here as parameters if 
        // we move this to a separate method.
        const double Factor = 1;
        const double Bias = 0;

        BitmapData sourceData = image.LockBits(
        new Rectangle(0, 0, image.Width, image.Height),
        ImageLockMode.ReadOnly,
        PixelFormat.Format32bppArgb);

        byte[] pixelBuffer = new byte[sourceData.Stride * sourceData.Height];
        byte[] resultBuffer = new byte[sourceData.Stride * sourceData.Height];

        Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);
        image.UnlockBits(sourceData);

        int filterWidth = filterMatrix.GetLength(1);
        int filterHeight = filterMatrix.GetLength(0);
        int filterOffsetWidth = (filterWidth - 1) / 2;
        int filterOffsetHeight = (filterHeight - 1) / 2;

        for (int offsetY = filterOffsetHeight; offsetY < image.Height - filterOffsetHeight; offsetY++)
        {
            for (int offsetX = filterOffsetWidth; offsetX < image.Width - filterOffsetWidth; offsetX++)
            {
                double blue = 0;
                double green = 0;
                double red = 0;

                int byteOffset = (offsetY * sourceData.Stride) + (offsetX * 4);

                for (int filterY = -filterOffsetWidth; filterY <= filterOffsetWidth; filterY++)
                {
                    for (int filterX = -filterOffsetWidth; filterX <= filterOffsetWidth; filterX++)
                    {
                        int calcOffset = byteOffset + (filterX * 4) + (filterY * sourceData.Stride);

                        blue += pixelBuffer[calcOffset]
                                * filterMatrix[filterY + filterOffsetWidth, filterX + filterOffsetWidth];

                        green += pixelBuffer[calcOffset + 1]
                                    * filterMatrix[filterY + filterOffsetWidth, filterX + filterOffsetWidth];

                        red += pixelBuffer[calcOffset + 2]
                                * filterMatrix[filterY + filterOffsetWidth, filterX + filterOffsetWidth];
                    }
                }

                blue = (Factor * blue) + Bias;
                green = (Factor * green) + Bias;
                red = (Factor * red) + Bias;

                blue = blue > 255 ? 255 : (blue < 0 ? 0 : blue);
                green = green > 255 ? 255 : (green < 0 ? 0 : green);
                red = red > 255 ? 255 : (red < 0 ? 0 : red);

                resultBuffer[byteOffset] = (byte)blue;
                resultBuffer[byteOffset + 1] = (byte)green;
                resultBuffer[byteOffset + 2] = (byte)red;
                resultBuffer[byteOffset + 3] = 255;
            }
        }

        // ReSharper disable once UseObjectOrCollectionInitializer
        newImage = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb);
        newImage.Tag = image.Tag;

        BitmapData resultData = newImage.LockBits(
            new Rectangle(0, 0, newImage.Width, newImage.Height),
            ImageLockMode.WriteOnly,
            PixelFormat.Format32bppArgb);

        Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length);
        newImage.UnlockBits(resultData);

        image.Dispose();
        image = newImage;

        // Save the image to ensure that nothing else is going on downstream.
        newImage.Save("C:\\Users\\James\\Desktop\\image.jpg", ImageFormat.Jpeg);
    }
    catch
    {
        if (newImage != null)
        {
            newImage.Dispose();
        }
    }

    return image;
}

高斯计算器。

/// <summary>
/// Calculates a Gaussian kernel with the given .
/// </summary>
/// <param name="length">
/// The length.
/// </param>
/// of the kernel to produce
/// <param name="weight">
/// The weight of the kernel.
/// </param>
/// <returns>
/// The <see><cref>double[,]</cref></see> containing the Gaussian kernel.
/// </returns>
private double[,] Calculate(int length, double weight)
{
    double[,] kernel = new double[length, length];
    double sumTotal = 0;

    int kernelRadius = length / 2;

    double calculatedEuler = 1.0 /
    (2.0 * Math.PI * Math.Pow(weight, 2));

    for (int filterY = -kernelRadius;
            filterY <= kernelRadius; filterY++)
    {
        for (int filterX = -kernelRadius; filterX <= kernelRadius; filterX++)
        {
            double distance = ((filterX * filterX) + (filterY * filterY)) / (2 * (weight * weight));

            kernel[filterY + kernelRadius,
                    filterX + kernelRadius] =
                    calculatedEuler * Math.Exp(-distance);

            sumTotal += kernel[filterY + kernelRadius,
                                filterX + kernelRadius];
        }
    }

    for (int y = 0; y < length; y++)
    {
        for (int x = 0; x < length; x++)
        {
            kernel[y, x] = kernel[y, x] *
                            (1.0 / sumTotal);
        }
    }

    return kernel;
}

您有一个黑色边框,因为您没有在那里渲染任何像素。

int filterOffsetWidth = (filterWidth - 1) / 2;
int filterOffsetHeight = (filterHeight - 1) / 2;

for (int offsetY = filterOffsetHeight; 
     offsetY < image.Height - filterOffsetHeight; 
     offsetY++)
{
    for (int offsetX = filterOffsetWidth; 
         offsetX < image.Width - filterOffsetWidth; 
         offsetX++)

如果要删除黑色边框,则必须为offsetY < filterOffsetHeight等计算一些值。

更新:

因此,对于15的矩阵大小, filterOffsetHeight将为7。您的外部循环从offsetY = 7开始,并且您从不为第0至6行计算任何值。该区域中的像素的红色,绿色的默认值为0和蓝色,在图像顶部显示为黑色边框。 同一件事发生在其他边界。

显然,您不能仅在这些边界中运行计算。 因此,您有两种选择:裁剪图像或使用其他算法计算边界。 如果要选择第二个选项,最简单的方法是假定原始图像外部的像素与图像边界上最近的像素具有相同的颜色。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM