【问题标题】:Convolutional algorithm logic [closed]卷积算法逻辑
【发布时间】:2018-05-17 08:56:29
【问题描述】:

好的,所以我正在尝试在 EmguCv 中实现我自己的卷积算法(这是一项要求)。过滤似乎无法正常工作。结果并非例外。我的算法中的错误在哪里?这是我到目前为止所做的:

            int L = 3;

            double kernelTopLeft = kernel[0 + L * 0];
            double kernelTopCenter = kernel[1 + L * 0];
            double kernelTopRight = kernel[2 + L * 0];
            double kernelCenterLeft = kernel[0 + L * 1];
            double kernelCenter = kernel[1 + L * 1];
            double kernelCenterRight = kernel[2 + L * 1];
            double kernelBottomLeft = kernel[0 + L * 2];
            double kernelBottomCenter = kernel[1 + L * 2];
            double kernelBottomRight = kernel[2 + L * 2];

                for (int bNumber = 0; bNumber < 3; bNumber++)
                {
                    for (int j = 1; j < img.Width - 1; j++)
                    {
                        for (int i = 1; i < img.Height - 1; i++)
                        {

                           //Getting pixels in 3x3 Window

                            double topLeft = img.Data[(i - 1), (j - 1), bNumber];
                            double centerLeft = img.Data[(i - 1), (j), bNumber];
                            double bottomLeft = img.Data[(i - 1), (j + 1), bNumber];
                            double topCenter = img.Data[(i), (j - 1), bNumber];
                            double center = img.Data[(i), (j), bNumber];
                            double bottomCenter = img.Data[(i), (j + 1), bNumber];
                            double topRight = img.Data[(i + 1), (j - 1), bNumber];
                            double centerRight = img.Data[(i + 1), (j), bNumber];
                            double bottomRight = img.Data[(i + 1), (j + 1), bNumber];

                            //Kernel operation is kernel window * pixel window (multiplication is mirrored)

                            double newValue = bottomRight * kernelTopLeft + bottomCenter * kernelTopCenter + bottomLeft * kernelTopRight +
                                              centerRight * kernelCenterLeft + center * kernelCenter + centerLeft * kernelCenterRight +
                                              topRight * kernelBottomLeft + topCenter * kernelBottomCenter + topLeft * kernelBottomRight;

                            if (newValue > 255)
                            {
                                newValue = 255;
                            }
                            else if (newValue < 0)
                            {
                                newValue = 0;
                            }

                            img.Data[(i), (j), bNumber] = (byte)newValue;
                        }
                    }
                }

我的算法实际上是在整个图像上移动一个 3x3 的窗口,并将其与内核相乘以得到中间像素的值,然后继续直到达到最终值。

【问题讨论】:

  • 有趣的算法,但完全跑题了。。你只是粘贴了一堆代码并说它不起作用,没有解释原因的线索
  • 真的很抱歉。我现在会更新帖子。我有点着急,我似乎无法弄清楚如何调试它。
  • 您正在更新img 中的数据,以便下一个3x3 区域的操作将使用img 中的新值作为左上角的像素集。你确定这是你想要的吗?您不应该将新像素写入新数组以使img 保持不变吗?除非您正在执行错误扩散或其他需要从一个内核进位到下一个内核的操作。
  • 引用wikipedia输出图像中给定像素的值是通过将每个内核值乘以相应的输入图像来计算的像素值。” (强调我的)
  • 至于调试,我建议创建一个特定的 4x4 图像并使用老式的 pen 'n' 纸手工计算出预期值:P

标签: c# image-processing filtering emgucv convolution


【解决方案1】:

正如我在 cmets 中所说,您似乎正在计算新的像素值,然后使用新值更新原始的 img.Data[]。这意味着当您浏览图像时,每个内核都使用右侧和下方行(您尚未处理)的像素的原始值,并使用中心左侧像素的新值并在上面的行中(您已经处理过)。

对于卷积,每个内核应该只考虑图像的原始值。引用Wikipedia:

输出图像中给定像素的值是通过将每个内核值乘以相应的输入图像像素值来计算的。

请注意,在某些形式的图像处理中,您确实会以某种形式将数据从一个内核传送到下一个内核。 Error diffusionFloyd–Steinberg dithering 要求将每个像素的错误值拆分并添加到尚未处理的像素中,但这通常通过更改输入图像中的像素来完成。

要修复它,请为输出创建一个相同大小的新“图像”,并在循环结束时更新它。

希望对你有帮助

【讨论】: