使用平均内核的图像处理
问题描述:
我一直在研究一个代码,它将图像转化为灰度,然后根据按下哪个按钮进行图像处理。当按下一个按钮(例如,平均3x3,Prewitt 5x5)时,它将调用2D乘法函数,该函数会在灰度图像上循环,同时循环遍历内核,并添加矩阵中的所有值。如果任何值超过255,则将其设置为255.然后在临时位图变量上使用SetPixel,最终将其置于picturebox中。当我运行该程序时,我选择了一个图像并将其显示(作为灰度),但是在选择其中一个过滤器后,程序冻结了大约30秒,然后没有任何更改,也没有应用过滤器。我试过调试,我似乎无法找到问题所在!使用平均内核的图像处理
编辑:。在最初的问题已经解决了(我不得不刷新PictureBox的新图像的正确显示 但我在这里面临的另一问题与问候的普鲁伊特内核
我得到这个错误 “附加信息:'-6'的值对于'红'无效,'红'应该大于或等于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算子的5×5内核
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();
如果将灰度图像“grayscaleimage”保存到文件中并将其打开,例如Paint(或类似),您是看到灰色图像还是黑色? – Sjips 2014-11-03 19:10:46
@Sjips它的灰色 – 2014-11-03 19:14:21
嗯,GetPixel/SetPixel是相对较慢的操作。也许通过添加'Debug.WriteLine'语句,你可以看到什么代码正在执行,并且你在哪里结束了一个无限循环(如果发生这种情况)。 – Sjips 2014-11-03 19:20:45