
本文約3200字,建議閱讀7分鐘
本教程的目標(biāo)是展示如何使用OpenCV的parallel_for_框架輕松實(shí)現(xiàn)代碼并行化。
目標(biāo)
本教程的目標(biāo)是展示如何使用OpenCV的parallel_for_框架輕松實(shí)現(xiàn)代碼并行化。為了說明這個(gè)概念,我們將編寫一個(gè)程序,利用幾乎所有的CPU負(fù)載來繪制Mandelbrot集合。完整的教程代碼可見原文。如果想了解更多關(guān)于多線程的信息,請參考本教程中提及的參考書或課程。預(yù)備條件
首先是搭建OpenCV并行框架。在OpenCV3.2中,可以按此順序使用以下并行框架:1. 英特爾線程構(gòu)建模塊(第三方庫,應(yīng)該明確啟用)2. C =并行C / C ++編程語言擴(kuò)展(第三方庫,應(yīng)該明確啟用)3. OpenMP(集成的編譯器,應(yīng)明確啟用)4. APPLE GCD(系統(tǒng)層面,自動(dòng)使用(僅適用APPLE))5. Windows RT并發(fā)(系統(tǒng)層面,自動(dòng)使用(僅適用Windows RT))6. Windows并發(fā)(部分運(yùn)行時(shí)間,自動(dòng)使用(僅適用Windows - MSVC ++> = 10))正如前面所述,OpenCV庫可以使用多個(gè)并行框架。有些并行庫為第三方提供的庫,建立時(shí)應(yīng)明確地用CMake(如TBB,C =)啟用,其余均為自動(dòng)可用的平臺(例如APPLE GCD),但是,無論是直接使用并行框架還是利用CMake啟用并行框架并重建庫,首先要做的是啟用并行框架。第二個(gè)(弱)預(yù)備條件與任務(wù)相關(guān),因?yàn)椴皇撬腥蝿?wù)的計(jì)算都可以/適合以并行方式來運(yùn)行。為了盡量保持簡單,可以將任務(wù)分解為與存儲器無關(guān)的多個(gè)元素,從而使其更加容易實(shí)現(xiàn)并行化。在計(jì)算機(jī)視覺處理過程中,由于大多數(shù)時(shí)間里一個(gè)像素的處理不依賴于其它像素的狀態(tài),所以往往更加容易實(shí)現(xiàn)并行化。簡單的示例:繪制Mandelbrot集合
這個(gè)例子中將展示如何繪制Mandelbrot集合,將普通的順序代碼實(shí)現(xiàn)并行化計(jì)算。理論
Mandelbrot集合的名稱是數(shù)學(xué)家阿德里恩·多迪(Adrien Douady)為悼念數(shù)學(xué)家蒙德布羅特(Mandelbrot),以他的名字來命名的。它在數(shù)學(xué)界之外,作為分形類的一個(gè)例子,在圖像表示領(lǐng)域非常著名。Mandelbrot集合為一組自相似的重復(fù)圖案在不同尺度下重復(fù)顯示結(jié)果。為了進(jìn)一步深入介紹,可以參考Wikipedia article。在這里,僅介紹利用公式繪制Mandelbrot集合(選自維基百科的文章)。Mandelbrot集合是在復(fù)平面中一組值C沿著0軌跡的二次迭代映射的邊界。
即,復(fù)數(shù)c作為Mandelbrot集的一部分,從 Z0 = 0開始重復(fù)進(jìn)行迭代,當(dāng)n趨近于無窮大時(shí),Zn的絕對值的邊界值,它可以表示為:

