亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

OpenCV視頻流C++多線程處理方法詳細(xì)分析

 更新時(shí)間:2022年11月16日 14:27:39   作者:hlld26  
為OpenCV是搞計(jì)算機(jī)視覺(jué)必須要掌握的基礎(chǔ),這篇文章主要給大家介紹了關(guān)于OpenCV視頻流多線程處理的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下

為什么需要多線程處理視頻流

在之前有寫過(guò)一篇文章Python環(huán)境下OpenCV視頻流的多線程處理方式,上面簡(jiǎn)單記錄了如何使用Python實(shí)現(xiàn)對(duì)OpenCV視頻流的多線程處理。簡(jiǎn)單來(lái)說(shuō),在目標(biāo)檢測(cè)等任務(wù)中,如果視頻流的捕獲、解碼以及檢測(cè)都在同一個(gè)線程中,那么很可能出現(xiàn)目標(biāo)檢測(cè)器實(shí)時(shí)性不高導(dǎo)致的檢測(cè)時(shí)延問(wèn)題。使用多線程處理,將視頻幀的捕獲和解碼放在一個(gè)線程,推理放在一個(gè)線程,可以有效緩解時(shí)延的問(wèn)題,使得目標(biāo)檢測(cè)的實(shí)時(shí)性看似有所提升。

C++的多線程處理方式

C++的處理方式與Python大致相同,但卻可能遇到一些問(wèn)題,如使用OpneCV多線程時(shí)X11庫(kù)報(bào)錯(cuò)、OpenCV顯示卡死等問(wèn)題,這些問(wèn)題可能的解決方法會(huì)在后面簡(jiǎn)單提一下。在本文中,使用的多線程是c++11中引入的thread標(biāo)準(zhǔn)庫(kù),實(shí)現(xiàn)方式則包括函數(shù)封裝和類封裝兩種。

函數(shù)封裝的實(shí)現(xiàn)方式

函數(shù)封裝的實(shí)現(xiàn)方式相比類封裝要更為簡(jiǎn)潔,當(dāng)然可復(fù)用性也會(huì)降低。簡(jiǎn)單的示例代碼如下:

// video_test.cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <atomic>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
static std::mutex mutex;
static std::atomic_bool isOpen;
static void cameraThreadFunc(int camId, int height, int width, cv::Mat* pFrame)
{
    cv::VideoCapture capture(camId);
    capture.set(cv::CAP_PROP_FOURCC, CV_FOURCC('M', 'J', 'P', 'G'));
    capture.set(cv::CAP_PROP_FRAME_WIDTH, width);
    capture.set(cv::CAP_PROP_FRAME_HEIGHT, height);
    capture.set(cv::CAP_PROP_FPS, 30);
    if (!capture.isOpened()) {
        isOpen = false;
        std::cout << "Failed to open camera with index " << camId << std::endl;
    }
    cv::Mat frame;
    while (isOpen) {
        capture >> frame;
        if (mutex.try_lock()) {
            frame.copyTo(*pFrame);
            mutex.unlock();
        }
        cv::waitKey(5);
    }
    capture.release();
}
int main(int argc, char* argv[])
{
    isOpen = true;
    cv::Mat frame(480, 640, CV_8UC3), gray;
    std::thread thread(cameraThreadFunc, 0, 480, 640, &frame);
    while (isOpen) {
        mutex.lock();
        frame.copyTo(gray);
        mutex.unlock();
        if (gray.empty()) {
            break;
        }
        cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY);
        cv::blur(gray, gray, cv::Size(3, 3));
        cv::Canny(gray, gray, 5 , 38 , 3);
        cv::waitKey(100);
        cv::imshow("video", gray);
        if (cv::waitKey(1) == 'q') {
            break;
        }
    }
    isOpen = false;
    thread.join();
    return 0;
}

在上面的代碼中,攝像頭的打開、幀捕獲及解碼都在cameraThreadFunc線程函數(shù)中進(jìn)行。在c++11中,有關(guān)pthread的線程操作都封裝在thread標(biāo)準(zhǔn)庫(kù)中,線程的開啟方式也由執(zhí)行pthread_create()函數(shù)變?yōu)閷?duì)thread類的操作。使用thread類時(shí),第一個(gè)參數(shù)為線程函數(shù)的指針,后續(xù)的參數(shù)為傳入線程函數(shù)的參數(shù)。需要注意的是:如果要傳入?yún)?shù)引用,則需要使用std::ref()對(duì)參數(shù)進(jìn)行包裝;如果傳入類成員函數(shù)時(shí),則thread類構(gòu)造函數(shù)的第二個(gè)參數(shù)必須為this

