如何在编写侵蚀过滤器时正确创建循环?

How can I create the loop properly while writing erosion filter?

我正在尝试编写侵蚀 filter.I 尝试确定我更改的部分,但我想填充其他数组元素 255.How 我可以这样做吗?

public static byte[] dnmmmerosion(byte[] data)
        {
            int wdth = 2400;
            int hght = 800;

            List<byte> dnmbytee = new List<byte>();

            byte[] dnmbyte = new byte[1200000];
            for (int i = 0; i < 1200000; i++)
            {
                dnmbytee[i] = 255;
            }   


            for (int k = 1; k < hght-1; k++)
            {
                for (int vvv = 0; vvv < wdth-1; vvv++)
                {
                    if (data[k+vvv] == 0 && data[k *wdth+vvv] == 0)
                    {
                        if (data[k * wdth + (vvv+1)] == 0 && data[k * wdth + vvv+2] == 0)
                        {
                            if (data[(k + 1) * wdth + vvv] == 0)
                            {
                                dnmbytee[k * wdth + vvv+1] = 0;
                            }
                        }
                    }
                }
            }

            for (int zzz = 0; zzz < 1200000; zzz++)
            {
                dnmbyte[zzz] = dnmbytee[zzz];
            }

            return dnmbyte;
        }

我的意思是我填充的元素在上面(比如:data[k+vvv] == 0,...)我想我在创建循环时在系数方面犯了错误

PS:我这样写代码的时候看到的画面很呆板

我正在对二进制图像进行处理。(因此数组由 255 和 0 元素组成。)如果结构的元素与图像中的元素相同(例如 elements:1,2,3 ,4,5) 将 255 写入第 3 个元素。

我不懂 C#,所以不会在代码中解决一些我不理解的问题。

首先你设置

int wdth = 2400;
int hght = 800;

然后为输出缓冲区分配 1,200,000 字节。这意味着您循环了 2400 x 800 = 1,920,000 字节,这大大超出了您的缓冲区。我认为您打算改为设置 hght = 500 。为避免此类问题,请不要多次使用相同的数值,而是定义可在代码中使用的常量:

int channels = 3;
int width = 800;   // let's not be lazy, and use real words as variable names!
int height = 500;
int buffer_size = channels * width * height;

byte[] dnmbyte = new byte[buffer_size];
for (int i = 0; i < buffer_size; i++)
...

接下来,我不确定为什么你需要中间缓冲区dnmbytee,为什么你不能直接写入dnmbyte。不知道 C# 中的 List 是什么,我假设它不是一个数组,而是一个实际的列表数据结构。像你这样使用它会非常昂贵,请坚持使用数组来获取像素数据!

最后,主要问题:您正在访问缓冲区,就好像您有 2400 x 500 像素,每个像素一个字节,而不是 800 x 500 像素,每个像素三个字节 (RGB)。形态学操作在彩色图像上没有很好的定义,所以我在这里假设一个像素的所有三个字节总是相同的。如果是,则读取每个像素的第一个字节,并写入所有三个字节。

为此,您将像这样循环和索引:

for (int y = 1; y < height-1; y++) {   // loop over all rows except the top and bottom-most ones
   for (int x = 1; x < width-1; x++) { // loop over all columns, except the left and right-most ones
      int current_pixel_index = (y * width + x) * channels;
      // read at data[current_pixel_index]
      ...
      dnmbyte[current_pixel_index + 0] = 0;
      dnmbyte[current_pixel_index + 1] = 0;
      dnmbyte[current_pixel_index + 2] = 0;
   }
}

要访问相邻像素,您始终将相同的值添加到当前像素索引:channels 使像素位于右侧,-width*channels 使像素位于顶部,等等。为结构元素中的每个像素创建一个列表,然后遍历该列表:

int[5] neighbors;
neighbors[0] = -width*channels;
neighbors[1] = -channels;
neighbors[2] = 0;
neighbors[3] = +channels;
neighbors[4] = +width*channels;

for (int y = 1; y < height-1; y++) {
   for (int x = 1; x < width-1; x++) {
      int current_pixel_index = (y * width + x) * channels;
      for (int k = 0; k < 5; k++) {
         // read at data[current_pixel_index + neighbors[k]]
      }
   }
}

腐蚀逻辑可以是这样的:

for (int k = 0; k < 5; k++) {
   if (data[current_pixel_index + neighbors[k]] == 0) {
      dnmbyte[current_pixel_index + 0] = 0;
      dnmbyte[current_pixel_index + 1] = 0;
      dnmbyte[current_pixel_index + 2] = 0;
      break;
   }
}

由于输出数组初始化为 255,如果 none 个邻居为 0,它将保持该值。

上面的代码没有设置图像边缘的任何像素(第一行和最后一行和列)。如果你也想处理这些,最简单的方法是在所有边上用一个像素填充输入,新像素的值应该为 255。另一种方法是在边缘像素处进行特殊处理,确保你不要试图越界读取。这种类型的处理往往会大大降低代码速度,也会使代码复杂化。填充通常是值得的!