【问题标题】:Image processing in MPIMPI 中的图像处理
【发布时间】:2018-08-03 23:08:46
【问题描述】:

这是我在 MPI 中编写经典平滑像素平均算法的尝试。我几乎让它工作了,但是光环交换发生了一些奇怪的事情,因为可以看到边缘的线条。我似乎找不到错误。我是否正确交换光环?我应该收集最终数组的哪个部分?

https://pastebin.com/4rtFnSJ5

int next = rank + 1;
int prev = rank - 1;

if (next >= size) {
  next = MPI_PROC_NULL;
}

if (prev < 0) {
  prev = MPI_PROC_NULL;
}

int rows = y / px;
int cols = x;
int d = 1;

for (int iter = 0; iter < TotalIter; iter++) {
  for (int i = 0; i < rows + 2; i++)
    for (int j = 0; j < cols + 2; j++)
      for (int k = 0; k < rgb; k++)
        new[i][j * rgb + k] = 0;

  for (int i = 1; i < rows + 1; i++) {

    int iMin = -min(d, i - 1);
    int iMax = min(d, (rows + 1 - i - 1));

    for (int j = 1; j < cols + 1; j++) {
      int jMin = -min(d, j - 1);
      int iMax = min(d, (cols + 1 - j - 1));

      int counter = 0;

      for (int p = iMin; p <= iMax; p++)
        for (int q = jMin; q <= jMax; q++) {
          counter = counter + 1;
          for (int k = 0; k < rgb; k++) {
            new[i][j * rgb + k] += old[i + p][(j + q) * rgb + k];
          }
        }

      for (int k = 0; k < rgb; k++) {
        new[i][j * rgb + k] -= old[i][j * rgb + k];
        new[i][j * rgb + k] /= (counter - 1);
      }
    }
  }

  for (int i = 2; i < rows; i++)
    for (int j = 2; j < cols; j++)
      for (int k = 0; k < rgb; k++) {
        old[i][j * rgb + k] = new[i][j * rgb + k];
      }

  MPI_Sendrecv(&old[rows][1], cols * rgb, MPI_INT, next, 1, &old[0][1],
               cols * rgb, MPI_INT, prev, 1, MPI_COMM_WORLD, &status);

  MPI_Sendrecv(&old[1][1], cols * rgb, MPI_INT, prev, 2, &old[rows + 1][1],
               cols * rgb, MPI_INT, next, 2, MPI_COMM_WORLD, &status);
}

 for (int i = 1; i< rows+1; i++)
    for (int j = 1; j< cols+1; j++)
        for (int k = 0; k< rgb; k++) {
           buf[i-1][(j-1)*rgb+k] =  old[i][j*rgb+k] ;
         }

MPI_Gather(&buf[0][0], rows *cols *rgb, MPI_INT, &Finalbuffer[0][0],
           rows *cols *rgb, MPI_INT, 0, MPI_COMM_WORLD);

在 8 个 MPI 进程上运行时的输出如下所示。我可以清楚地看到分界线。出于这个原因,我认为我没有正确地进行光环交换。

【问题讨论】:

  • 初始化中有一个错误 - new[i][j x rgb+c] = 0 应该是“+k”。你没有给我们足够的信息来调试代码,因为你没有说,例如,什么是“prev”和“next”。但是,我的猜测是收集是错误的 - 你想收集旧数组的 interior (不包括光环),但你实际上是收集从 [0][0] 开始的部分还包括一些光晕和边缘数据。
  • @DavidHenty 谢谢。我已经更新了我的问题并修正了错字。你说得对,收集似乎是错误的,但我对收集什么感到困惑。这应该是MPI_Gather(&amp;old[1][1], rows*cols*rgb, MPI_INT, &amp;Finalbuffer[0][0], rows*cols*rgb , MPI_INT, 0, MPI_COMM_WORLD);
  • 请编辑您的帖子并添加minimal reproducible example。同时,仔细检查您的数据是否在连续内存中。
  • 这不起作用,因为收集将收集连续的数据,并且“旧”区域的核心(即不包括光环的中心)不连续。正如@GillesGouaillardet 指出的那样,解决方案取决于原始数组是否是连续分配的(如果您使用了“malloc”,它们可能不是)。
  • @DavidHenty 数组是连续分配的。我必须说这仅适用于 1 等级。使用多个等级时,我可以看到划分分解的线。然而,图像是正确构建的,但并不完全相同。

标签: mpi


【解决方案1】:

好的,这里有很多问题。

首先,您的代码只能使用 d=1,因为您只交换深度为 1 的光晕。如果您想处理距离为 d 的邻居,则需要交换深度为 d 的光晕。

其次,您在第一次扫描数组之后进行第一次光环交换,因此您在第 1 次迭代中读取垃圾光环数据 - 您需要在开始处理数组之前进行光环交换。

第三,当你从索引 2 开始复制新到旧时:你需要包括从 1 到 lrows 和 1 到 lcols 的所有像素。

最后,您的 Imin、Imax 等逻辑似乎是错误的。您不想在并行程序中截断边缘的范围 - 您需要离开边缘以获取光环数据。我只是设置了 Imin = -d、Imax = d 等。

通过这些修复,代码似乎运行良好,即没有明显的光环效应,但它仍然在不同数量的进程上给出不同的结果。

PS 我也很高兴看到您使用了我自己的 MPI 示例之一中的“arraymalloc2d”代码 - http://www.archer.ac.uk/training/course-material/2018/07/intro-epcc/exercises/cfd.tar.gz;我很高兴看到这些培训代码被证明对人们有用!

【讨论】:

  • @_David Henty 我无法修复它。您介意分享您的更改吗?理论上,所有输出都应该相同。我不明白...
  • 我正在检查我的代码,它为多个进程生成了无效图像。我重新运行了您的原始代码并获得了相同的效果。您能否让我访问您的测试 PNG 输入文件并准确说明您在运行时使用的参数?
  • @_David Henty 运行此./binary input.png output.png 25 1。我上面上传的PNG文件你不能用吗?
猜你喜欢
  • 1970-01-01
  • 2014-01-01
  • 1970-01-01
  • 2010-11-11
  • 1970-01-01
  • 2021-08-23
  • 2021-12-20
  • 2023-03-03
  • 2012-03-24
相关资源
最近更新 更多