国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

一文徹底搞懂為什么OpenCV用GPU/cuda跑得比用CPU慢?

這篇具有很好參考價(jià)值的文章主要介紹了一文徹底搞懂為什么OpenCV用GPU/cuda跑得比用CPU慢?。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

一、原因總結(jié)

最近項(xiàng)目需要,發(fā)現(xiàn)了這個(gè)問題。網(wǎng)上找原因,匯總起來,有以下幾點(diǎn)原因:

1、首先對(duì)于任何一個(gè)CUDA程序,在調(diào)用它的第一個(gè)CUDA API時(shí)后都要花費(fèi)秒級(jí)的時(shí)間去初始化運(yùn)行環(huán)境,后續(xù)還要分配顯存,傳輸數(shù)據(jù),啟動(dòng)內(nèi)核,每一樣都有延遲。這樣如果你一個(gè)任務(wù)CPU運(yùn)算都僅要幾十毫秒,相比而言必須帶上這些延遲的GPU程序就會(huì)顯得非常慢。

2、其次,一個(gè)運(yùn)算量很小的程序,你的CUDA內(nèi)核不可能啟動(dòng)太多的線程,沒有足夠的線程來屏蔽算法執(zhí)行時(shí)從顯存加載數(shù)據(jù)到GPU SM中的時(shí)延,這就沒有發(fā)揮GPU的真正功能。

3、數(shù)據(jù)從內(nèi)存?zhèn)鬟f到顯存和cudaMalloc耗時(shí)很長,NVIDIA提供的nsight中的profile可以看每一個(gè)部分的耗時(shí)?;旧螼penCV的算法都?xì)w納為三個(gè)部分:upload(gpu::Mat), processCodeBlock, download(gpu::Mat)。你看看是不是80%以上的時(shí)間都花在第一個(gè)和最后一個(gè)上,問題就迎刃而解了。因?yàn)間pu在計(jì)算上雖然比cpu快,但實(shí)際上在使用gpu的時(shí)候有一步非常耗時(shí),那就是將內(nèi)存與顯存中的數(shù)據(jù)進(jìn)行互相拷貝,同時(shí)這也是使用gpu運(yùn)算時(shí)逃不掉的一步。

4、GPU擅長的是大規(guī)模并行計(jì)算,比起cpu只是以巨額核心數(shù)取得優(yōu)勢(shì)的,單核速度其實(shí)被cpu碾壓。如果數(shù)據(jù)規(guī)模小的話GPU并不能用上太多核,所以比cpu慢。減少數(shù)據(jù)在CPU和GPU之間的傳遞次數(shù);運(yùn)算量非常小的部分不要用GPU,數(shù)據(jù)量非常大、循環(huán)次數(shù)非常多的時(shí)候才使用GPU。

//執(zhí)行這些簡單算子,CPU比GPU更快

cvtColor,GaussianBlur,Canny

//執(zhí)行這些耗時(shí)算子,GPU比CPU更快

HoughCircles,HoughLines,matchTemplate

5、如果問題規(guī)模較小,邏輯控制較為復(fù)雜,并行性很小優(yōu)先使用CPU處理該問題,如果包含較大規(guī)模的數(shù)據(jù)處理,則考慮使用GPU進(jìn)行處理。

CPU上線程是重量級(jí)實(shí)體,可以開啟1~32個(gè)線程,且上下文切換較為緩慢,GPU上線程是高度輕量級(jí)的,可以開幾百甚至上千個(gè)線程。

CUDA通過兩種API來對(duì)設(shè)備GPU設(shè)備進(jìn)行控制,包括驅(qū)動(dòng)API和運(yùn)行API,其中驅(qū)動(dòng)API較難編程,但是設(shè)備控制能力和利用率高。兩者只能選擇其中一種,不能混合使用。

一個(gè)CUDA程序包含了兩個(gè)部分代碼,在CPU上運(yùn)行的主機(jī)代碼和在GPU上運(yùn)行的設(shè)備代碼。

6、總結(jié)一句,GPU的并行處理的確很快,但數(shù)據(jù)傳入GPU和傳出的開銷實(shí)在太大,往往影響了代碼的整體效率,運(yùn)算量非常小的計(jì)算不要用GPU。

二、舉例opencv

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/core/cuda.hpp>
#include <opencv2/core/ocl.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/cudaimgproc.hpp>
#include <opencv2/cudaarithm.hpp>
#include <opencv2/cudafilters.hpp>
#include <opencv2/cudawarping.hpp>

