【OpenCV】 视频处理(读取视频、写入视频、目标检测、特征匹配、相机校正)

https://www.hahack.com/wiki/opencv-video.html#

参考资料:

  • 《OpenCV 2 Computer Vision Application Programming Cookbook》
  • 《The OpenCV Reference Manual》

读取视频

 使用 CV::VideoCapture 来读取视频序列。

#include <stdio.h>
#include <string>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
int main()
{
    // Open the video file
    cv::VideoCapture capture("../stomp.avi");
    // check if video successfully opened
    if (!capture.isOpened())
        return 1;
    // Get the frame rate
    double rate = capture.get(CV_CAP_PROP_FPS);
    bool stop(false);
    cv::Mat frame;  // current video frame
    cv::namedWindow("Extracted Frame");
    // Delay between each frame in ms
    // corresponds to video frame rate
    int delay = 1000 / rate;
    // for all frames in video
    while (!stop){
        // read next frame if any
        if (!capture.read(frame))
            break;
        cv::imshow("Extracted Frame", frame);
        // introduce a delay
        // or press key to stop
        if (cv::waitKey(delay) >= 0)
            stop = true;
    }
    // Close the video file
    // Not required since called by destructor
    capture.release();
}

 也可以通过类似的方法读入摄像头捕捉的视频,要改动的地方仅仅是将上面的视频文件名改为摄像头的 ID,默认的摄像头 ID 为 0。

写入视频

使用 CV::VideoWriter 来写入视频。

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include <dbg.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;
int main()
{
    VideoCapture cap;
    cap.open(0);
    namedWindow("MyVideo", 1);
    double dWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH);
    double dHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
    Size frameSize(static_cast<int>(dWidth), static_cast<int>(dHeight));
    
    VideoWriter oVideoWriter("MyVideo.avi", CV_FOURCC('P','I','M','1'), 20, frameSize, true);	// initialize the VideoWriter objetct
    while (1) {
        Mat frame;
        bool bSuccess = cap.read(frame);
        if (!bSuccess){ // if not success, break loop
            cout << "ERROR: cannot read a frame from video file" << endl;
            break;
        }
        
        oVideoWriter.write(frame);
        imshow("MyVideo", frame); // show the frame in "MyVideo" window
        if(waitKey(10) == 27) {// wait for ESC key
            cout << "ESC key is pressed by user" << endl;
            break;
        }
    }
    
    return 0;
}

 目标检测


mean-shift 和 camshift


均值漂移(mean-shift)

mean-shift 算法是一种在一组数据的密度分布中寻找局部极值的稳定 [1] 的方法。若分布是连续的,处理过程就比较容易,这种情况下本质上只需要对数据的密度直方图应用爬山算法即可。然而,对于离散的数据集,这个问题在某种程度上是比较麻烦的。

mean-shift 算法的步骤如下:

  1. 选择搜索窗口。
  2. 计算窗口(可能是带权重的)的重心。
  3. 将窗口的中心设置在计算出的重心处。
  4. 返回第 2 步,直到窗口的位置不再变化(通常会)。

OpenCV 提供 cv::meanshift() 函数来进行 mean-shift 算法跟踪。

int cv::meanShift(InputArray probImage, Rect& window, TermCriteria criteria)

其中,

  • probImage - 图像直方图反投影后的结果;
  • window - 初始的查找窗口,即要跟踪的区域;
  • criteria - 迭代搜索算法的终止条件,主要由 mean-shift 移动的最大迭代次数和可视为窗口位置收敛的最小移动距离组成。
  • 返回的是收敛时算法的迭代次数。

对于第一个参数 probImage ,可以直接使用 cv::calcBackProject() 得到的结果。但《OpenCV 2 Computer Vision Application Programming Cookbook》建议先把图像转换到 HSV 颜色空间,然后使用 Hue 单通道的直方图的反投影变换结果作为 probImage ;

获取彩色图像的 Hue 通道的直方图算法实现如下:

// Computes the 1D Hue histogram with a mask.
// BGR source image is converted to HSV
cv::MatND getHueHistogram(const cv::Mat &image,
                             int minSaturation = 0) {
    cv::MatND hist;
    // Convert to HSV color space
    cv::Mat hsv;
    cv::cvtColor(image, hsv, CV_BGR2HSV);
       // Mask to be used (or not)
       cv::Mat mask;
       if (minSaturation > 0) {
           // Spliting the 3 channels into 3 images
           std::vector<cv::Mat> v;
           cv::split(hsv, v);
           // Mask out the low saturated pixels
           cv::threshold(v[1], mask, minSaturation,
                         255, cv::THRESH_BINARY);
       }
    // Prepare arguments for a 1D hue histogram
    hranges[0]= 0.0;
    hranges[1]= 180.0;
    channels[0]= 0; // the hue channel
       // Compute histogram
    cv::calcHist(&hsv, 
        1,			// histogram of 1 image only
        channels,	// the channel used
        mask,	// no mask is used
        hist,		// the resulting histogram
        1,			// it is a 1D histogram
        histSize,	// number of bins
        ranges		// pixel value range
    );
    return hist;
}

使用 cv::meanshift() 函数在两幅图像间跟踪某一物体的步骤如下:

  1. 读入第一张图像,定义好目标跟踪窗口,即感兴趣区域
  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值