欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

OpenCV2學(xué)習(xí)筆記之視頻流讀取與處理

 更新時(shí)間:2022年01月09日 09:34:27   作者:Herbert_Zero  
為OpenCV是搞計(jì)算機(jī)視覺必須要掌握的基礎(chǔ),這篇文章主要給大家介紹了關(guān)于OpenCV2學(xué)習(xí)筆記之視頻流讀取與處理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

由于項(xiàng)目需要,計(jì)劃實(shí)現(xiàn)九路視頻拼接,因此必須熟悉OpenCV對視頻序列的處理。視頻信號處理是圖像處理的一個(gè)延伸,所謂的視頻序列是由按一定順序進(jìn)行排放的圖像組成,即幀(Frame)。在這里,主要記錄下如何使用Qt+OpenCV讀取視頻中的每一幀,之后,在這基礎(chǔ)上將一些圖像處理的算法運(yùn)用到每一幀上(如使用Canny算子檢測視頻中的邊緣)。

一. 讀取視頻序列

OpenCV提供了一個(gè)簡便易用的框架以提取視頻文件和USB攝像頭中的圖像幀,如果只是單單想讀取某個(gè)視頻,你只需要?jiǎng)?chuàng)建一個(gè)cv::VideoCapture實(shí)例,然后在循環(huán)中提取每一幀。新建一個(gè)Qt控制臺(tái)項(xiàng)目,直接在main函數(shù)添加:

#include <QCoreApplication>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 讀取視頻流
    cv::VideoCapture capture("e:/BrokeGirls.mkv");
    // 檢測視頻是否讀取成功
    if (!capture.isOpened())
    {
        qDebug() << "No Input Image";
        return 1;
    }

    // 獲取圖像幀率
    double rate= capture.get(CV_CAP_PROP_FPS);
    bool stop(false);
    cv::Mat frame; // 當(dāng)前視頻幀
    cv::namedWindow("Extracted Frame");

    // 每一幀之間的延遲
    int delay= 1000/rate;

    // 遍歷每一幀
    while (!stop)
    {
        // 嘗試讀取下一幀
        if (!capture.read(frame))
            break;
        cv::imshow("Extracted Frame",frame);
        // 引入延遲
        if (cv::waitKey(delay)>=0)
                stop= true;
    }
        return a.exec();
}

(注意:要正確打開視頻文件,計(jì)算機(jī)中必須安裝有對應(yīng)的解碼器,否則cv::VideoCapture無法理解視頻格式!)運(yùn)行后,將出現(xiàn)一個(gè)窗口,播放選定的視頻(需要在創(chuàng)建cv::VideoCapture對象時(shí)指定視頻的文件名)。

這里寫圖片描述

二. 處理視頻幀

為了對視頻的每一幀進(jìn)行處理,這里創(chuàng)建自己的類VideoProcessor,其中封裝了OpenCV的視頻獲取框架,該類允許我們指定每幀調(diào)用的處理函數(shù)。

首先,我們希望指定一個(gè)回調(diào)處理函數(shù),每一幀中都將調(diào)用它。該函數(shù)接受一個(gè)cv::Mat對象,并輸出處理后的cv::Mat對象,其函數(shù)簽名如下:

void processFrame(cv::Mat& img, cv::Mat& out);

作為這樣一個(gè)處理函數(shù)的例子,以下的Canny函數(shù)計(jì)算圖像的邊緣,使用時(shí)直接添加在mian文件中即可:

    // 對視頻的每幀做Canny算子邊緣檢測
void canny(cv::Mat& img, cv::Mat& out) 
{
    // 先要把每幀圖像轉(zhuǎn)化為灰度圖
    cv::cvtColor(img,out,CV_BGR2GRAY);
    // 調(diào)用Canny函數(shù)
    cv::Canny(out,out,100,200);
    // 對像素進(jìn)行翻轉(zhuǎn)
    cv::threshold(out,out,128,255,cv::THRESH_BINARY_INV);
}

現(xiàn)在我們需要?jiǎng)?chuàng)建一個(gè)VideoProcessor類,用來部署視頻處理模塊。而在此之前,需要先另外創(chuàng)建一個(gè)類,即VideoProcessor內(nèi)部使用的幀處理類。這是因?yàn)樵诿嫦驅(qū)ο蟮纳舷挛闹?,更適合使用幀處理類而不是一個(gè)幀處理函數(shù),而使用類可以給程序員在涉及算法方面有更多的靈活度(書上介紹的)。將這個(gè)內(nèi)部幀處理類命名為FrameProcessor,其定義如下:

#ifndef FRAMEPROCESSOR_H
#define FRAMEPROCESSOR_H
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

class FrameProcessor
{
public:
    virtual void process(cv:: Mat &input, cv:: Mat &output)= 0;
};