#define IMAGE_TEST_PATHNAME "D:\\test_src.jpg"
#define IMAGE_SOURCE        "D:\\test_src.jpg"
#define IMAGE_TEMPLATE      "D:\\test_templ.jpg"

void checkCuda() //舊版本的是cv::gpu,#include <opencv2/gpu/gpu.hpp>,已棄用
{
    int64 begintime, endtime;
    int num_devices = cv::cuda::getCudaEnabledDeviceCount();
    if (num_devices <= 0)
    {
        std::cerr << "There is no cuda device" << std::endl;
        return;
    }

    int enable_device_id = -1;
    for (int i = 0; i < num_devices; i++)
    {
        cv::cuda::DeviceInfo dev_info(i);
        if (dev_info.isCompatible())
        {
            enable_device_id = i;
        }
    }

    if (enable_device_id < 0)
    {
        std::cerr << "GPU module isn't built for GPU" << std::endl;
        return;
    }

    cv::cuda::setDevice(enable_device_id); //指定顯卡

    //有一個(gè)問題是,一般使用GPU加速的話,第一次調(diào)用GPU,會(huì)很慢很慢,一條簡單的語句都用了10多秒左右。
    //治標(biāo)不治本的解決方法是在程序的開頭加上一句cv::gpu::GpuMata(10, 10, CV_8U);
    //這樣會(huì)令耗時(shí)的操作放在一開頭,不那么影響后面的操作時(shí)間
    //為什么第一次函數(shù)調(diào)用很慢
    //那是因?yàn)槌跏蓟_銷;在第一個(gè)GPU函數(shù)調(diào)用Cuda Runtime API被隱式初始化;
    cv::cuda::GpuMat(10, 10, CV_8U);

    //測(cè)試用例
    cv::Mat src_image = cv::imread(IMAGE_PATHNAME);
    cv::Mat dst_image;
    cv::cuda::GpuMat d_src_img(src_image); //upload src image to gpu
    //或者d_src_img.upload(src_image);
    cv::cuda::GpuMat d_dst_img;

    begintime = cv::getTickCount();
    cv::cuda::cvtColor(d_src_img, d_dst_img, cv::COLOR_BGR2GRAY); //canny
    d_dst_img.download(dst_image);                                //download dst image to cpu
    endtime = cv::getTickCount();
    std::cerr << 1000 * (endtime - begintime) / cv::getTickFrequency() << std::endl;

    cv::namedWindow("checkCuda", cv::WINDOW_NORMAL);
    cv::imshow("checkCuda", dst_image);
}

void calcEdgesCuda()
{
    cv::ocl::setUseOpenCL(false);

    double start = cv::getTickCount();
    cv::cuda::GpuMat gpuGray, gpuBlur, gpuEdges;
    cv::Mat cpuEdges;

    cv::Mat cpuFrame = cv::imread(IMAGE_PATHNAME);

    cv::cuda::registerPageLocked(cpuFrame); //鎖頁內(nèi)存

    cv::cuda::GpuMat gpuFrame;
    gpuFrame.upload(cpuFrame);

    cv::cuda::cvtColor(gpuFrame, gpuGray, cv::COLOR_BGR2GRAY);

    cv::Ptr<cv::cuda::Filter> gaussFilter = cv::cuda::createGaussianFilter(CV_8UC1, CV_8UC1, cv::Size(3, 3), 15, 15);
    gaussFilter->apply(gpuGray, gpuBlur);

    cv::Ptr<cv::cuda::CannyEdgeDetector> cannyEdge = cv::cuda::createCannyEdgeDetector(50, 100, 3);
    cannyEdge->detect(gpuBlur, gpuEdges);

    cv::cuda::GpuMat gpuLines; //This should be GpuMat...
#if 0                          //find line
    std::vector<cv::Vec2f> vtLines;
    cv::Ptr<cv::cuda::HoughLinesDetector> hough = cv::cuda::createHoughLinesDetector(1, CV_PI / 180, 120);
    hough->detect(gpuEdges, gpuLines);
    hough->downloadResults(gpuLines, vtLines);
#else
    cv::Ptr<cv::cuda::HoughCirclesDetector> hough1 = cv::cuda::createHoughCirclesDetector(1.5, 15, 300, 1, 1, 100);
    hough1->detect(gpuEdges, gpuLines);
    cv::Ptr<cv::cuda::HoughCirclesDetector> hough2 = cv::cuda::createHoughCirclesDetector(1, 15, 100, 30, 1, 100);
    hough2->detect(gpuEdges, gpuLines);
#endif

    gpuEdges.download(cpuEdges);
    cv::cuda::unregisterPageLocked(cpuFrame); //解除鎖頁

    std::cout << "Cuda cost time:(s)" << ((cv::getTickCount() - start) / cv::getTickFrequency()) << std::endl;

    cv::namedWindow("Canny Edges Cuda", cv::WINDOW_NORMAL);
    cv::imshow("Canny Edges Cuda", cpuEdges);
}

