OpenCV中MeanShift算法视频移动对象分析

简介:

MeanShift算法
Mean Shift是一种聚类算法,在数据挖掘,图像提取,视频对象跟踪中都有应用。OpenCV在图像处理模块中使用均值迁移可以实现去噪、边缘保留滤波等操作。在视频分析模块中使用均值迁移算法结合直方图反向投影算法实现对移动对象分析,是一种非常稳定的视频移动对象跟踪算法。其核心的思想是对反向投影之后的图像做均值迁移(meanshift)从而发现密度最高的区域,也是对象分布最大的区域,均值迁移的原理可以通过下面这张图来解释:

image
会从初始化的中心位置,通过计算生成新的中心位置坐标,dx与dy就是均值迁移每次移动的步长,移动到新的中心之后,会基于新的分布进行中心位置计算,如此不断迭代,直到中心位置处于最大分布为止。

MeanShift移动对象分析,首先会读取视频第一帧,选择ROI区域,生成直方图。然后对视频中的每一帧执行如下操作:

1.直方图反向投影该帧
2.基于前一帧的窗口位置,使用means shift寻找新的最大分布密度,生成新位置窗口
3.更新窗口直至最后一帧
image
image
OpenCV中meanshift的API函数如下:

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

参数解释

probImage 输入图像,是直方图反向投影的结果
window 搜索窗口,ROI对象区域,每帧会自动更新窗口
criteria 均值迁移停止条件

代码演示
代码实现分为如下几个部分

通过VidoeCapture读取视频文件

VideoCapture cap("D:/images/video/balltest.mp4");
  1. 对第一帧进行ROI选择,绘制直方图
// Object has been selected by user, set up CAMShift search properties once
Mat roi(hue, selection), maskroi(mask, selection);
calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
normalize(hist, hist, 0, 255, NORM_MINMAX);

trackWindow = selection;
trackObject = 1; // Don't set up again, unless user selects new ROI

histimg = Scalar::all(0);
int binW = histimg.cols / hsize;
Mat buf(1, hsize, CV_8UC3);
for (int i = 0; i < hsize; i++)
    buf.at<Vec3b>(i) = Vec3b(saturate_cast<uchar>(i*180. / hsize), 255, 255);
cvtColor(buf, buf, COLOR_HSV2BGR);

for (int i = 0; i < hsize; i++)
{
    int val = saturate_cast<int>(hist.at<float>(i)*histimg.rows / 255);
    rectangle(histimg, Point(i*binW, histimg.rows),
        Point((i + 1)*binW, histimg.rows - val),
        Scalar(buf.at<Vec3b>(i)), -1, 8);
}

执行反向投影

calcBackProject(&hue, 1, 0, hist, backproj, &phranges);

执行MeanShift均值迁移分析,得到每帧移动位置信息, 并完成绘制

meanShift(backproj, trackWindow, TermCriteria(TermCriteria::EPS | TermCriteria::COUNT, 10, 1));
rectangle(image, trackWindow, Scalar(0, 0, 255), 3, LINE_AA);

完整的演示代码如下

#include <opencv2/opencv.hpp>"
#include <iostream>
#include <ctype.h>

using namespace cv;
using namespace std;

Mat image;
bool selectObject = false;
int trackObject = 0;
bool showHist = true;
Point origin;
Rect selection;
int vmin = 10, vmax = 256, smin = 30;

