具有openmp并行的Qimage setPixel不能正常工作

时间:2018-05-15 23:36:12

标签: c++ qt parallel-processing openmp qimage

代码没有并行性,但是当我添加pragma omp parallel时,它不起作用。此外,如果我不添加setPixel,代码与pragma omp parallel完美配合。所以,我想知道为什么并行性不能正常工作,当我尝试在新图像中设置像素时,用代码255退出程序。此代码想要使用高斯向量更改执行两个循环的图像以更改每个像素。如果无法理解某些事情,我会立即解决。

for (h = 0; h < height; h++){
  QRgb* row = (QRgb*) result->scanLine(h);

  //#pragma omp parallel for schedule(dynamic) num_threads(cores) private (j, auxazul, auxrojo, auxverde) reduction(+:red,green,blue)
  for (w = 0; w < width; w++) {
      red=green=blue=0;

      minj = max((M-w),0);
      supj = min((width+M-w),N);
      for (j=minj; j<supj; j++){
          auxazul = azul [w-M+j][h];
          auxrojo = rojo [w-M+j][h];
          auxverde = verde [w-M+j][h];

          red += vectorGauss[j]*auxrojo;
          green += vectorGauss[j]*auxverde;
          blue += vectorGauss[j]*auxazul;
      }

      red /= 256; green /= 256; blue /= 256;
      //result->setPixel(w,h,QColor(red,green,blue).rgba());
      row[w] = QColor(red,green,blue).rgba();
  }

2 个答案:

答案 0 :(得分:1)

QImage :: setPixel不是线程安全的,因为它调用 detach()方法(查看官方文档here)。请记住,QImage使用隐式共享

此外, setPixel() 非常慢。如果您正在寻求性能(就像通常在处理并行实现时那样),那不是最好的方法。

正如您在提供的示例中所做的那样使用 scanLine()是正确的方法。

答案 1 :(得分:0)

除了注释setPixel很慢而且不是线程安全的,你在编写结果时当前有一个竞争条件

 row[w] = QColor(red,green,blue).rgba(); 

您的代码首先是缓慢的,因为您以低效的方式访问您的颜色矩阵。泵送螺纹会使这部件变得更糟。鉴于您在每条扫描线上循环,您希望拥有颜色矩阵的转置。允许你这样做:

for (h = 0; h < height; h++){
  QRgb* row = (QRgb*) result->scanLine(h);

  auto azulscan = azul [h];
  auto rojoscan = rojo [h];
  auto verdescan = verde [h];

  for (w = 0; w < width; w++) {
      red=green=blue=0;
      minj = max((M-w),0);
      supj = min((width+M-w),N);
      for (j=minj; j<supj; j++){
          auto auxazul = azulscan [w-M+j];
          auto  auxrojo = rojoscan [w-M+j];
          auto auxverde = verdescan [w-M+j];

          red += vectorGauss[j]*auxrojo;
          green += vectorGauss[j]*auxverde;
          blue += vectorGauss[j]*auxazul;
      }
      row[w] = QColor(red,green,blue).rgba();
  }

}

我不熟悉openmp但是你想要每个扫描线有一个线程,所以你的并行循环需要高于第一个循环。像

这样的东西
#pragma omp parallel for whatever
for (h = 0; h < height; h++){
  QRgb* row;

  #pragma omp critical
  {
    row = = (QRgb*) result->scanLine(h);
  }

  .... 

}

另一点。一旦转换了颜色输入,就可以使用std::inner_product计算单行中的颜色值。

green = std::inner_product(&vectorGauss[minj], &vectorGauss[supj-1]+1, &verdescan[w-M+jmin], &verdescan[w-M+supj]+1)