tft每日頭條

 > 科技

 > 在opencv中基本用到的數據類型

在opencv中基本用到的數據類型

科技 更新时间:2025-02-21 18:58:01

如何利用OpenCV的parallel_for_并行化代碼

目标

本教程的目标是展示如何使用OpenCV的parallel_for_框架輕松實現代碼并行化。為了說明這個概念,我們将編寫一個程序,利用幾乎所有的CPU負載來繪制Mandelbrot集合。完整的教程代碼在這裡。如果想了解更多關于多線程的信息,請參考本教程中提及的參考書或課程。

預備條件

首先是搭建OpenCV并行框架。在OpenCV3.2中,可以按此順序使用以下并行框架:

  1. 英特爾線程構建模塊(第三方庫,應該明确啟用)
  2. C =并行C / C 編程語言擴展(第三方庫,應該明确啟用)
  3. OpenMP(集成的編譯器,應明确啟用)
  4. APPLE GCD(系統層面,自動使用(僅适用APPLE))
  5. Windows RT并發(系統層面,自動使用(僅适用Windows RT))
  6. Windows并發(部分運行時間,自動使用(僅适用Windows - MSVC > = 10))
  7. Pthreads (如果适用)

正如前面所述,OpenCV庫可以使用多個并行框架。有些并行庫為第三方提供的庫,建立時應明确地用CMake(如TBB,C =)啟用,其餘均為自動可用的平台(例如APPLE GCD),但是,無論是直接使用并行框架還是利用CMake啟用并行框架并重建庫,首先要做的是啟用并行框架。

第二個(弱)預備條件與任務相關,因為不是所有任務的計算都可以/适合以并行方式來運行。為了盡量保持簡單,可以将任務分解為與存儲器無關的多個元素,從而使其更加容易實現并行化。在計算機視覺處理過程中,由于大多數時間裡一個像素的處理不依賴于其它像素的狀态,所以往往更加容易實現并行化。

簡單的示例:繪制Mandelbrot集合

這個例子中将展示如何繪制Mandelbrot集合,将普通的順序代碼實現并行化計算。

理論

Mandelbrot集合的名稱是數學家阿德裡恩·多迪(Adrien Douady)為悼念數學家蒙德布羅特(Mandelbrot),以他的名字來命名的。它在數學界之外,作為分形類的一個例子,在圖像表示領域非常著名。Mandelbrot集合為一組自相似的重複圖案在不同尺度下重複顯示結果。為了進一步深入介紹,可以參考Wikipedia article。在這裡,僅介紹利用公式繪制Mandelbrot集合(選自維基百科的文章)。

Mandelbrot集合是在複平面中一組值C沿着0軌迹的二次叠代映射的邊界。

在opencv中基本用到的數據類型(OpenCV之九如何利用OpenCV的parallel)1

即,複數c作為Mandelbrot集的一部分,從 Z0 = 0開始重複進行叠代,當n趨近于無窮大時,Zn的絕對值的邊界值,它可以表示為:

在opencv中基本用到的數據類型(OpenCV之九如何利用OpenCV的parallel)2

僞代碼

生成Mandelbrot集合的簡單的算法被稱為“逃逸時間算法”。為渲染圖像中的每個像素,根據複數值是否在邊界範圍之内,利用遞推關系進行測試。經過數次叠代之後,不屬于Mandelbrot集合的像素将快速逃逸,留下來的将是屬于Mandelbrot集合的像素。随着計算時間的增加,叠代後的高階值将産生一個更詳細的圖像。在這裡使用實現“逃逸”所需要的叠代次數來描繪圖像中的像素值。

在opencv中基本用到的數據類型(OpenCV之九如何利用OpenCV的parallel)3

将僞代碼和理論相關聯之後,得到:

在opencv中基本用到的數據類型(OpenCV之九如何利用OpenCV的parallel)4

在opencv中基本用到的數據類型(OpenCV之九如何利用OpenCV的parallel)5

在上圖中,複數的實部在x軸上,複數的虛部在y軸上。通過對圖形局部放大,可以看到整個形狀均重複可見。

代碼實現逃逸時間算法的實現

在opencv中基本用到的數據類型(OpenCV之九如何利用OpenCV的parallel)6

