C++ 位图上的并发腐蚀或扩展

C++ 位图上的并发腐蚀或扩展,c++,algorithm,image-processing,concurrency,openmp,C++,Algorithm,Image Processing,Concurrency,Openmp,我需要在位图上做一个形态学操作(一个专门的扩展/腐蚀版本)。 为了加快速度,我正在使用openmp并行化进程: int* bitmap = ...; // pointer to bitmap data with width and height #pragma omp parallel for for(long iy=0; iy<height; iy++) for(long ix=0; ix<width; ix++)

我需要在位图上做一个形态学操作(一个专门的扩展/腐蚀版本)。 为了加快速度,我正在使用openmp并行化进程:

  int* bitmap = ...;              // pointer to bitmap data with width and height
#pragma omp parallel for
   for(long iy=0; iy<height; iy++) 
      for(long ix=0; ix<width; ix++) 
         if(write_pattern(ix,iy)) 
            apply_pattern(ix,iy, 0);   // writes "0" to bitmap, write only, no read
int*位图=…;//指向具有宽度和高度的位图数据的指针
#pragma-omp并行

对于(long iy=0;iy我不太介意并行化,但我想指出,并行化膨胀/侵蚀并不是我在这里的首选

通过膨胀/侵蚀,您可以对像素周围的结构元素执行最大/最小操作。例如,如果您有一个5x5窗口,您可以查看每个像素的25个像素,因此本质上您可以查看每个像素25次。因此,每个像素的计算复杂度与pixe中结构元素的大小成正比我对这种幼稚的方法很感兴趣

使用更高效的算法计算形态算子,你可以降低这种复杂性,甚至可以降低到恒定的复杂性(每像素),而不管结构元素的大小。有很多关于这方面的文献,我在最后包括了一些参考文献,他们还引用了其他论文并进行了比较

我不知道您所处的环境,以及性能有多重要。但并行化将是我所做的最后一步。首先,我会让算法运行,而不管性能如何。一旦我对此感到满意(或者对运行时感到恼火,我愿意做些事情),我改进为一个更高效的解算器。如果最后,我仍然需要稍微推动运行时,我会并行化(或者考虑使用GPU是否有意义)

如果你现在进行并行化,你可能会得到一些加速,但是你会在提高性能的算法改进上失败

现在,正如承诺的那样,两篇关于高效形态过滤器的论文: 提出了一种基于结构元素的O(1)算法,并对经典的有效算法进行了比较/引用。
看起来也不错。我还没有详细阅读,但我在我的研究领域认识Ron Kimmel,这可能是一本不错的书。

我不太介意并行化,但我想指出,并行化膨胀/侵蚀不是我在这里选择的第一选择

通过膨胀/侵蚀,您可以对像素周围的结构元素执行最大/最小操作。例如,如果您有一个5x5窗口,您可以查看每个像素的25个像素,因此本质上您可以查看每个像素25次。因此,每个像素的计算复杂度与pixe中结构元素的大小成正比我对这种幼稚的方法很感兴趣

使用更高效的算法计算形态算子,你可以降低这种复杂性,甚至可以降低到恒定的复杂性(每像素),而不管结构元素的大小。有很多关于这方面的文献,我在最后包括了一些参考文献,他们还引用了其他论文并进行了比较

我不知道您所处的环境,以及性能有多重要。但并行化将是我所做的最后一步。首先,我会让算法运行,而不管性能如何。一旦我对此感到满意(或者对运行时感到恼火,我愿意做些事情),我改进为一个更高效的解算器。如果最后,我仍然需要稍微推动运行时,我会并行化(或者考虑使用GPU是否有意义)

如果你现在进行并行化,你可能会得到一些加速,但是你会在提高性能的算法改进上失败

现在,正如承诺的那样,两篇关于高效形态过滤器的论文: 提出了一种基于结构元素的O(1)算法,并对经典的有效算法进行了比较/引用。
看起来也不错。我还没有详细阅读过它,但我在我的研究领域认识Ron Kimmel,这可能是一本不错的书。

OpenMP是一种共享内存范例。如果你能保证你所有的不同进程都会将相同的值写入相同的位置,那么让它们这样做是可以的。有竞争条件,但ey不会影响结果

这为您提供了以下代码:

int* bitmap = ...;              // pointer to bitmap data with width and height

#pragma omp parallel for collapse(2)
for(long iy=0; iy<height; iy++) 
for(long ix=0; ix<width; ix++) 
  if(write_pattern(ix,iy)) 
    apply_pattern(ix,iy, 0);   // writes "0" to bitmap, write only, no read

如果写入成本很高,您可以对
模式的内容进行一些处理,以合并写入、消除冗余写入、对写入进行拓扑排序等。

OpenMP是一种共享内存模式。如果您可以保证所有不同的进程都将相同的值写入相同的位置,那么就可以了有比赛条件,但不会影响比赛结果

这为您提供了以下代码:

int* bitmap = ...;              // pointer to bitmap data with width and height

#pragma omp parallel for collapse(2)
for(long iy=0; iy<height; iy++) 
for(long ix=0; ix<width; ix++) 
  if(write_pattern(ix,iy)) 
    apply_pattern(ix,iy, 0);   // writes "0" to bitmap, write only, no read

如果书写成本很高,您可以对
模式的内容进行一些处理,以合并写入、消除冗余写入、对写入进行拓扑排序,&c.

您描述的内容听起来不正常-但如果没有一个具体的答案,就不可能给出具体的答案。您描述的内容听起来不正常-但不可能给出具体的答案没有一个。很好的答案。算法在大多数情况下在性能上都优于并行性,尽管它们需要花费更多的精力来编写代码。虽然不是100%适用于我的问题,但它让我得出结论,将结构元素拆分为多个片段,这些片段的像素位于连续的内存位置。现在我并行处理这些片段。这使e以下优点:段不重叠(无快速写入)还有更好的缓存利用率。回答得好。算法在大多数情况下的性能都优于并行性,尽管它们需要花费更多的精力来编写代码。虽然不是100%适用于我的问题,但它让我得出结论,将结构元素拆分为多个片段,这些片段的像素位于连续的内存位置。现在我并行处理这些片段lel。这提供了以下优点:段不重叠(无快速写入)和更好的缓存利用率。我想简单总结一下这个答案:如果使用并行,不要
int* bitmap = ...;              // pointer to bitmap data with width and height

typedef std::pair<long,long> gridloc;
std::vector<gridloc> patterns;

//Use a custom reduction operator, available in newer versions of OpenMP
#pragma omp declare reduction (merge : std::vector<gridloc> : omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end()))
#pragma omp parallel for collapse(2) reduction(merge:patterns)
for(long iy=0; iy<height; iy++) 
for(long ix=0; ix<width; ix++) 
  if(write_pattern(ix,iy)) {
    patterns.emplace_back(ix,iy)
  }

for(const auto &c: patterns)
  apply_pattern(c.first,c.second, 0);   // writes "0" to bitmap, write only, no read