使用多線程時(shí)還需要考慮線程之間的同步問(wèn)題,在上面的程序中,兩個(gè)線程會(huì)同時(shí)訪問(wèn)pFrame指向的緩存空間,使用mutex可確保同一時(shí)刻下僅有一個(gè)線程能訪問(wèn)到緩存空間。另外,使用atomic_bool在多線程中進(jìn)行狀態(tài)切換也是必要的,原子操作使得對(duì)布爾變量的賦值在臨界區(qū)中進(jìn)行,可消除線程之間競(jìng)爭(zhēng)訪問(wèn)或訪問(wèn)結(jié)果不一致的情況。

在上面的程序中,由于主線程會(huì)先訪問(wèn)pFrame變量,因此需要預(yù)先為pFrame申請(qǐng)空間,不然程序開始執(zhí)行時(shí)出現(xiàn)pFrame為空的情況。在Ubuntu中使用g++編譯的方法如下:

g++ video_test.cpp -std=c++11 -I/usr/local/include/ -lpthread -L/usr/local/lib -lopencv_highgui -lopencv_core -lopencv_imgproc -lopencv_videoio -o video_test

根據(jù)OpenCV版本和安裝位置的不同,需要相應(yīng)修改頭文件和庫(kù)文件的位置,例如對(duì)于OpenCV4,頭文件目錄應(yīng)修改為/usr/local/include/opencv4。在Jetson平臺(tái)上,頭文件的位置在/usr/include/opencv4,庫(kù)文件則在/usr/lib/aarch64-linux-gnu。如果有配置pkg-config,那么還可以使用如下方式進(jìn)行編譯:

g++ video_test.cpp -std=c++11 `pkg-config --cflags opencv` -pthread `pkg-config --libs opencv` -o video_test

類封裝的實(shí)現(xiàn)方式

同函數(shù)封裝的方式相似,類封裝的方式僅是將線程函數(shù)和線程同步變量變?yōu)轭惓蓡T,從而提升程序的可復(fù)用性。簡(jiǎn)單的示例代碼如下:

// video_test.cpp
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <atomic>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
class VideoCaptureMT {
public:
	VideoCaptureMT(int index, int height=480, int width=640);
	VideoCaptureMT(std::string filePath, int height=480, int width=640);
	~VideoCaptureMT();
	bool isOpened() {
		return m_IsOpen;
	}
	void release() {
		m_IsOpen = false;
	}
	bool read(cv::Mat& frame);
private:
	void captureInit(int index, std::string filePath, int height, int width);
	void captureFrame();
	cv::VideoCapture* m_pCapture;
	cv::Mat* m_pFrame;
	std::mutex* m_pMutex;
	std::thread* m_pThread;
	std::atomic_bool m_IsOpen;
};
VideoCaptureMT::VideoCaptureMT(int index, int height, int width)
{
	captureInit(index, std::string(), height, width);
}
VideoCaptureMT::VideoCaptureMT(std::string filePath, int height, int width)
{
	captureInit(0, filePath, height, width);
}
VideoCaptureMT::~VideoCaptureMT()
{
	m_IsOpen = false;
	m_pThread->join();
	if (m_pCapture->isOpened()) {
		m_pCapture->release();
	}
	delete m_pThread;
	delete m_pMutex;
	delete m_pCapture;
	delete m_pFrame;
}
void VideoCaptureMT::captureInit(int index, std::string filePath, int height, int width)
{
	if (!filePath.empty()) {
		m_pCapture = new cv::VideoCapture(filePath);
	}
	else {
		m_pCapture = new cv::VideoCapture(index);
	}
	m_pCapture->set(cv::CAP_PROP_FRAME_WIDTH, width);
	m_pCapture->set(cv::CAP_PROP_FRAME_HEIGHT, height);
	m_pCapture->set(cv::CAP_PROP_FPS, 30);
	m_IsOpen = true;
	m_pFrame = new cv::Mat(height, width, CV_8UC3);
	m_pMutex = new std::mutex();
	m_pThread = new std::thread(&VideoCaptureMT::captureFrame, this);
}
void VideoCaptureMT::captureFrame()
{
	cv::Mat frameBuff;
	while (m_IsOpen) {
		(*m_pCapture) >> frameBuff;
		if (m_pMutex->try_lock()) {
			frameBuff.copyTo(*m_pFrame);
			m_pMutex->unlock();
		}
		cv::waitKey(5);
	}
}
bool VideoCaptureMT::read(cv::Mat& frame)
{
	if (m_pFrame->empty()) {
		m_IsOpen = false;
	}
	else {
		m_pMutex->lock();
		m_pFrame->copyTo(frame);
		m_pMutex->unlock();
	}
	return m_IsOpen;
}
int main(int argc, char* argv[])
{
	VideoCaptureMT capture(0);
	cv::Mat frame, gray;
	while (capture.isOpened()) {
		if (!capture.read(frame)) {
			break;
		}
		cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY);
		cv::blur(gray, gray, cv::Size(3, 3));
		cv::Canny(gray, gray, 5 , 38 , 3);
		cv::waitKey(100);
		cv::imshow("image", gray);
        if (cv::waitKey(5) == 'q') {
			break;
		}
	}
	capture.release();
	return 0;
}