偽代碼
生成Mandelbrot集合的簡單的算法被稱為“逃逸時(shí)間算法”。為渲染圖像中的每個(gè)像素,根據(jù)復(fù)數(shù)值是否在邊界范圍之內(nèi),利用遞推關(guān)系進(jìn)行測試。經(jīng)過數(shù)次迭代之后,不屬于Mandelbrot集合的像素將快速逃逸,留下來的將是屬于Mandelbrot集合的像素。隨著計(jì)算時(shí)間的增加,迭代后的高階值將產(chǎn)生一個(gè)更詳細(xì)的圖像。在這里使用實(shí)現(xiàn)“逃逸”所需要的迭代次數(shù)來描繪圖像中的像素值。
將偽代碼和理論相關(guān)聯(lián)之后,得到:
在上圖中,復(fù)數(shù)的實(shí)部在x軸上,復(fù)數(shù)的虛部在y軸上。通過對圖形局部放大,可以看到整個(gè)形狀均重復(fù)可見。
代碼實(shí)現(xiàn)
逃逸時(shí)間算法的實(shí)現(xiàn)

在這里,我們使用了std::complex模板類來表示復(fù)數(shù)。利用這個(gè)函數(shù)來進(jìn)行測試,以檢查像素是否在集合之中,并返回“逃逸”迭代。順序的Mandelbrot實(shí)現(xiàn)

在此程序中,通過依次遍歷渲染圖像中的像素來進(jìn)行測試,以檢查像素是否屬于Mandelbrot集合。需要做的另一件事是把像素坐標(biāo)轉(zhuǎn)換Mandelbrot集合空間:
最后,將灰度值分配給像素,使用以下規(guī)則:
使用線性縮放轉(zhuǎn)換不足以感知的灰度變化。為了克服這個(gè)問題,使用一個(gè)平方根轉(zhuǎn)換來提升感知度(引用了Jeremy D. Frens博客中的內(nèi)容): 