int main(int argc, const char** argv)
{
    // VideoCapture cap(0);
    VideoCapture cap("D:/images/video/balltest.mp4");
    Rect trackWindow;
    int hsize = 16;
    float hranges[] = { 0,180 };
    const float* phranges = hranges;

    if (!cap.isOpened())
    {
        printf("could not open camera...\n");
        return -1;
    }

    namedWindow("Histogram", WINDOW_AUTOSIZE);
    namedWindow("CamShift Demo", WINDOW_AUTOSIZE);

    Mat frame, hsv, hue, mask, hist, histimg = Mat::zeros(200, 320, CV_8UC3), backproj;
    bool paused = false;
    cap.read(frame);
    Rect selection = selectROI("CamShift Demo", frame, true, false);

    while(true)
    {
        bool ret = cap.read(frame);
        if (!ret) break;
        frame.copyTo(image);

        cvtColor(image, hsv, COLOR_BGR2HSV);

        int _vmin = vmin, _vmax = vmax;
        inRange(hsv, Scalar(26, 43, 46), Scalar(34, 255, 255), mask);
        int ch[] = { 0, 0 };
        hue.create(hsv.size(), hsv.depth());
        mixChannels(&hsv, 1, &hue, 1, ch, 1);

        if (trackObject <= 0)
        {
            // Object has been selected by user, set up CAMShift search properties once
            Mat roi(hue, selection), maskroi(mask, selection);
            calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
            normalize(hist, hist, 0, 255, NORM_MINMAX);

            trackWindow = selection;
            trackObject = 1; // Don't set up again, unless user selects new ROI

            histimg = Scalar::all(0);
            int binW = histimg.cols / hsize;
            Mat buf(1, hsize, CV_8UC3);
            for (int i = 0; i < hsize; i++)
                buf.at<Vec3b>(i) = Vec3b(saturate_cast<uchar>(i*180. / hsize), 255, 255);
            cvtColor(buf, buf, COLOR_HSV2BGR);

            for (int i = 0; i < hsize; i++)
            {
                int val = saturate_cast<int>(hist.at<float>(i)*histimg.rows / 255);
                rectangle(histimg, Point(i*binW, histimg.rows),
                    Point((i + 1)*binW, histimg.rows - val),
                    Scalar(buf.at<Vec3b>(i)), -1, 8);
            }
        }

        // Perform meanShift
        calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
        backproj &= mask;
        meanShift(backproj, trackWindow, TermCriteria(TermCriteria::EPS | TermCriteria::COUNT, 10, 1));
        rectangle(image, trackWindow, Scalar(0, 0, 255), 3, LINE_AA);

        imshow("CamShift Demo", image);
        imshow("Histogram", histimg);
        char c = (char)waitKey(50);
        if (c == 27)
            break;
    }

    return 0;
}

显示效果如下:
image
image

原文发布时间为:2018-12-19
本文作者:gloomyfish
本文来自云栖社区合作伙伴“ OpenCV学堂”,了解相关信息可以关注“CVSCHOOL”微信公众号

相关文章
|
4天前
|
算法 搜索推荐 Java
Java数据结构 -- 常见算法分析(查找算法、排序算法)精解详解!!!
Java数据结构 -- 常见算法分析(查找算法、排序算法)精解详解!!!
7 0
|
7天前
|
搜索推荐 算法 程序员
常见排序算法及其稳定性分析
常见排序算法及其稳定性分析
|
7天前
|
存储 算法 搜索推荐
【大数据分析与挖掘技术】Mahout推荐算法
【大数据分析与挖掘技术】Mahout推荐算法
12 0
|
13天前
|
存储 计算机视觉 流计算
【OpenCV】计算视频的光流并跟踪物体calcOpticalFlowPyrLK
【OpenCV】计算视频的光流并跟踪物体calcOpticalFlowPyrLK
22 0
|
13天前
|
算法 计算机视觉
基于高斯混合模型的视频背景提取和人员跟踪算法matlab仿真
该内容是关于使用MATLAB2013B实现基于高斯混合模型(GMM)的视频背景提取和人员跟踪算法。算法通过GMM建立背景模型,新帧与模型比较,提取前景并进行人员跟踪。文章附有程序代码示例,展示从读取视频到结果显示的流程。最后,结果保存在Result.mat文件中。
|
13天前
|
算法
视频讲解|基于多目标粒子群算法的配电网储能选址定容
视频讲解|基于多目标粒子群算法的配电网储能选址定容
|
13天前
|
机器学习/深度学习 自然语言处理 算法
Python遗传算法GA对长短期记忆LSTM深度学习模型超参数调优分析司机数据|附数据代码
Python遗传算法GA对长短期记忆LSTM深度学习模型超参数调优分析司机数据|附数据代码
|
13天前
|
机器学习/深度学习 算法 数据可视化
Matlab决策树、模糊C-均值聚类算法分析高校教师职称学历评分可视化
Matlab决策树、模糊C-均值聚类算法分析高校教师职称学历评分可视化
|
13天前
|
编解码 API 计算机视觉
opencv从视频文件读取视频内容,从摄像头读取保存视频内容
opencv从视频文件读取视频内容,从摄像头读取保存视频内容
|
13天前
|
机器学习/深度学习 算法 数据挖掘
【视频】支持向量机算法原理和Python用户流失数据挖掘SVM实例(下)
【视频】支持向量机算法原理和Python用户流失数据挖掘SVM实例(下)