void matchTemplateCPU()
{
    cv::Mat src = cv::imread(IMAGE_SOURCE, cv::IMREAD_GRAYSCALE);
    cv::Mat templ = cv::imread(IMAGE_TEMPLATE, cv::IMREAD_GRAYSCALE);
    cv::Mat dst;
    double minVal = 0;
    double maxVal = 0;
    cv::Point minLoc;
    cv::Point maxLoc;

    double start = cv::getTickCount();
    cv::matchTemplate(src, templ, dst, cv::TM_CCOEFF_NORMED); //用6種匹配方式
    cv::normalize(dst, dst, 1, 0, cv::NORM_MINMAX);
    cv::minMaxLoc(dst, &minVal, &maxVal, &minLoc, &maxLoc); //找到最佳匹配點(diǎn)
    std::cout << "matchTemplateCPU cost time:(s)" << ((cv::getTickCount() - start) / cv::getTickFrequency()) << std::endl;

    cv::rectangle(src, cv::Rect(maxLoc.x, maxLoc.y, templ.cols, templ.rows), 1, 8, 0);

    cv::namedWindow("matchTemplateCPU", cv::WINDOW_NORMAL);
    cv::imshow("matchTemplateCPU", src);
}

void matchTemplateCuda()
{
    cv::Mat src = cv::imread(IMAGE_SOURCE, cv::IMREAD_GRAYSCALE);
    cv::Mat templ = cv::imread(IMAGE_TEMPLATE, cv::IMREAD_GRAYSCALE);
    cv::Mat dst;
    double minVal = 0;
    double maxVal = 0;
    cv::Point minLoc;
    cv::Point maxLoc;
    cv::cuda::GpuMat gsrc, gtempl, gdst;

    double start = cv::getTickCount();
    gsrc.upload(src);
    gtempl.upload(templ);
    cv::Ptr<cv::cuda::TemplateMatching> matcher;
    matcher = cv::cuda::createTemplateMatching(CV_8U, cv::TM_CCOEFF_NORMED);
    matcher->match(gsrc, gtempl, gdst);
    cv::cuda::minMaxLoc(gdst, &minVal, &maxVal, &minLoc, &maxLoc);
    std::cout << "matchTemplateCuda cost time:(s)" << ((cv::getTickCount() - start) / cv::getTickFrequency()) << std::endl;

    cv::rectangle(src, cv::Rect(maxLoc.x, maxLoc.y, templ.cols, templ.rows), 1, 8, 0);

    cv::namedWindow("matchTemplateCuda", cv::WINDOW_NORMAL);
    cv::imshow("matchTemplateCuda", src);
}

鎖頁能夠加速數(shù)據(jù)在CPU和GPU之間的傳遞

cv::cuda::registerPageLocked(img);//鎖頁內(nèi)存
gimg.upload(img);//上傳數(shù)據(jù)至GPU

gimg.download(img);//下載數(shù)據(jù)至CPU
cv::cuda::unregisterPageLocked(img);//解除鎖頁

---

姊妹篇

OpenCV算法加速(4)官方源碼v4.5.5的默認(rèn)并行和優(yōu)化加速的編譯選項(xiàng)是什么?請(qǐng)重點(diǎn)關(guān)注函數(shù)cv::getBuildInformation()的返回值_opencv 編譯選項(xiàng)_利白的博客-CSDN博客

參考文獻(xiàn)

為什么opencv用GPU實(shí)現(xiàn)比用CPU實(shí)現(xiàn)的慢?_opencv在顯卡上和cpu上跑程序哪個(gè)快_THMAIL的博客-CSDN博客

opencv(C++)GPU、CPU 模板匹配_opencv 操作gpu_1037號(hào)森林里一段干木頭的博客-CSDN博客

cuda實(shí)現(xiàn)的連通域

https://docs.nvidia.com/cuda/npp/group__image__filter__label__markers.html