在上面的代碼中,線程函數(shù)和線程間同步變量都是類成員,不同的地方在于:攝像頭是在主線程中打開,在子線程中捕獲和解碼幀,但實(shí)際效果和函數(shù)封裝的方式?jīng)]有區(qū)別。

可能遇到的問(wèn)題

使用C++編寫OpenCV的多線程程序時(shí)可能會(huì)遇到一些問(wèn)題,例如我在Jetson AGX上運(yùn)行時(shí)會(huì)報(bào)錯(cuò),提示需要進(jìn)行XInitThreads的初始化。出現(xiàn)這樣的情況時(shí),需要在cpp文件中添加#include <X11/Xlib.h>頭文件,并在main函數(shù)開頭添加XInitThreads()函數(shù)調(diào)用,在編譯時(shí)還需要添加-lX11鏈接庫(kù)。我在Jetson Nano上運(yùn)行時(shí)還遇到顯示窗口卡死的情況,既imshow函數(shù)出現(xiàn)問(wèn)題,點(diǎn)擊關(guān)閉窗戶后又會(huì)重新打開新窗口正常顯示。遇到這樣的情況,可在main函數(shù)開頭添加一行代碼cv::setNumThreads(1),設(shè)置OpenCV在單線程的模式下運(yùn)行可緩解窗口卡死的情況。

到此這篇關(guān)于OpenCV視頻流C++多線程處理方法詳細(xì)分析的文章就介紹到這了,更多相關(guān)OpenCV視頻流內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 輕松實(shí)現(xiàn)C/C++各種常見進(jìn)制相互轉(zhuǎn)換

    輕松實(shí)現(xiàn)C/C++各種常見進(jìn)制相互轉(zhuǎn)換

    這篇文章主要介紹了輕松實(shí)現(xiàn)C/C++各種常見進(jìn)制相互轉(zhuǎn)換,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • 堆基本操作實(shí)現(xiàn)最大堆

    堆基本操作實(shí)現(xiàn)最大堆

    這篇文章主要介紹了堆基本操作實(shí)現(xiàn)最大堆,需要的朋友可以參考下
    2014-02-02
  • C語(yǔ)言預(yù)處理詳解

    C語(yǔ)言預(yù)處理詳解

    這篇文章主要給大家介紹了關(guān)于C語(yǔ)言之預(yù)處理的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-10-10
  • C++使用jsoncpp解析json的方法示例

    C++使用jsoncpp解析json的方法示例

    這篇文章主要介紹了C++使用jsoncpp解析json的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • C++簡(jiǎn)單集合類的實(shí)現(xiàn)方法

    C++簡(jiǎn)單集合類的實(shí)現(xiàn)方法

    如何使用C++實(shí)現(xiàn)一個(gè)簡(jiǎn)單的集合類,這篇文章主要介紹了C++簡(jiǎn)單集合類的實(shí)現(xiàn)方法,感興趣的小伙伴們可以參考一下
    2016-07-07
  • C++算法設(shè)計(jì)之馬踏棋盤的實(shí)現(xiàn)

    C++算法設(shè)計(jì)之馬踏棋盤的實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了C++算法設(shè)計(jì)之馬踏棋盤的實(shí)現(xiàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • c++中的static修飾符示例詳解

    c++中的static修飾符示例詳解

    在c++中,靜態(tài)成員是屬于整個(gè)類而不是某個(gè)對(duì)象,靜態(tài)成員變量只存儲(chǔ)一份供所有對(duì)象共用,下面這篇文章主要給大家介紹了關(guān)于c++中static修飾符的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-10-10
  • c與c++之間的相互調(diào)用及函數(shù)區(qū)別示例詳解

    c與c++之間的相互調(diào)用及函數(shù)區(qū)別示例詳解

    這篇文章主要為大家介紹了c與c++相互調(diào)用的使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • C++使用ADO實(shí)現(xiàn)存取圖片的方法

    C++使用ADO實(shí)現(xiàn)存取圖片的方法

    這篇文章主要介紹了C++使用ADO實(shí)現(xiàn)存取圖片的方法,需要的朋友可以參考下
    2014-07-07
  • C++開發(fā)在IOS環(huán)境下運(yùn)行的LRUCache緩存功能

    C++開發(fā)在IOS環(huán)境下運(yùn)行的LRUCache緩存功能

    本文著重介紹如何在XCODE中,通過(guò)C++開發(fā)在IOS環(huán)境下運(yùn)行的緩存功能。算法基于LRU,最近最少使用,需要的朋友可以參考下
    2012-11-11

最新評(píng)論