执行三个嵌套for循环的最快方法是什么?

时间:2017-02-10 08:14:12

标签: c++ opencv image-processing parallel-processing gpu-programming

我是一名图像处理程序员,我正在使用opencv C ++。作为我写的程序的一部分,我有三个嵌套。第一个用于不同的图像,第二个用于图像行,第三个用于图像列。三个之间没有任何依赖关系,并且它们可以并行(我的意思是,所有图像的所有像素都可以并行处理)。我不熟悉并行编程,GPU编程,线程,tbb,并行for循环和.......我发现互联网上有不同的链接提出了这样的建议。我想知道什么是我的问题最快的解决方案? 我的操作系统是Windows,我正在使用visual studio 2015。

我的代码如下:

int prjResCol[MAX_NUMBER_OF_PROJECTOR];
int prjResRow[MAX_NUMBER_OF_PROJECTOR];
Mat prjCamCor[MAX_NUMBER_OF_PROJECTOR][2]
Mat prjImgColored[MAX_NUMBER_OF_PROJECTOR];

for (int i = 0; i < numOfProjector; i++)
{
    Mat tmp(prjResRow[i], prjResCol[i], CV_8UC3, Scalar(0, 0, 0));
    prjImgColored[i] = tmp;

    for (int ii = 0; ii < prjResRow[i]; ii++)
    {
        double* ptrPrjCamIAnd0 = prjCamCor[i][0].ptr<double>(ii);
        double* ptrPrjCamIAnd1 = prjCamCor[i][1].ptr<double>(ii);
        Vec3b* ptrPrjImgColoredI = prjImgColored[i].ptr<Vec3b>(ii);

        for (int jj = 0; jj < prjResCol[i]; jj++)
        {

            if ((ptrPrjCamIAnd0[jj] != NAN_VALUE) && (ptrPrjCamIAnd1[jj] != NAN_VALUE))
            {
                ptrPrjImgColoredI[jj] = secondImgColored.at<Vec3b>(ptrPrjCamIAnd1[jj], ptrPrjCamIAnd0[jj]);
            }

        }
    }
    imwrite(mainAdr + "\\img" + to_string(i) + ".bmp", prjImgColored[i]);
}

1 个答案:

答案 0 :(得分:0)

正如您所写,使用Parallel For循环迭代像素将是大图像的最快方式。使用并行算法时会有一些开销,因此对于小图像(例如256 X 256),您可能会更好地使用您发布的传统循环。

以下是用Visual C ++编写的示例:

// Calls the provided function for each pixel in a Bitmap object.
void ProcessImage(Bitmap* bmp, const function<void (DWORD&)>& f)
{
   int width = bmp->GetWidth();
   int height = bmp->GetHeight();

   // Lock the bitmap.
   BitmapData bitmapData;
   Rect rect(0, 0, bmp->GetWidth(), bmp->GetHeight());
   bmp->LockBits(&rect, ImageLockModeWrite, PixelFormat32bppRGB, &bitmapData);

   // Get a pointer to the bitmap data.
   DWORD* image_bits = (DWORD*)bitmapData.Scan0;

   // Call the function for each pixel in the image.
   parallel_for (0, height, [&, width](int y)
   {      
      for (int x = 0; x < width; ++x)
      {
         // Get the current pixel value.
         DWORD* curr_pixel = image_bits + (y * width) + x;

         // Call the function.
         f(*curr_pixel);
      }
   });

   // Unlock the bitmap.
   bmp->UnlockBits(&bitmapData);
}

您可以采用另一种方法来并行化您的工作流程,您可以同时对多个图像执行单线程(双循环)迭代。下面是用C#编写的示例。您只需要将您的串行双循环替换为位图翻转例程。使用适当的并行库,C ++实现应该非常相似:

//用于演示目的的简单来源。根据需要修改此路径。         String [] files = System.IO.Directory.GetFiles(@“C:\ Users \ Public \ Pictures \ Sample Pictures”,“* .jpg”);         String newDir = @“C:\ Users \ Public \ Pictures \ Sample Pictures \ Modified”;         System.IO.Directory.CreateDirectory(NEWDIR);

    // Method signature: Parallel.ForEach(IEnumerable<TSource> source, Action<TSource> body)
    // Be sure to add a reference to System.Drawing.dll.
    Parallel.ForEach(files, (currentFile) => 
    {
        // The more computational work you do here, the greater 
        // the speedup compared to a sequential foreach loop.
        String filename = System.IO.Path.GetFileName(currentFile);
        var bitmap = new Bitmap(currentFile);

        bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone);
        bitmap.Save(Path.Combine(newDir, filename));

        // Peek behind the scenes to see how work is parallelized.
        // But be aware: Thread contention for the Console slows down parallel loops!!!

         Console.WriteLine("Processing {0} on thread {1}", filename, Thread.CurrentThread.ManagedThreadId);
         //close lambda expression and method invocation
         });

Open CV支持parallel For至少版本2.4.3。通过使用并行循环,您可以利用多核CPU的功能,其中每个核心将迭代图像的单独子部分。

OpenCV还支持CUDA,这是由NVIDA创建的并行处理API,可利用GPU的强大功能。我不认为这种方法是解决这个特定问题的方法,但是既然你提到你是一个图像处理程序员,那么它就值得研究未来的问题。