我使用Winforms。在我的窗体中,我有一个显示白色图像的图片框。我还有一个按钮,如果你单击它,这个按钮可以去除图像上的斑点/点。2当图像尺寸不大时,它可以快速地去除斑点。3如果图像很大,它需要一段时间。4有时这个功能也会从图像中去除一些它认为是斑点的单词。如何提高此功能的性能,并更准确地去除斑点或点,基本上消除图像的斑点?
更新经过研究,我发现这个库似乎很有希望解决这个问题:
http://www.aforgenet.com/framework/docs/html/cdf93487-0659-e371-fed9-3b216efb6954.htm
斑点图像链接:http://www.filedropper.com/testing-image3
图像示例
- 请注意,链接中的图片有此图片的更大版本:*
图像信息
- 这里需要注意的是,这是一个白色图像-位深1*
我的代码
private int[] mask = new int[9];
private void remove_spot_btn_Click(object sender, EventArgs e)
{
Bitmap img = new Bitmap(pictureBox1.Image);
Color c;
for (int ii = 0; ii < img.Width; ii++)
{
for (int jj = 0; jj < img.Height; jj++)
{
if (ii - 1 >= 0 && jj - 1 >= 0)
{
c = img.GetPixel(ii - 1, jj - 1);
mask[0] = Convert.ToInt16(c.R);
}
else
{
mask[0] = 0;
}
if (jj - 1 >= 0 && ii + 1 < img.Width)
{
c = img.GetPixel(ii + 1, jj - 1);
mask[1] = Convert.ToInt16(c.R);
}
else
mask[1] = 0;
if (jj - 1 >= 0)
{
c = img.GetPixel(ii, jj - 1);
mask[2] = Convert.ToInt16(c.R);
}
else
mask[2] = 0;
if (ii + 1 < img.Width)
{
c = img.GetPixel(ii + 1, jj);
mask[3] = Convert.ToInt16(c.R);
}
else
mask[3] = 0;
if (ii - 1 >= 0)
{
c = img.GetPixel(ii - 1, jj);
mask[4] = Convert.ToInt16(c.R);
}
else
mask[4] = 0;
if (ii - 1 >= 0 && jj + 1 < img.Height)
{
c = img.GetPixel(ii - 1, jj + 1);
mask[5] = Convert.ToInt16(c.R);
}
else
mask[5] = 0;
if (jj + 1 < img.Height)
{
c = img.GetPixel(ii, jj + 1);
mask[6] = Convert.ToInt16(c.R);
}
else
mask[6] = 0;
if (ii + 1 < img.Width && jj + 1 < img.Height)
{
c = img.GetPixel(ii + 1, jj + 1);
mask[7] = Convert.ToInt16(c.R);
}
else
mask[7] = 0;
c = img.GetPixel(ii, jj);
mask[8] = Convert.ToInt16(c.R);
Array.Sort(mask);
int mid = mask[4];
img.SetPixel(ii, jj, Color.FromArgb(mid, mid, mid));
}
}
pictureBox1.Image = img;
MessageBox.Show("Complete");
}
4条答案
按热度按时间yx2lnoni1#
正如在注解中提到的,要在
Bitmap
中更改像素,使其具有比SetPixel
更好的性能,可以使用Bitmap.LockBits
方法访问位图数据。若要以最少的变更使程式码更快,您可以建立类别,使用
LockBits
封装位图数据的快速存取,并为类别建立GetPixel
和SetPixel
方法。***注意:****答案只是尝试通过应用最少的更改来提高代码的速度。它不会在算法中应用任何增强功能来更好地减少噪音。*示例
例如,我使用了一个由Vano Maisuradze编写的类,并做了一些小的修改(我从代码中删除了不必要的try/catch块)。该类使用
LockBits
方法,并提供了GetPixel
和SetPixel
方法的快速版本。然后您的代码应更改为:
以下是类别的实作:
kmb7vmvb2#
正如你所发现的,使用AForge.NET是一个好主意(你只需要把它作为一个nuget来添加),我建议你使用它的Median filter,它经常被用于去噪(参见wikipedia中的Median Filter)。
AForge需要24 bpp的RGB图像,因此在示例中需要首先转换它,但下面的代码示例似乎在它上面运行得相当好:
如果你真的需要高性能,那么你可以选择NVidia CUDA/NPP(直接使用GPU),但这需要更多的工作,C#不直接支持(当然需要NVidia卡)。2D CUDA median filter optimization以及有关CUDA的白色,请访问:Image Processing and Video Algorithms with CUDA
nnsrf1az3#
你的代码取了9个附近像素的中值,实际上只是模糊。这不是一个好的降噪算法--它更像是一个模糊算法。研究你的解决方案需要哪种降噪算法(取决于你的噪声类型),然后从那里开始。
of1yzvn44#
在处理另一个项目时发现,无需将图像转换为位图,然后使用Get泛指el和Set泛指el函数,只需将图像转换为位图以调用Get泛指el和Set泛指el函数即可。这样效率更高,使用的内存也少得多。**示例:**使用
((Bitmap)pictureBox1.Image).GetPixel(ii-1,jj-1);
而不是img.GetPixel(ii - 1, jj - 1);