OpenCV學習筆記(四十四)——初探GPU

好久沒有更新啦,感覺最近沒有什麼特別的收穫值得和大家分享,還是有些懶,TLD結束了也沒有寫個blog做總結。還是和大家分享一下OpenCV的一個大家很少接觸的模塊吧——GPU。這個部分我接觸的也是很少,只是根據教程和大家簡單交流一下,如果有高手有使用心得,歡迎多多批評。

OpenCV的GPU模塊只支持NVIDIA的顯卡,原因是該部分是基於NVIDIA的CUDA和NVIDIA的NPP模塊實現的。而該模塊的好處在於使用GPU模塊無需安裝CUDA工具,也無需學習GPU編程,因爲不需要編寫GPU相關的代碼。但如果你想重新編譯OpenCV的GPU模塊的話,還是需要CUDA的toolkit。

由於GPU模塊的發展,使大部分函數使用起來和之前在CPU下開發非常類似。首先,就是把GPU模塊鏈接到你的工程中,幷包含必要的頭文件gpu.hpp。其次,就是GPU模塊下的數據結構,原本在cv名字空間中的現在都在gpu名字空間中,使用時可以gpu::和cv::來防止混淆。

需要再說明的是,在GPU模塊中,矩陣的名字爲GpuMat,而不是之前的Mat,其他的函數名字和CPU模塊中相同,不同的是,現在的參數輸入不再是Mat,而是GpuMat。

還有一個問題就是,對於2.0的GPU模塊,多通道的函數支持的並不好,推薦使用GPU模塊處理灰度的圖像。有些情況下,使用GPU模塊的運行速度還不及CPU模塊下的性能,所以可以認爲,GPU模塊相對而言還不夠成熟,需要進一步優化。很重要的一個原因就是內存管理部分和數據轉換部分對於GPU模塊而言消耗了大量的時間。

需要注意的是,在所有使用GPU模塊的函數之前,最好需要調用函數gpu::getCudaEnabledDeviceCount,如果你在使用的OpenCV模塊編譯時不支持GPU,這個函數返回值爲0;否則返回值爲已安裝的CUDA設備的數量。

還有一點就是使用GPU模塊,需要在用CMake編譯OpenCV時使其中的WITH_CUDAWITH_TBB的宏生效,爲ON

由於我對GPU部分的熟悉程度還不行,先拿來一段sample自帶的一段求矩陣轉置的程序來做例子,代碼如下:

#include <iostream>
#include "cvconfig.h"
#include "opencv2/core/core.hpp"
#include "opencv2/gpu/gpu.hpp"
#include "opencv2/core/internal.hpp" // For TBB wrappers

using namespace std;
using namespace cv;
using namespace cv::gpu;

struct Worker { void operator()(int device_id) const; };

int main()
{
    int num_devices = getCudaEnabledDeviceCount();
    if (num_devices < 2)
    {
        std::cout << "Two or more GPUs are required\n";
        return -1;
    }
    for (int i = 0; i < num_devices; ++i)
    {
        DeviceInfo dev_info(i);
        if (!dev_info.isCompatible())
        {
            std::cout << "GPU module isn't built for GPU #" << i << " ("
                 << dev_info.name() << ", CC " << dev_info.majorVersion()
                 << dev_info.minorVersion() << "\n";
            return -1;
        }
    }

    // Execute calculation in two threads using two GPUs
    int devices[] = {0, 1};
    parallel_do(devices, devices + 2, Worker());

    return 0;
}


void Worker::operator()(int device_id) const
{
    setDevice(device_id);

    Mat src(1000, 1000, CV_32F);
    Mat dst;

    RNG rng(0);
    rng.fill(src, RNG::UNIFORM, 0, 1);

    // CPU works
    transpose(src, dst);

    // GPU works
    GpuMat d_src(src);
    GpuMat d_dst;
    transpose(d_src, d_dst);

    // Check results
    bool passed = norm(dst - Mat(d_dst), NORM_INF) < 1e-3;
    std::cout << "GPU #" << device_id << " (" << DeviceInfo().name() << "): "
        << (passed ? "passed" : "FAILED") << endl;

    // Deallocate data here, otherwise deallocation will be performed
    // after context is extracted from the stack
    d_src.release();
    d_dst.release();
}

以上介紹的內容不但膚淺,而且顯得比較凌亂。希望高手看完後多多指正,跟我一樣不太明白的朋友僅供參考。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章