Qimage setPixel with openmp parallel for 不起作用

Qimage setPixel with openmp parallel for doesn't work

代码在没有并行性的情况下工作,但是当我添加 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();
  }

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

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

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

除了 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)