綠色曲線對應(yīng)于簡單的線性縮放轉(zhuǎn)換,藍(lán)色曲線對應(yīng)于平方根轉(zhuǎn)換,可以從中觀察到的最低值如何沿著斜坡正向上升。并行Mandelbrot實(shí)現(xiàn)
在順序的Mandelbrot實(shí)現(xiàn)中,每個(gè)像素被獨(dú)立計(jì)算。為了優(yōu)化計(jì)算,我們可以利用現(xiàn)代處理器的多核架構(gòu)并行執(zhí)行多個(gè)像素的計(jì)算,利用OpenCV的CV :: parallel_for_框架可以輕松實(shí)現(xiàn)。
第一件事是聲明一個(gè)繼承CV :: ParallelLoopBody的自定義類,覆蓋virtual void operator ()(const cv::Range& range) const。 operator ()表示將通過一個(gè)獨(dú)立的線程來處理像素的子集,這種拆分是自動(dòng)完成的,以平均分配計(jì)算負(fù)荷,為此必須將像素索引坐標(biāo)轉(zhuǎn)換成2D [行,列]坐標(biāo)。還要注意的是,必須保持圖像的mat對象引用值,以便能夠適時(shí)地對圖像進(jìn)行修改。
在這里,range表示將要執(zhí)行的操作總數(shù),即圖像中的像素總數(shù)。使用CV :: setNumThreads設(shè)置線程數(shù),還可以使用CV :: parallel_for_中的 nstripes參數(shù)指定拆分的數(shù)量CV :: parallel_for_。例如,如果處理器有4個(gè)線程,則設(shè)置CV :: setNumThreads(2)或者設(shè)置nstripes = 2應(yīng)該是一樣的,默認(rèn)情況下它會(huì)使用所有可用的處理器線程,但拆分后只有兩個(gè)線程。為了簡化并行的實(shí)現(xiàn),C ++ 11標(biāo)準(zhǔn)刪除了ParallelMandelbrot類,采用lambda表達(dá)式代替它:
運(yùn)行結(jié)果
可以在原文找到完整的教程源代碼,并行實(shí)現(xiàn)的性能取決于CPU的種型。例如,在4核/ 8線程的CPU上,可以提速6.9倍左右。如果要問,為什么達(dá)不到8倍速,其中有很多因素;主要原因是由于:由教程代碼生成的輸出圖像(可以對代碼進(jìn)行修改,以使用更多次的迭代,根據(jù)逃逸迭代次數(shù)來分配像素顏色,并使用調(diào)色板以獲得更美的圖像):
Mandelbrot集合XMIN = -2.1,XMAX = 0.6,YMIN = -1.2,YMAX = 1.2,maxIterations = 500
原文鏈接:
https://docs.opencv.org/4.5.2/d7/dff/tutorial_how_to_use_OpenCV_parallel_for_.html
獨(dú)家|OpenCV?1.1 Mat?- 基本圖像容器(附鏈接)
獨(dú)家|OpenCV?1.3 矩陣的掩膜操作(附鏈接)
獨(dú)家|OpenCV 1.5 利用OpenCV疊加(混合)兩幅圖像
獨(dú)家|OpenCV 1.6 改變圖像的對比度和亮度!
獨(dú)家|OpenCV 1.7 離散傅里葉變換
獨(dú)家|OpenCV1.8 使用XML和YAML文件實(shí)現(xiàn)文件的輸入/輸出
陳之炎,北京交通大學(xué)通信與控制工程專業(yè)畢業(yè),獲得工學(xué)碩士學(xué)位,歷任長城計(jì)算機(jī)軟件與系統(tǒng)公司工程師,大唐微電子公司工程師,現(xiàn)任北京吾譯超群科技有限公司技術(shù)支持。目前從事智能化翻譯教學(xué)系統(tǒng)的運(yùn)營和維護(hù),在人工智能深度學(xué)習(xí)和自然語言處理(NLP)方面積累有一定的經(jīng)驗(yàn)。業(yè)余時(shí)間喜愛翻譯創(chuàng)作,翻譯作品主要有:IEC-ISO 7816、伊拉克石油工程項(xiàng)目、新財(cái)稅主義宣言等等,其中中譯英作品“新財(cái)稅主義宣言”在GLOBAL TIMES正式發(fā)表。能夠利用業(yè)余時(shí)間加入到THU 數(shù)據(jù)派平臺的翻譯志愿者小組,希望能和大家一起交流分享,共同進(jìn)步
工作內(nèi)容:需要一顆細(xì)致的心,將選取好的外文文章翻譯成流暢的中文。如果你是數(shù)據(jù)科學(xué)/統(tǒng)計(jì)學(xué)/計(jì)算機(jī)類的留學(xué)生,或在海外從事相關(guān)工作,或?qū)ψ约和庹Z水平有信心的朋友歡迎加入翻譯小組。
你能得到:定期的翻譯培訓(xùn)提高志愿者的翻譯水平,提高對于數(shù)據(jù)科學(xué)前沿的認(rèn)知,海外的朋友可以和國內(nèi)技術(shù)應(yīng)用發(fā)展保持聯(lián)系,THU數(shù)據(jù)派產(chǎn)學(xué)研的背景為志愿者帶來好的發(fā)展機(jī)遇。
其他福利:來自于名企的數(shù)據(jù)科學(xué)工作者,北大清華以及海外等名校學(xué)生他們都將成為你在翻譯小組的伙伴。
點(diǎn)擊文末“閱讀原文”加入數(shù)據(jù)派團(tuán)隊(duì)~
轉(zhuǎn)載須知
如需轉(zhuǎn)載,請?jiān)陂_篇顯著位置注明作者和出處(轉(zhuǎn)自:數(shù)據(jù)派ID:DatapiTHU),并在文章結(jié)尾放置數(shù)據(jù)派醒目二維碼。有原創(chuàng)標(biāo)識文章,請發(fā)送【文章名稱-待授權(quán)公眾號名稱及ID】至聯(lián)系郵箱,申請白名單授權(quán)并按要求編輯。
發(fā)布后請將鏈接反饋至聯(lián)系郵箱(見下方)。未經(jīng)許可的轉(zhuǎn)載以及改編者,我們將依法追究其法律責(zé)任。