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



我是一名图像处理程序员,使用的是opencv C++。作为我编写的程序的一部分,我有三个嵌套。第一个用于不同的图像,第二个用于图像行,第三个用于图像列。三者之间没有任何依赖关系,它们可以非常并行(我的意思是,所有图像的所有像素都可以并行处理)。我不熟悉并行编程、GPU编程、线程、tbb、循环并行和。我在互联网上找到了不同的链接,这些链接暗示了这些事情。我想知道我的问题最快的解决方案是什么?我的操作系统是windows,我使用的是visualstudio2015。

我的代码如下:

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]);
}

正如您所写的,使用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至少从2.4.3版本开始支持并行For。通过使用并行循环,您可以利用多核CPU的强大功能,其中每个核都将在图像的单独部分上迭代。

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

最新更新