使用平均内核的图像操作

本文关键字:图像 操作 内核 | 更新日期: 2023-09-27 18:28:59

我一直在编写一个代码,该代码获取图像,将其转换为灰度,然后根据按下的按钮进行图像操作。当按下按钮(例如Average 3x3,Prewitt 5x5)时,它会调用2D乘法函数,该函数在灰度图像上循环,同时在内核上循环,将矩阵中的所有值相加。如果任何值超过255,则将其设置为255。然后在一个临时位图变量上使用SetPixel,该变量最终被放入picturebox中。当我运行程序时,我选择一个图像,它会显示它(灰度),但在选择其中一个过滤器后,程序会冻结大约30秒,然后什么都不改变,也不应用过滤器。我试过调试,但似乎找不到问题出在哪里!

编辑:最初的问题已经解决了(我必须刷新图片框才能正确显示新图像。但我在这里面临着另一个关于prewitt内核的问题。

我得到这个错误"附加信息:值"-6"对"red"无效。"red"应大于或等于0且小于或等于255。"

而且我不确定在我的代码中更改什么来解决这个问题。

正在初始化:

public partial class Form1 : Form
{
    private Image img;
    Bitmap grayscaleimage;
    double[][] AVGKernel = new double[11][];
    double[][] PrewittKernel = new double[11][];
    int[] AVGKernal1DH = new int[11];
    int[] AVGKernal1DV = new int[11];
    Bitmap tempBitmap;
    public Form1()
    {
        InitializeComponent();
        for (int i = 0; i < 11; i++)
        {
            AVGKernel[i] = new double[11];
            PrewittKernel[i] = new double[11];
            for (int j = 0; j < 11; j++)
            {
                AVGKernel[i][j] = 0;
                PrewittKernel[i][j] = 0;
                AVGKernal1DH[j] = 0;
                AVGKernal1DV[j] = 0;
            }
        }
}

打开按钮并将图片转换为灰度:

private void OpenImageButton(object sender, EventArgs e)
    {
        OpenFileDialog openFileDialog = new OpenFileDialog();
        if (openFileDialog.ShowDialog() == DialogResult.OK)
        {
            this.img = Image.FromFile(openFileDialog.FileName);
            grayscaleimage = new Bitmap(img);
            int rgb;
            Color c;
            for (int y = 0; y < grayscaleimage.Height; y++)
                for (int x = 0; x < grayscaleimage.Width; x++)
                {
                    c = grayscaleimage.GetPixel(x, y);
                    rgb = (int)((c.R + c.G + c.B) / 3);
                    grayscaleimage.SetPixel(x, y, Color.FromArgb(rgb, rgb, rgb));
                }
            this.pictureBox1.BackgroundImage = grayscaleimage;
            pictureBox1.BackgroundImageLayout = ImageLayout.Zoom;
        }
    }

许多可用按钮的一个例子:

private void button5_Click(object sender, EventArgs e)
    {
        AVGKernel[0][0] = 1; AVGKernel[0][1] = 1; AVGKernel[0][2] = 1; AVGKernel[0][3] = 1; AVGKernel[0][4] = 1;
        AVGKernel[1][0] = 1; AVGKernel[1][1] = 1; AVGKernel[1][2] = 1; AVGKernel[1][3] = 1; AVGKernel[1][4] = 1;
        AVGKernel[2][0] = 1; AVGKernel[2][1] = 1; AVGKernel[2][2] = 1; AVGKernel[2][3] = 1; AVGKernel[2][4] = 1;
        AVGKernel[3][0] = 1; AVGKernel[3][1] = 1; AVGKernel[3][2] = 1; AVGKernel[3][3] = 1; AVGKernel[3][4] = 1;
        AVGKernel[4][0] = 1; AVGKernel[4][1] = 1; AVGKernel[4][2] = 1; AVGKernel[4][3] = 1; AVGKernel[4][4] = 1;
        kernal2DMultiplication(AVGKernel, 5);
        this.pictureBox1.BackgroundImage = tempBitmap;
    }

Prewitt 5x5内核

 private void button13_Click(object sender, EventArgs e)
    {
        PrewittKernel[0][0] = 2; PrewittKernel[0][1] = 1; PrewittKernel[0][2] = 0; PrewittKernel[0][3] = -1; PrewittKernel[0][4] = -2;
        PrewittKernel[1][0] = 2; PrewittKernel[1][1] = 1; PrewittKernel[1][2] = 0; PrewittKernel[1][3] = -1; PrewittKernel[1][4] = -2;
        PrewittKernel[2][0] = 2; PrewittKernel[2][1] = 1; PrewittKernel[2][2] = 0; PrewittKernel[2][3] = -1; PrewittKernel[2][4] = -2;
        PrewittKernel[3][0] = 2; PrewittKernel[3][1] = 1; PrewittKernel[3][2] = 0; PrewittKernel[3][3] = -1; PrewittKernel[3][4] = -2;
        PrewittKernel[4][0] = 2; PrewittKernel[4][1] = 1; PrewittKernel[4][2] = 0; PrewittKernel[4][3] = -1; PrewittKernel[4][4] = -2;
        kernal2DMultiplication(PrewittKernel, 5);
        this.pictureBox1.BackgroundImage = tempBitmap;
        this.pictureBox1.Refresh();
    }

最后,调用的函数:

private void kernal2DMultiplication(double[][] kernel, int size)
    {
        tempBitmap = grayscaleimage;
        double nrgb = 0;
        for (int i = 0; i < grayscaleimage.Width - size / 2; i++)
        {
            for (int j = 0; j < grayscaleimage.Height - size / 2; j++)
            {
                if (i >= size / 2 && j >= size / 2)
                {
                    for (int k = 0; k < size; k++)
                        for (int l = 0; l < size; l++)
                            nrgb += grayscaleimage.GetPixel(i + k - (size / 2), j + l - (size / 2)).R * kernel[k][l];
                            nrgb = nrgb / (size * size);
                    if (nrgb > 255)
                        nrgb = 255;
                    tempBitmap.SetPixel(i, j, Color.FromArgb((int)nrgb, (int)nrgb, (int)nrgb));
                }
            }
        }
    }

使用平均内核的图像操作

问题是您在原地修改BackgroundImage位图,而不是复制、修改副本,然后将副本设置为BackgroundImage:

    this.pictureBox1.BackgroundImage = grayscaleimage; // initially
    tempBitmap = grayscaleimage; 
    // Make changes to tempBitmap
    this.pictureBox1.BackgroundImage = tempBitmap; // actually still the same pointer

在这种情况下,BackgroundImage设置器不会强制重新绘制控件。要自己强制执行,请调用Refresh():

    this.pictureBox1.Refresh();

要提高性能,请考虑用对LockBits的单个调用替换对SetPixel的多个调用。例如,请参见此处。