在這裡,我們使用了std::complex模闆類來表示複數。利用這個函數來進行測試,以檢查像素是否在集合之中,并返回“逃逸”叠代。

順序的Mandelbrot實現

在opencv中基本用到的數據類型(OpenCV之九如何利用OpenCV的parallel)7

在此程序中,通過依次遍曆渲染圖像中的像素來進行測試,以檢查像素是否屬于Mandelbrot集合。

需要做的另一件事是把像素坐标轉換Mandelbrot集合空間:

在opencv中基本用到的數據類型(OpenCV之九如何利用OpenCV的parallel)8

最後,将灰度值分配給像素,使用以下規則:

  • 當叠代次數達到最大值時,像素為黑色(假定像素在Mandelbrot集合中);
  • 否則根據逃脫“逃逸叠代”和縮放尺度,為像素分配一個灰度值,以适應灰度範圍。

在opencv中基本用到的數據類型(OpenCV之九如何利用OpenCV的parallel)9

使用線性縮放轉換不足以感知的灰度變化。為了克服這個問題,使用一個平方根轉換來提升感知度(引用了Jeremy D. Frens博客中的内容):

在opencv中基本用到的數據類型(OpenCV之九如何利用OpenCV的parallel)10

在opencv中基本用到的數據類型(OpenCV之九如何利用OpenCV的parallel)11

在opencv中基本用到的數據類型(OpenCV之九如何利用OpenCV的parallel)12

綠色曲線對應于簡單的線性縮放轉換,藍色曲線對應于平方根轉換,可以從中觀察到的最低值如何沿着斜坡正向上升。

并行Mandelbrot實現

在順序的Mandelbrot實現中,每個像素被獨立計算。為了優化計算,我們可以利用現代處理器的多核架構并行執行多個像素的計算,利用OpenCV的CV :: parallel_for_框架可以輕松實現。

在opencv中基本用到的數據類型(OpenCV之九如何利用OpenCV的parallel)13

第一件事是聲明一個繼承CV :: ParallelLoopBody的自定義類覆蓋virtual void operator ()(const cv::Range& range) const。

operator ()表示将通過一個獨立的線程來處理像素的子集,這種拆分是自動完成的,以平均分配計算負荷,為此必須将像素索引坐标轉換成2D [行,列]坐标。還要注意的是,必須保持圖像的mat對象引用值,以便能夠适時地對圖像進行修改。

調用并行執行程序:

在opencv中基本用到的數據類型(OpenCV之九如何利用OpenCV的parallel)14

在這裡,range表示将要執行的操作總數,即圖像中的像素總數。使用CV :: setNumThreads設置線程數,還可以使用CV :: parallel_for_中的 nstripes參數指定拆分的數量CV :: parallel_for_。例如,如果處理器有4個線程,則設置CV :: setNumThreads(2)或者設置nstripes = 2應該是一樣的,默認情況下它會使用所有可用的處理器線程,但拆分後隻有兩個線程。

為了簡化并行的實現,C 11标準删除了ParallelMandelbrot類,采用lambda表達式代替它:

在opencv中基本用到的數據類型(OpenCV之九如何利用OpenCV的parallel)15

運行結果

可以在這裡找到完整的教程源代碼,并行實現的性能取決于CPU的種型。例如,在4核/ 8線程的CPU上,可以提速6.9倍左右。如果要問,為什麼達不到8倍速,其中有很多因素;主要原因是由于:

  • 創建和管理線程的額外開銷;
  • 并行運行的後台進程;
  • 帶2個邏輯線程的4硬件核與8硬件核之間是有區别的。

由教程代碼生成的輸出圖像(可以對代碼進行修改,以使用更多次的叠代,根據逃逸叠代次數來分配像素顔色,并使用調色闆以獲得更美的圖像):

在opencv中基本用到的數據類型(OpenCV之九如何利用OpenCV的parallel)16

Mandelbrot集合XMIN = -2.1,XMAX = 0.6,YMIN = -1.2,YMAX = 1.2,maxIterations = 500

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关科技资讯推荐

热门科技资讯推荐

网友关注

Copyright 2023-2025 - www.tftnews.com All Rights Reserved