zoukankan      html  css  js  c++  java
  • 图像分割实战-视频背景替换


    1 . 读取并播放视频

    利用 VideoCapture 类来对视频进行读取显示。有两种读入视频的方法:
    先实例化再初始化 :
    VideoCapture capture ;
    capture .open(“bike.avi”);

    在实例化的同时进行初始化;
    VideoCapture capture (“bike.avi”);

    例子代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34

    #include<iostream>
    using namespace cv;
    using namespace std;
    void ()
    {

    VideoCapture capture("bike.avi");
    if (!capture.isOpened())
    {
    cout << "could not find the video file...n" << endl;
    }
    //循环显示每一帧
    while (true)
    {
    Mat frame; //定义一个 Mat 变量,用于存储每一帧的图像
    capture >> frame; //读取当前帧
    if (!frame.empty())
    {
    imshow("Original Video", frame); //显示当前帧
    waitKey(30); //延时 30ms
    }
    else
    {
    break;
    }
    }
    }

    int main()
    {
    test();
    return 0;
    }

    2 . 案例实战

    实现一个视频背景的替换,和上一节的图片背景替换类似,只是把视频分解成一帧一帧读出来进行处理。
    步骤:

    • 分割算法的选择。算法可以选择 GMM 、KMeans 、基于色彩的处理方法、GRB与HSV色彩空间等,这里采用GRB与HSV色彩空间。

    1.png | center | 300x0

    • 背景融合 - 高斯模糊。
    • 遮罩层生成。

    基本流程图:

    2.png | center | 300x0

    例子代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113

    #include<iostream>
    using namespace cv;
    大专栏  图像分割实战-视频背景替换ord">using namespace std;
    Mat backgrount01;
    Mat replaceAndBiend(Mat &frame, Mat &maskImg);
    void ()
    {
    backgrount01 = imread("bg_01.jpg");
    VideoCapture capture("01.mp4");

    if (!capture.isOpened())
    {
    cout << "could not find the video file...n" << endl;
    }
    Mat frame,hsvImg,maskImg;
    int count = 0;
    namedWindow("Origianl Video", CV_WINDOW_NORMAL);
    namedWindow("result Video", CV_WINDOW_NORMAL);
    while (capture.read(frame))
    {
    //获取 mask
    cvtColor(frame, hsvImg, COLOR_BGR2HSV);
    inRange(hsvImg, Scalar(34, 43, 46), Scalar(155, 255, 255), maskImg);

    //形态学操作
    Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
    morphologyEx(maskImg, maskImg, MORPH_CLOSE, kernel);
    erode(maskImg, maskImg,kernel);
    GaussianBlur(maskImg, maskImg, Size(3, 3), 0, 0);

    Mat result = replaceAndBiend(frame, maskImg);
    char c = waitKey(50);
    if (c == 27)
    {
    break;
    }
    imshow("Origianl Video", frame);
    imshow("result Video", result);
    }
    }
    //进行通道混合的函数
    Mat replaceAndBiend(Mat &frame, Mat &maskImg)
    {
    //返回结果图像
    Mat result = Mat::zeros(frame.size(), frame.type());
    int h = frame.rows;
    int w = frame.cols;
    int dims = frame.channels();

    int m = 0;
    double wt = 0;

    int r = 0, g = 0, b = 0;
    int r1 = 0, g1 = 0, b1 = 0;
    int r2 = 0, g2 = 0, b2 = 0;

    //这次用指针变量图像
    for (int row = 0; row < h; row++)
    {
    uchar *curent = frame.ptr<uchar>(row);
    uchar *bgrow = backgrount01.ptr<uchar>(row);
    uchar *maskrow = maskImg.ptr<uchar>(row);
    uchar *targetrow = result.ptr<uchar>(row);
    for (int col=0; col < w; col++)
    {
    m = *maskrow++;
    if (m == 255) //背景
    {
    //三个通道都赋予背景的值
    *targetrow++ = *bgrow++;
    *targetrow++ = *bgrow++;
    *targetrow++ = *bgrow++;
    curent += 3;
    }
    else if (m == 0) //前景
    {
    *targetrow++ = *curent++;
    *targetrow++ = *curent++;
    *targetrow++ = *curent++;
    bgrow += 3;
    }
    else
    {
    b1 = *bgrow++;
    g1 = *bgrow++;
    r1 = *bgrow++;

    b2 = *curent++;
    g2 = *curent++;
    r2 = *curent++;

    //权重
    wt = m / 255.0;
    //通道混合
    b = b1*wt + b2*(1.0 - w);
    g = g1*wt + g2*(1.0 - w);
    r = r1*wt + r2*(1.0 - w);

    *targetrow++ = b;
    *targetrow++ = g;
    *targetrow++ = r;
    }
    }
    }
    return result;
    }
    int main()
    {
    test();
    waitKey(0);
    return 0;
    }

    效果图:

    3.png | center | 300x0

    例子图片链接:

    VS+OpenCV安装包链接:



  • 相关阅读:
    android120 zhihuibeijing 开机页面
    Android View.onMeasure方法的理解
    android119 侧滑菜单
    android事件拦截处理机制详解
    Android应用在不同版本间兼容性处理
    虚拟机重置密码
    ESXi虚拟机开机进入bios的方法
    [日常工作]Win2008r2 以及更高版本的操作系统安装Oracle10.2.0.5
    Linux下安装oracle的过程
    Oracle18c Exadata 版本安装介质安装失败。
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12433083.html
Copyright © 2011-2022 走看看