#endif // FRAMEPROCESSOR_H

現(xiàn)在可以開始定義VideoProcessor類了,以下為videoprocessor.h中的內(nèi)容:

#ifndef VIDEOPROCESSOR_H
#define VIDEOPROCESSOR_H
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <QDebug>
#include "frameprocessor.h"

class VideoProcessor
{
  private:
      // 創(chuàng)建視頻捕獲對象
      cv::VideoCapture capture;
      // 每幀調(diào)用的回調(diào)函數(shù)
      void (*process)(cv::Mat&, cv::Mat&);
      // FrameProcessor接口
      FrameProcessor *frameProcessor;
      // 確定是否調(diào)用回調(diào)函數(shù)的bool信號
      bool callIt;
      // 輸入窗口的名稱
      std::string windowNameInput;
      // 輸出窗口的名稱
      std::string windowNameOutput;
      // 延遲
      int delay;
      // 已處理的幀數(shù)
      long fnumber;
      // 在該幀停止
      long frameToStop;
      // 是否停止處理
      bool stop;

      // 當(dāng)輸入圖像序列存儲(chǔ)在不同文件中時(shí),可使用以下設(shè)置
      // 把圖像文件名的數(shù)組作為輸入
      std::vector<std::string> images;
      // 圖像向量的迭加器
      std::vector<std::string>::const_iterator itImg;

      // 得到下一幀
      // 可能來自:視頻文件或攝像頭
      bool readNextFrame(cv::Mat &frame)
      {
          if (images.size()==0)
              return capture.read(frame);
          else {

              if (itImg != images.end())
              {
                  frame= cv::imread(*itImg);
                  itImg++;
                  return frame.data != 0;
              }
          }
      }

public:

      // 默認(rèn)設(shè)置 digits(0), frameToStop(-1),
      VideoProcessor() : callIt(false), delay(-1),
          fnumber(0), stop(false),
          process(0), frameProcessor(0) {}

      // 創(chuàng)建輸入窗口
      void displayInput(std::string wt);
      // 創(chuàng)建輸出窗口
      void displayOutput(std::string wn);
      // 不再顯示處理后的幀
      void dontDisplay();

      // 以下三個(gè)函數(shù)設(shè)置輸入的圖像向量
      bool setInput(std::string filename);
      // 若輸入為攝像頭,設(shè)置ID
      bool setInput(int id);
      // 若輸入為一組圖像序列時(shí),應(yīng)用該函數(shù)
      bool setInput(const std::vector<std::string>& imgs);

      // 設(shè)置幀之間的延遲
      // 0意味著在每一幀都等待按鍵響應(yīng)
      // 負(fù)數(shù)意味著沒有延遲
      void setDelay(int d);

      // 返回圖像的幀率
      double getFrameRate();

      // 需要調(diào)用回調(diào)函數(shù)
      void callProcess();

      // 不需要調(diào)用回調(diào)函數(shù)
      void dontCallProcess();

      // 設(shè)置FrameProcessor實(shí)例
      void setFrameProcessor(FrameProcessor* frameProcessorPtr);

      // 設(shè)置回調(diào)函數(shù)
      void setFrameProcessor(void (*frameProcessingCallback)(cv::Mat&, cv::Mat&));

      // 停止運(yùn)行
      void stopIt();

      // 判斷是否已經(jīng)停止
      bool isStopped();

      // 是否開始了捕獲設(shè)備?
      bool isOpened();

      // 返回下一幀的幀數(shù)
      long getFrameNumber();

      // 該函數(shù)獲取并處理視頻幀
      void run();

};

#endif // VIDEOPROCESSOR_H

然后,在videoprocessor.cpp中定義各個(gè)函數(shù)的功能:

#include "videoprocessor.h"

// 創(chuàng)建輸入窗口
void VideoProcessor::displayInput(std::string wt)
{
    windowNameInput= wt;
    cv::namedWindow(windowNameInput);
}

// 創(chuàng)建輸出窗口
void VideoProcessor::displayOutput(std::string wn)
{
    windowNameOutput= wn;
    cv::namedWindow(windowNameOutput);
}

// 不再顯示處理后的幀
void VideoProcessor::dontDisplay()
{
    cv::destroyWindow(windowNameInput);
    cv::destroyWindow(windowNameOutput);
    windowNameInput.clear();
    windowNameOutput.clear();
}

// 設(shè)置輸入的圖像向量
bool VideoProcessor::setInput(std::string filename)
{
  fnumber= 0;
  // 釋放之前打開過的視頻資源
  capture.release();
  images.clear();

  // 打開視頻
  return capture.open(filename);
}

// 若輸入為攝像頭,設(shè)置ID
bool VideoProcessor::setInput(int id)
{
  fnumber= 0;
  // 釋放之前打開過的視頻資源
  capture.release();
  images.clear();

  // 打開視頻文件
  return capture.open(id);
}

