【问题标题】:3X3 Median Filtering in c# but not working?c#中的3X3中值过滤但不起作用?
【发布时间】:2015-11-13 23:32:21
【问题描述】:

真的,我正在尝试通过 C# 应用 3X3 中值过滤,根据我对中值过滤概念的理解,我编写了以下代码,但是当我运行它时,表单挂起。我认为在最后一个嵌套的 for 循环中有一些问题,但我不知道应用中位数概念的错误或错误在哪里!

public static Bitmap MedianFiltering(Bitmap bm)
    {
        List<int> termsList = new List<int>();
        Bitmap res, temp;
        Color c;
        int counter = 0;

        //Convert to Grayscale 
        for (int i = 0; i < bm.Width; i++)
        {
            for (int j = 0; j < bm.Height; j++)
            {
                c = bm.GetPixel(i, j);
                byte gray = (byte)(.333 * c.R + .333 * c.G + .333 * c.B);
                bm.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
            }
        }

        temp = bm;

       //applying Median Filtering 
        for (int i = 0; i <= temp.Width - 3; i++)
            for (int j = 0; j <= temp.Height - 3; j++)
            {
                for (int x = i; x <= i + 2; x++)
                    for (int y = j; y <= j + 2; y++)
                    {

                        c = temp.GetPixel(x, y);
                        termsList.Add(c.R);
                        counter++;
                    }
                int[] terms = termsList.ToArray();
                Array.Sort<int>(terms);
                Array.Reverse(terms);
                int color = terms[4];
                temp.SetPixel(i + 1, j + 1, Color.FromArgb(color, color, color));
                counter = 0;
            }
        res = temp;

        return res;
    }

谢谢。

【问题讨论】:

  • 如果您在 UI 线程上运行此代码(例如,从按钮处理程序),UI 挂起是正常的。但它应该只挂起,直到中值滤波器计算完成。您可以使用异步方法使表单在计算过程中不挂起。
  • 我现在试过了,在这一行! temp.SetPixel(i + 1, j + 1, Color.FromArgb(color, color, color));
  • 所以它完全挂了?如果您等待足够的时间,它会完成吗?
  • 我等了 5 分钟以上,结果相同
  • 5分钟后有进展吗?将Debug.WriteLine(i + ", " + j); 放在temp.SetPixel(i + 1, j + 1,.... 行之后。这会将当前像素坐标输出到输出窗口(在 Visual Studio 中查看 -> 输出)。这样,您可以查看程序是否仍在运行。

标签: c# .net image-processing


【解决方案1】:

您没有在每次像素处理后清除termsList。这导致列表不断增长。对列表进行排序和反转将花费越来越长的时间。这也会导致不正确的结果,因为您只想获取与当前像素相关的 9 个像素的中位数。

像这样简单地清除列表:

...
int[] terms = termsList.ToArray();
termsList.Clear();
...

更新:

我对代码做了更多优化:

public static void MedianFiltering(Bitmap bm)
{
    List<byte> termsList = new List<byte>();

    byte[,] image = new byte[bm.Width,bm.Height];

    //Convert to Grayscale 
    for (int i = 0; i < bm.Width; i++)
    {
        for (int j = 0; j < bm.Height; j++)
        {
            var c = bm.GetPixel(i, j);
            byte gray = (byte)(.333 * c.R + .333 * c.G + .333 * c.B);
            image[i, j] = gray;
        }
    }

    //applying Median Filtering 
    for (int i = 0; i <= bm.Width - 3; i++)
        for (int j = 0; j <= bm.Height - 3; j++)
        {
            for (int x = i; x <= i + 2; x++)
                for (int y = j; y <= j + 2; y++)
                {
                    termsList.Add(image[x, y]);
                }
            byte[] terms = termsList.ToArray();
            termsList.Clear();
            Array.Sort<byte>(terms);
            Array.Reverse(terms);
            byte color = terms[4];
            bm.SetPixel(i + 1, j + 1, Color.FromArgb(color, color, color));
        }
}

请注意,在您的原始方法中,您返回了 Bitmap。我删除了这个。

请注意temp = bm; 不会创建Bitmap 的副本。它只是将temp 变量指向同一个对象(由bm 指向)。因此,在您的原始方法中,您返回了在方法参数中传递的确切对象。要使用新方法,请传递Bitmap,然后将修改它自己的位图(这也适用于您的方法)。

这在我的机器上提高了 4 倍的性能。

我所做的主要是将位图数据读入字节数组,而不是使用Bitmap它自己多次读/写数据。

如果您需要进一步提升性能,请查看this question

【讨论】:

  • 它现在工作得更快了,我大概等了 5 分钟才得到结果,但我想做一些东西来应用它以提高性能,你有什么建议吗?
  • 奇怪。 5分钟太多了。输入图像有多大?宽度和高度是多少?
  • 我将您的代码(在添加 termsList.Clear() 后)绑定到大小为 1013x699 的图像上。在我的机器上大约需要 8 秒。虽然还有改进的余地,但在你的机器上为什么要花 5 分钟还是很奇怪。
  • 我正在 Mac 上的 windows 虚拟机上工作,这有什么影响吗?我现在尝试了一张 500x333 的图像,需要 2.5 分钟
  • 回答您的问题:是的。虚拟机几乎总是比真实的慢。
猜你喜欢
  • 2011-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-15
  • 1970-01-01
相关资源
最近更新 更多