CV-CUDA? is an open-source, GPU accelerated library for cloud-scale image processing and computer vision.

https://github.com/CVCUDA/CV-CUDA

《通用圖形處理器設(shè)計(jì)——GPGPU編程模型與架構(gòu)原理》

作者:景乃鋒、柯晶、梁曉 出版社:清華大學(xué)出版社 出版時(shí)間:2022年05月文章來源地址http://www.zghlxwxcb.cn/news/detail-439131.html

到了這里,關(guān)于一文徹底搞懂為什么OpenCV用GPU/cuda跑得比用CPU慢?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 一文了解以太坊為什么合并及未來升級(jí)規(guī)劃

    一文了解以太坊為什么合并及未來升級(jí)規(guī)劃

    一、什么是以太坊升級(jí) 以太坊升級(jí)最初被稱為「ETH 2.0」或「寧靜(Serenity)」,是一次規(guī)劃已久的以太坊網(wǎng)絡(luò)重大升級(jí),將使以太坊網(wǎng)絡(luò)具有更好的可擴(kuò)展性、安全性和可持續(xù)性。 二、為什么要進(jìn)行升級(jí) 眾所周知,以太坊正面臨著網(wǎng)絡(luò)擁堵、運(yùn)行節(jié)點(diǎn)門檻高、能源損耗大等

    2023年04月08日
    瀏覽(26)
  • 一文讀懂為什么需要跨鏈?跨鏈?zhǔn)鞘裁??跨鏈?shí)現(xiàn)技術(shù)?

    一文讀懂為什么需要跨鏈?跨鏈?zhǔn)鞘裁??跨鏈?shí)現(xiàn)技術(shù)?

    區(qū)塊鏈的現(xiàn)狀 從2014開始,“區(qū)塊鏈2.0”成為一個(gè)關(guān)于去中心化區(qū)塊鏈數(shù)據(jù)庫的術(shù)語。區(qū)塊鏈2.0 技術(shù)跳過了交易和價(jià)值交換中擔(dān)任金錢和信息仲裁的中介機(jī)構(gòu)。這使得人們的隱私得到保護(hù),可以將掌握的信息兌換成貨幣,并且有能力保證知識(shí)產(chǎn)權(quán)的所有者得到收益。 從狹義角

    2024年01月23日
    瀏覽(18)
  • 從駕考科目二到自動(dòng)駕駛,聊聊GPU為什么對(duì)自動(dòng)駕駛很重要

    從駕考科目二到自動(dòng)駕駛,聊聊GPU為什么對(duì)自動(dòng)駕駛很重要

    “下一個(gè)項(xiàng)目,坡道起步?!?…… “考試不合格,請(qǐng)將車子開到起點(diǎn),重新驗(yàn)證考試。你的扣分項(xiàng)是:起步時(shí)間超30秒:扣100分。行駛過程中車輪軋到邊線:扣100分?!?想必經(jīng)歷過駕駛證考試的同學(xué),對(duì)科目二的坡道起步都有說不清道不明的情感。我在坡道起步項(xiàng)目上連續(xù)

    2024年02月09日
    瀏覽(22)
  • iNFTnews|一文讀懂為什么說元宇宙是未來

    iNFTnews|一文讀懂為什么說元宇宙是未來

    我敢肯定,我們中的任何人都將知道“元宇宙”這個(gè)。在去年(2021年)的這個(gè)時(shí)候,元宇宙已經(jīng)成為繼NFT、GameFi等之后加密貨幣新的大趨勢(shì)。 在馬克·扎克伯格(Mark Zuckerberg)宣布Facebook從“社交媒體公司”轉(zhuǎn)型為“元宇宙公司”并將Facebook正式更名為Meta之后,元宇宙

    2024年01月22日
    瀏覽(26)
  • 一文看懂什么是歐幾里得算法!多圖演示輾轉(zhuǎn)相除算法究竟是什么!為什么要這樣開展!多圖預(yù)警!

    一文看懂什么是歐幾里得算法!多圖演示輾轉(zhuǎn)相除算法究竟是什么!為什么要這樣開展!多圖預(yù)警!

    ps:全文圖片均為手繪,如果有不標(biāo)準(zhǔn)的地方還望諒解,之后會(huì)慢慢熟悉畫圖工具的,感謝感謝?。?! 歐幾里得算法 又稱為 輾轉(zhuǎn)相除法 ,是指用于計(jì)算兩個(gè)非負(fù)整數(shù)a,b的最大 公約數(shù) 。 兩個(gè)整數(shù)的最大公約數(shù)是指能夠同時(shí)整除它們的最大的正整數(shù)。 輾轉(zhuǎn)相除法能夠?qū)崿F(xiàn)效

    2024年02月02日
    瀏覽(41)
  • 你的 Redis為什么變慢了?一文講透Redis性能優(yōu)化如何做

    你的 Redis為什么變慢了?一文講透Redis性能優(yōu)化如何做

    對(duì) Redis 進(jìn)行基準(zhǔn)性能測(cè)試 例如,我的機(jī)器配置比較低,當(dāng)延遲為 2ms 時(shí),我就認(rèn)為 Redis 變慢了,但是如果你的硬件配置比較高,那么在你的運(yùn)行環(huán)境下,可能延遲是 0.5ms 時(shí)就可以認(rèn)為 Redis 變慢了。 所以,你只有了解了你的 Redis 在生產(chǎn)環(huán)境服務(wù)器上的基準(zhǔn)性能,才能進(jìn)一步

    2024年02月02日
    瀏覽(20)
  • 【Day1】零基礎(chǔ)學(xué)java--》記事本運(yùn)行java程序,通熟語言讓你徹底明白為什么配置java環(huán)境變量

    【Day1】零基礎(chǔ)學(xué)java--》記事本運(yùn)行java程序,通熟語言讓你徹底明白為什么配置java環(huán)境變量

    前言: 大家好,我是 良辰丫 ,從今天開始我將協(xié)同大家一起從零基礎(chǔ)學(xué)習(xí)Java,期待與君為伴,走向海的彼岸。?????? ??個(gè)人主頁:良辰針不戳 ??所屬專欄:EveryDay零基礎(chǔ)學(xué)java ??勵(lì)志語句:生活也許會(huì)讓我們遍體鱗傷,但最終這些傷口會(huì)成為我們一輩子的財(cái)富。 ??期

    2024年02月11日
    瀏覽(13)
  • tensorflow-gpu安裝100%成功(tensorflow-gpu版和tensorflow-cpu版的區(qū)別、為什么要?jiǎng)?chuàng)建虛擬環(huán)境、如何同時(shí)使用兩個(gè)gpu庫、tensorflow-gpu版安裝)

    tensorflow-gpu安裝100%成功(tensorflow-gpu版和tensorflow-cpu版的區(qū)別、為什么要?jiǎng)?chuàng)建虛擬環(huán)境、如何同時(shí)使用兩個(gè)gpu庫、tensorflow-gpu版安裝)

    1.tensorflow-gpu版和tensorflow-cpu版的區(qū)別 tensorflow-gpu版需要同時(shí)配置安裝CUDA、cuDNN,而tensorflow-cpu版不需要配置,直接 pip/conda install tensorflow 即可安裝tensorflow-cpu版本 2.為什么要?jiǎng)?chuàng)建虛擬環(huán)境 在安裝gpu版本的庫時(shí)通常會(huì)創(chuàng)建單獨(dú)的虛擬環(huán)境,例如安裝tensorflow-gpu,則需要利用 cond

    2024年02月08日
    瀏覽(29)
  • 【真情流露】我為什么要寫一本OpenCV C++書籍

    【真情流露】我為什么要寫一本OpenCV C++書籍

    使用OpenCV契機(jī) 大家好,我是賈志剛,OpenCV學(xué)堂公眾號(hào)的號(hào)主,從2009年開始搞圖像處理到今天我已經(jīng)十四年了。剛開始搞圖像處理做的是生物數(shù)據(jù)分析與細(xì)胞分析,用的是工具跟SDK是ImageJ這個(gè)框架,多數(shù)算法都是我自己裸寫,不依賴任何庫。直到2014年的一天有個(gè)朋友跟我說你

    2024年02月04日
    瀏覽(20)
  • 一文徹底搞懂JSON數(shù)據(jù)

    一文徹底搞懂JSON數(shù)據(jù)

    什么是JSON,為什么需要JSON,JSON的3種形式,JSON常用的方法等 TIP JSON指的是全稱是:javascript對(duì)象表示法 JSON是Ajax發(fā)送和接收數(shù)據(jù)的一種格式 JSON是一種輕量級(jí)的數(shù)據(jù)交互格式, 其為字符串類型 (面試題會(huì)考到) JSON是一種語法,用來序列化對(duì)象、數(shù)組、數(shù)值、字符串、布爾值和

    2024年02月06日
    瀏覽(29)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包