Opencv中的MeanShift图像分割和视频背景分离(python实现)

Posted Keep_Trying_Go

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Opencv中的MeanShift图像分割和视频背景分离(python实现)相关的知识,希望对你有一定的参考价值。

文章目录

1.MeanShift原理

(1)严格来说该方法并不是用来对图像进行分割的,而是在彩色层面的平滑滤波;
(2)它会中和色彩分布相近的颜色,平滑色彩细节,侵蚀掉那些面积较小的颜色区域;
(3)它以图像上任一点P为圆心,半径为sp,色彩幅值为sr进行不断的迭代;

pyrMeanShiftFiltering(src, sp, sr, dst=None, maxLevel=None, termcrit=None):

Src:输入的原始图像;
Sp:双精度半径,值越大,模糊程度越大;
Sr:色彩的幅值变化范围,变化范围越大,连成一片区域的也就是越大。
Dst:输出的图像;
maxLevel:默认值为1;
Termcrit:终止标准:何时停止meanshift迭代。

import os
import cv2
import numpy as np

img=cv2.imread('images/lenna.png')
img=cv2.resize(src=img,dsize=(450,450))
#图像分割
dst=cv2.pyrMeanShiftFiltering(src=img,sp=20,sr=30)
#图像分割(边缘的处理)
canny=cv2.Canny(image=dst,threshold1=30,threshold2=100)
#查找轮廓
conturs,hierarchy=cv2.findContours(image=canny,mode=cv2.RETR_EXTERNAL,method=cv2.CHAIN_APPROX_SIMPLE)
#画出轮廓
cv2.drawContours(image=img,contours=conturs,contourIdx=-1,color=(0,255,0),thickness=3)

cv2.imshow('img',img)
cv2.imshow('dst',dst)
cv2.imshow('canny',canny)
cv2.waitKey(0)
cv2.destroyAllWindows()

if __name__ == '__main__':
    print('Pycharm')


Canny边缘检测算法:
https://mydreamambitious.blog.csdn.net/article/details/125116318
图像查找findHomography:
https://mydreamambitious.blog.csdn.net/article/details/125385752


2.视频前后景分离

(1)MOG2去除背景

在createBackgroundSubtractorMOG的基础上进行了改进;

混合高斯模型为基础的前景或者背景分割算法

createBackgroundSubtractorMOG2(history=None, varThreshold=None, detectShadows=None):

History:进行建模的需要多长的参考帧,默认值为200;
varThreshold:判断背景模型是否能很好地描述像素。
detectShadows:阴影检测;

import os
import cv2
import numpy as np

#打开摄像头
cap=cv2.VideoCapture('video/University_Traffic.mp4')
#创建前景分离对象
bgsegment=cv2.createBackgroundSubtractorMOG2()

while cap.isOpened():
    OK,frame=cap.read()
    if OK==False:
        break
    frame=cv2.resize(src=frame,dsize=(500,500))
    fgmask=bgsegment.apply(frame)
    cv2.imshow('img',fgmask)

    if cv2.waitKey(1)&0xFF==27:
        break

cap.release()
cv2.destroyAllWindows()

if __name__ == '__main__':
    print('Pycharm')

从视频帧中可以看到MOG2产生了很多的噪点,所以对此提出了改进的方法:
GMG去除背景的方法:
静态背景图估计和每个像素的贝叶斯分割抗噪性更强;

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

星标或者置顶【OpenCV学堂】

干货教程第一时间送达!

MeanShift算法

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

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

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

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

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

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

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

OpenCV中meanshift的API函数如下:

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

参数解释

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

代码演示

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

  1. 通过VidoeCapture读取视频文件

VideoCapture cap("D:/images/video/balltest.mp4");


2. 对第一帧进行ROI选择,绘制直方图

// Object has been selected by user, set up CAMShift search properties once
Mat roi(hue, selection)maskroi(mask, selection);
calcHist(&roi, 10, maskroi, hist, 1, &hsize, &phranges);
normalize(hist, hist, 0255, 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), 255255);
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)), -18);
}


  1. 执行反向投影

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


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

meanShift(backproj, trackWindow, TermCriteria(TermCriteria::EPS | TermCriteria::COUNT, 101));
rectangle(image, trackWindow, Scalar(00255), 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(200320, CV_8UC3), backproj;
    bool paused = false;
    cap.read(frame);
    Rect selection = selectROI("CamShift Demo", frame, truefalse);

    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(264346), Scalar(34255255), mask);
        int ch[] = { 00 };
        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, 10, maskroi, hist, 1, &hsize, &phranges);
            normalize(hist, hist, 0255, 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), 255255);
            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)), -18);
            }
        }

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

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

    return 0;
}

显示效果如下:

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

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


欢迎扫码加入【OpenCV研习社】

- 学习OpenCV+tensorflow开发技术
- 与更多伙伴相互交流、一起学习进步
- 每周一到每周五分享知识点学习(音频+文字+源码)
- 系统化学习知识点,从易到难、由浅入深
- 直接向老师提问、每天答疑辅导



推荐阅读






关注【OpenCV学堂】

长按或者扫码即可关注


以上是关于Opencv中的MeanShift图像分割和视频背景分离(python实现)的主要内容,如果未能解决你的问题,请参考以下文章

使用Python,OpenCV的Meanshift 和 Camshift 算法来查找和跟踪视频中的对象

youcans 的 OpenCV 例程200篇176.图像分割之均值漂移算法 Mean Shift

从backproject到meanshift:各自的作用

常用视频目标跟踪算法仿真对比:帧间差分法,背景差分法,光流法,Meanshift,Camshift

[OpenCV-Python] OpenCV 中视频分析 部分 VI

opencv--视频操作