C#卷积滤波器适用于任何尺寸矩阵(1×1,3×3,5×5,…)未完全应用

我正在为我的项目制作一个卷积滤波器,我设法为任何大小的矩阵制作它,但随着它变大,我注意到并非所有的位都被改变了。 以下是显示问题的图片:

第一个是原件 在此处输入图像描述 过滤:模糊9×9

filter:EdgeDetection 9×9: 在此处输入图像描述

正如你所看到的,有一条小条纹永远不会改变,随着矩阵变大,条纹也会变大(3×3不可见)

我的卷积矩阵类:

public class ConvMatrix { public int Factor = 1; public int Height, Width; public int Offset = 0; public int[,] Arr; //later I assign functions to set these variables ... } 

过滤function:

  Bitmap Conv3x3(Bitmap b, ConvMatrix m) { if (0 == m.Factor) return b; Bitmap bSrc = (Bitmap)b.Clone(); BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); BitmapData bmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); int stride = bmData.Stride; System.IntPtr Scan0 = bmData.Scan0; System.IntPtr SrcScan0 = bmSrc.Scan0; unsafe { byte* p = (byte*)(void*)Scan0; byte* pSrc = (byte*)(void*)SrcScan0; int nOffset = stride - b.Width * m.Width; int nWidth = b.Width - (m.Size-1); int nHeight = b.Height - (m.Size-2); int nPixel = 0; for (int y = 0; y < nHeight; y++) { for (int x = 0; x < nWidth; x++) { for (int r = 0; r < m.Height; r++) { nPixel = 0; for (int i = 0; i < m.Width; i++) for (int j = 0; j < m.Height; j++) { nPixel += (pSrc[(m.Width * (i + 1)) - 1 - r + stride * j] * m.Arr[j, i]); } nPixel /= m.Factor; nPixel += m.Offset; if (nPixel  255) nPixel = 255; p[(m.Width * (m.Height / 2 + 1)) - 1 - r + stride * (m.Height / 2)] = (byte)nPixel; } p += m.Width; pSrc += m.Width; } p += nOffset; pSrc += nOffset; } } b.UnlockBits(bmData); bSrc.UnlockBits(bmSrc); return b; } 

请帮忙

问题是你的代码显然没有边缘。 外部循环( nWidthnHeight )限制的计算不应该涉及矩阵的大小,它们应该等于位图的大小。

执行此操作时,如果您想象在这种情况下将矩阵的中心点放在每个像素上时会发生什么(因为您需要从像素的所有大小读取),矩阵将部分位于边缘附近的图像之外。

关于在边缘附近做什么有几种方法,但合理的方法是将坐标夹到边缘。 即,当您最终从位图外部读取像素时,只需从边缘(大小或角落)获取最近的像素。

我也不明白为什么你需要五个循环 – 你似乎循环遍历矩阵的高度两次。 这看起来不对。 总而言之,一般结构应该是这样的:

 for (int y = 0; y < bitmap.Height; y++) { for (int x = 0; x < bitmap.Width; x++) { int sum = 0; for (int matrixY = -matrix.Height/2; matrixY < matrix.Height/2; matrixY++) for (int matrixX = -matrix.Width/2; matrixX < matrix.Width/2; matrixX++) { // these coordinates will be outside the bitmap near all edges int sourceX = x + matrixX; int sourceY = y + matrixY; if (sourceX < 0) sourceX = 0; if (sourceX >= bitmap.Width) sourceX = bitmap.Width - 1; if (sourceY < 0) sourceY = 0; if (sourceY >= bitmap.Height) sourceY = bitmap.Height - 1; sum += source[x, y]; } } // factor and clamp sum destination[x, y] = sum; } } 

您可能需要一个额外的循环来处理需要单独处理的每个颜色通道。 我无法立即看到你的代码中的哪些内容可能来自所有隐藏变量。