MPI 中的图像处理
Image processing in MPI
这是我尝试在 MPI 中编写经典平滑像素平均算法的代码。我几乎让它工作了,但是光晕交换发生了一些奇怪的事情,因为可以看到边缘的线条。我似乎找不到错误。我是否正确地交换了光环?我应该收集最终数组的哪一部分?
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 进程上 运行 时输出如下所示。我可以清楚地看到分隔线。出于这个原因,我认为我没有正确地进行光环交换。
好的,所以这里有很多问题。
首先,您的代码只能使用 d=1,因为您只交换深度为 1 的光晕。如果要处理距离为 d 的邻居,则需要交换深度为 d 的光晕。
其次,您在第一次扫描数组后进行第一次光环交换,因此您正在读取迭代 1 上的垃圾光环数据 - 您需要在执行之前进行光环交换开始处理您的数组。
第三,当您从索引 2 开始将新的复制回旧的时:您需要包括从 1 到 lrows 和 1 到 lcols 的所有像素。
最后,你的Imin、Imax等逻辑似乎是错误的。您不想 t运行cate 并行程序边缘的范围 - 您需要离开边缘以获取光晕数据。我只是设置 Imin = -d, Imax = d 等等
通过这些修复,代码似乎 运行 OK,即没有明显的光环效应,但它仍然在不同数量的进程上给出不同的结果。
PS 看到您使用了我自己的一个 MPI 示例中的 "arraymalloc2d" 代码 - http://www.archer.ac.uk/training/course-material/2018/07/intro-epcc/exercises/cfd.tar.gz ,我也很受宠若惊;我很高兴看到这些培训代码被证明对人们有用!
这是我尝试在 MPI 中编写经典平滑像素平均算法的代码。我几乎让它工作了,但是光晕交换发生了一些奇怪的事情,因为可以看到边缘的线条。我似乎找不到错误。我是否正确地交换了光环?我应该收集最终数组的哪一部分?
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 进程上 运行 时输出如下所示。我可以清楚地看到分隔线。出于这个原因,我认为我没有正确地进行光环交换。
好的,所以这里有很多问题。
首先,您的代码只能使用 d=1,因为您只交换深度为 1 的光晕。如果要处理距离为 d 的邻居,则需要交换深度为 d 的光晕。
其次,您在第一次扫描数组后进行第一次光环交换,因此您正在读取迭代 1 上的垃圾光环数据 - 您需要在执行之前进行光环交换开始处理您的数组。
第三,当您从索引 2 开始将新的复制回旧的时:您需要包括从 1 到 lrows 和 1 到 lcols 的所有像素。
最后,你的Imin、Imax等逻辑似乎是错误的。您不想 t运行cate 并行程序边缘的范围 - 您需要离开边缘以获取光晕数据。我只是设置 Imin = -d, Imax = d 等等
通过这些修复,代码似乎 运行 OK,即没有明显的光环效应,但它仍然在不同数量的进程上给出不同的结果。
PS 看到您使用了我自己的一个 MPI 示例中的 "arraymalloc2d" 代码 - http://www.archer.ac.uk/training/course-material/2018/07/intro-epcc/exercises/cfd.tar.gz ,我也很受宠若惊;我很高兴看到这些培训代码被证明对人们有用!