// 若輸入為一組圖像序列時(shí),應(yīng)用該函數(shù)
bool VideoProcessor::setInput(const std::vector<std::string>& imgs)
{
  fnumber= 0;
  // 釋放之前打開過的視頻資源
  capture.release();

  // 輸入將是該圖像的向量
  images= imgs;
  itImg= images.begin();

  return true;
}

// 設(shè)置幀之間的延遲
// 0意味著在每一幀都等待按鍵響應(yīng)
// 負(fù)數(shù)意味著沒有延遲
void VideoProcessor::setDelay(int d)
{
    delay= d;
}

// 返回圖像的幀率
double VideoProcessor::getFrameRate()
{
    if (images.size()!=0) return 0;
    double r= capture.get(CV_CAP_PROP_FPS);
    return r;
}

// 需要調(diào)用回調(diào)函數(shù)
void VideoProcessor::callProcess()
{
    callIt= true;
}

// 不需要調(diào)用回調(diào)函數(shù)
void VideoProcessor::dontCallProcess()
{
    callIt= false;
}

// 設(shè)置FrameProcessor實(shí)例
void VideoProcessor::setFrameProcessor(FrameProcessor* frameProcessorPtr)
{
    // 使回調(diào)函數(shù)無效化
    process= 0;
    // 重新設(shè)置FrameProcessor實(shí)例
    frameProcessor= frameProcessorPtr;
    callProcess();
}

// 設(shè)置回調(diào)函數(shù)
void VideoProcessor::setFrameProcessor(void (*frameProcessingCallback)(cv::Mat&, cv::Mat&))
{
    // 使FrameProcessor實(shí)例無效化
    frameProcessor= 0;
    // 重新設(shè)置回調(diào)函數(shù)
    process= frameProcessingCallback;
    callProcess();
}

// 以下函數(shù)表示視頻的讀取狀態(tài)
// 停止運(yùn)行
void VideoProcessor::stopIt()
{
    stop= true;
}

// 判斷是否已經(jīng)停止
bool VideoProcessor::isStopped()
{
    return stop;
}

// 是否開始了捕獲設(shè)備?
bool VideoProcessor::isOpened()
{
    return capture.isOpened() || !images.empty();
}

// 返回下一幀的幀數(shù)
long VideoProcessor::getFrameNumber()
{
  if (images.size()==0)
  {
      // 得到捕獲設(shè)備的信息
      long f= static_cast<long>(capture.get(CV_CAP_PROP_POS_FRAMES));
      return f;

  }
  else // 當(dāng)輸入來自一組圖像序列時(shí)的情況
  {
      return static_cast<long>(itImg-images.begin());
  }
}

// 該函數(shù)獲取并處理視頻幀
void VideoProcessor::run()
{
    // 當(dāng)前幀
    cv::Mat frame;
    // 輸出幀
    cv::Mat output;

    // 打開失敗時(shí)
    if (!isOpened())
    {
        qDebug() << "Error!";
        return;
    }
    stop= false;
    while (!isStopped())
    {
        // 讀取下一幀
        if (!readNextFrame(frame))
            break;
        // 顯示輸出幀
        if (windowNameInput.length()!=0)
            cv::imshow(windowNameInput,frame);
        // 調(diào)用處理函數(shù)
        if (callIt)
        {
          // 處理當(dāng)前幀
          if (process)
              process(frame, output);
          else if (frameProcessor)
              frameProcessor->process(frame,output);
          // 增加幀數(shù)
          fnumber++;
        }
        else
        {
          output= frame;
        }
        // 顯示輸出幀
        if (windowNameOutput.length()!=0)
            cv::imshow(windowNameOutput,output);
        // 引入延遲
        if (delay>=0 && cv::waitKey(delay)>=0)
          stopIt();
        // 檢查是否需要停止運(yùn)行
        if (frameToStop>=0 && getFrameNumber()==frameToStop)
            stopIt();
    }
}

定義好視頻處理類,它將與一個(gè)回調(diào)函數(shù)相關(guān)聯(lián)。使用該類,可以創(chuàng)建一個(gè)實(shí)例,指定輸入的視頻文件,綁定回調(diào)函數(shù),然后開始對每一幀進(jìn)行處理,要調(diào)用這個(gè)視頻處理類,只需在main函數(shù)中添加:

    // 定義一個(gè)視頻處理類處理視頻幀
    // 首先創(chuàng)建實(shí)例
    VideoProcessor processor;
    // 打開視頻文件
    processor.setInput("e:/BrokeGirls.mkv");
    // 聲明顯示窗口
    // 分別為輸入和輸出視頻
    processor.displayInput("Input Video");
    processor.displayOutput("Output Video");
    // 以原始幀率播放視頻
    processor.setDelay(1000./processor.getFrameRate());
    // 設(shè)置處理回調(diào)函數(shù)
    processor.setFrameProcessor(canny);
    // 開始幀處理過程
    processor.run();
    cv::waitKey();

效果:

這里寫圖片描述

OpenCV:打開攝像頭獲取視頻流 

#include

#include

using namespace cv;

using namespace std;

int main()

{

//【1】從攝像頭讀入視頻

    VideoCapture capture(1);

    if (!capture.isOpened())

{

cout<< "open camera fail ..." << endl;

        return -1;

    }

capture.set(CAP_PROP_FRAME_WIDTH, 640);

    capture.set(CAP_PROP_FRAME_HEIGHT, 480);

    char filename[200];

    int count =0;

    //【2】循環(huán)顯示每一幀

    Mat frame;  //定義一個(gè)Mat變量,用于存儲(chǔ)每一幀的圖像

    char key;

    while (true)

{

//讀入圖像

        capture>> frame;  //讀取當(dāng)前幀

        key = waitKey(20);

        if(key ==27)//esc鍵退出

            break;

        if(key ==32)//空格鍵保存圖像

        {

sprintf(filename, "Picture_%d.png", ++count);

            imwrite(filename, frame);//

            namedWindow("[frame]", WINDOW_NORMAL);

            imshow("[frame]",frame);

        }

imshow("image", frame);  //顯示當(dāng)前幀

    }

return 0;

}

總結(jié) 

到此這篇關(guān)于OpenCV2學(xué)習(xí)筆記之視頻流讀取與處理的文章就介紹到這了,更多相關(guān)OpenCV視頻流讀取與處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • selenium WebDriverWait類等待機(jī)制的實(shí)現(xiàn)

    selenium WebDriverWait類等待機(jī)制的實(shí)現(xiàn)

    這篇文章主要介紹了selenium WebDriverWait類等待機(jī)制的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • Python不同目錄間進(jìn)行模塊調(diào)用的實(shí)現(xiàn)方法

    Python不同目錄間進(jìn)行模塊調(diào)用的實(shí)現(xiàn)方法

    這篇文章主要介紹了Python不同目錄間進(jìn)行模塊調(diào)用的實(shí)現(xiàn)方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-01-01
  • python正則表達(dá)式re之compile函數(shù)解析

    python正則表達(dá)式re之compile函數(shù)解析

    這篇文章主要介紹了python正則表達(dá)式re之compile函數(shù)解析,介紹了其定義,匹配模式等相關(guān)內(nèi)容,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-10-10
  • Python發(fā)展史及網(wǎng)絡(luò)爬蟲

    Python發(fā)展史及網(wǎng)絡(luò)爬蟲

    Python 是一個(gè)高層次的結(jié)合了解釋性、編譯性、互動(dòng)性和面向?qū)ο蟮哪_本語言。這篇文章給大家介紹了python發(fā)展史及網(wǎng)絡(luò)爬蟲知識,感興趣的朋友跟隨小編一起看看吧
    2019-06-06
  • python簡單實(shí)現(xiàn)獲取當(dāng)前時(shí)間

    python簡單實(shí)現(xiàn)獲取當(dāng)前時(shí)間

    最近項(xiàng)目中經(jīng)常需要python去取當(dāng)前的時(shí)間,雖然不是很難,但是老是忘記,用一次丟一次,為了能夠更好的記住,我今天特意寫下python 當(dāng)前時(shí)間這篇文章,如果你覺的對你有用的話,可以收藏下。
    2016-08-08
  • python中反射用法實(shí)例

    python中反射用法實(shí)例

    這篇文章主要介紹了python中反射用法,實(shí)例分析了Python中反射的原理與使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-03-03
  • Python logging管理不同級別log打印和存儲(chǔ)實(shí)例

    Python logging管理不同級別log打印和存儲(chǔ)實(shí)例

    這篇文章主要介紹了Python logging管理不同級別log打印和存儲(chǔ)實(shí)例,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • 在python中pandas的series合并方法

    在python中pandas的series合并方法

    今天小編就為大家分享一篇在python中pandas的series合并方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-11-11
  • CentOS 6.X系統(tǒng)下升級Python2.6到Python2.7 的方法

    CentOS 6.X系統(tǒng)下升級Python2.6到Python2.7 的方法

    今天到新公司發(fā)現(xiàn)用的CentOS 6.X系統(tǒng),默認(rèn)安裝的Python是2.6版本,可是我的程序引用的部分庫需要2.7版本或以上,所以只能升級Python到2.7版本了,現(xiàn)在將升級的步驟分享給大家,有需要的朋友們可以參考借鑒。
    2016-10-10
  • python 安裝impala包步驟

    python 安裝impala包步驟

    這篇文章主要介紹了python 安裝impala包步驟,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03

最新評論