服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - 利用OpenCV实现绿幕视频背景替换

利用OpenCV实现绿幕视频背景替换

2022-08-15 10:16Zero___Chen C/C++

这篇文章主要介绍了如何利用OpenCV实现绿幕视频背景替换功能,文中的示例代码讲解详细,对我们学习OpenCV有一定的帮助,感兴趣的可以学习一下

前言

本文将使用OpenCV C++ 进行绿幕视频背景替换。

一、图像预处理

背景

利用OpenCV实现绿幕视频背景替换

绿幕视频

利用OpenCV实现绿幕视频背景替换

首先,我们需要使用resize API将背景图尺寸修改与视频尺寸大小。这样才能进行后续的像素赋值操作。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Mat bg = imread("background.jpg");  //背景图
 
VideoCapture capture;  //读取待处理的绿幕视频
capture.open("5.flv");
if (!capture.isOpened())
{
    cout << "Can not open video!" << endl;
    system("pause");
    return -1;
}
 
int width = capture.get(CAP_PROP_FRAME_WIDTH);
int height = capture.get(CAP_PROP_FRAME_HEIGHT);
 
resize(bg, bg, Size(width, height), 1, 1, INTER_CUBIC);  //将背景图resize成视频尺寸大小

二、HSV色彩空间转换

1. cvtColor色彩空间转换

?
1
cvtColor(frame, HSV, COLOR_BGR2HSV);   //将原图转换成HSV色彩空间

2. inRange抠图

经百度查表,我们可以获取绿色HSV颜色分量范围

?
1
2
3
//绿色HSV颜色分量范围
int hmin = 35, smin = 43, vmin = 46;
int hmax = 77, smax = 255, vmax = 255;

由于我们已经将原图转换为HSV色彩空间,故可以使用inRange API将前景从绿幕中抠出来。inRange将两阈值内的像素置为255(即绿色被置为白色),阈值外的像素置为0(其他颜色被置为黑色)。故由此我们可以将前景抠出来。

?
1
2
//经过inRange API处理,输出一张二值图像,即将前景从绿幕中扣出来啦
inRange(HSV, Scalar(hmin, smin, vmin), Scalar(hmax, smax, vmax), mask);

利用OpenCV实现绿幕视频背景替换

mask图像,即从绿幕中抠出来的前景图。

三、背景替换

我们通过修改图像像素值达到替换背景目的。通过遍历视频图像像素值,当mask像素值为0时,表示此时图像像素为前景,将绿幕视频当前像素点赋给目标图像dst;当mask像素值为255时,表示此时图像像素为背景,将背景图当前像素点赋给目标图像dst。

?
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
Mat Replace_Background(Mat frame, Mat mask, Mat bg)
{
    Mat dst = Mat::zeros(frame.size(), frame.type());
 
    for (int i = 0; i < frame.rows; i++)
    {
        for (int j = 0; j < frame.cols; j++)
        {
            int p = mask.at<uchar>(i, j);  //传入的mask是张二值图,p为当前mask像素值
 
            if (p == 0)
            {   //代表mask此时为前景,将绿幕视频中的前景像素赋给dst
                dst.at<Vec3b>(i, j) = frame.at<Vec3b>(i, j);
            }
            else if (p == 255)
            {
                //代表mask此时为背景,将背景图像素赋给dst
                dst.at<Vec3b>(i, j) = bg.at<Vec3b>(i,j);
            }
 
        }
    }
 
    return dst;
}

利用OpenCV实现绿幕视频背景替换

最终效果如图所示。

利用OpenCV实现绿幕视频背景替换

利用OpenCV实现绿幕视频背景替换

利用OpenCV实现绿幕视频背景替换

四、源码

?
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
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
 
 
Mat Replace_Background(Mat frame, Mat mask, Mat bg)
{
    Mat dst = Mat::zeros(frame.size(), frame.type());
 
    for (int i = 0; i < frame.rows; i++)
    {
        for (int j = 0; j < frame.cols; j++)
        {
            int p = mask.at<uchar>(i, j);  //传入的mask是张二值图,p为当前mask像素值
 
            if (p == 0)
            {   //代表mask此时为前景,将绿幕视频中的前景像素赋给dst
                dst.at<Vec3b>(i, j) = frame.at<Vec3b>(i, j);
            }
            else if (p == 255)
            {
                //代表mask此时为背景,将背景图像素赋给dst
                dst.at<Vec3b>(i, j) = bg.at<Vec3b>(i,j);
            }
 
        }
    }
 
    return dst;
}
 
int main()
{
 
    Mat bg = imread("background.jpg");  //背景图
 
    VideoCapture capture;  //读取待处理的绿幕视频
    capture.open("5.flv");
    if (!capture.isOpened())
    {
        cout << "Can not open video!" << endl;
        system("pause");
        return -1;
    }
 
    int width = capture.get(CAP_PROP_FRAME_WIDTH);
    int height = capture.get(CAP_PROP_FRAME_HEIGHT);
 
    resize(bg, bg, Size(width, height), 1, 1, INTER_CUBIC);  //将背景图resize成视频尺寸大小
 
    Mat frame, HSV, mask, dst;
    //绿色HSV颜色分量范围
    int hmin = 35, smin = 43, vmin = 46;
    int hmax = 77, smax = 255, vmax = 255;
 
    while (capture.read(frame))
    {
 
        cvtColor(frame, HSV, COLOR_BGR2HSV);   //将原图转换成HSV色彩空间
 
        //经过inRange API处理,输出一张二值图像,即将前景从绿幕中扣出来啦
        inRange(HSV, Scalar(hmin, smin, vmin), Scalar(hmax, smax, vmax), mask);
 
        dst = Replace_Background(frame, mask, bg);
 
        imshow("demo", frame);
        //imwrite("frame.jpg", frame);
        imshow("mask", mask);
        //imwrite("mask.jpg", mask);
        imshow("dst", dst);
        //imwrite("dst.jpg", dst);
 
        char key = waitKey(10);
 
        if (key == 27)
        {
            break;
        }
    }
 
    destroyAllWindows();
    capture.release();
    system("pause");
    return 0;
}

总结

本文使用OpenCV C++进行绿幕视频背景替换,关键步骤有以下几点。

1、将原图转换成HSV色彩空间。

2、使用inRange API将前景从绿幕中抠出来,得到一张二值图。

3、通过像素赋值操作达到背景替换效果。

到此这篇关于利用OpenCV实现绿幕视频背景替换的文章就介绍到这了,更多相关OpenCV绿幕视频背景替换内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/Zero___Chen/article/details/121869696

延伸 · 阅读

精彩推荐
  • C/C++C++中的变长参数深入理解

    C++中的变长参数深入理解

    变长参数的函数,即参数个数可变、参数类型不定的函数。设计一个参数个数可变、参数类型不定的函数是可能的,最常见的例子是printf函数、scanf函数和...

    kevonyang4052021-04-18
  • C/C++解析ActiveMQ的使用说明总结

    解析ActiveMQ的使用说明总结

    本篇文章是对ActiveMQ的使用进行了详细的分析介绍,需要的朋友参考下...

    C语言教程网5782020-12-01
  • C/C++C/C++ Qt MdiArea 多窗体组件应用教程

    C/C++ Qt MdiArea 多窗体组件应用教程

    MDI窗体控件类似于画布,该控件只具备展示窗体的功能,无法实现生成窗体,所以我们需要在项目中手动增加自定义的Dialog对话框,并对该对话框进行一定...

    Lyshark6692022-03-08
  • C/C++C++野指针和悬空指针的实现方法

    C++野指针和悬空指针的实现方法

    野指针和悬空指针是指针中常见的两个概念,本文详细的介绍了这两种的使用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    Linux猿9132021-12-13
  • C/C++C++二分法在数组中查找关键字的方法

    C++二分法在数组中查找关键字的方法

    这篇文章主要介绍了C++二分法在数组中查找关键字的方法,涉及C++数组查找算法的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    清清飞扬11652021-03-15
  • C/C++C语言拓展实现Lua sleep函数

    C语言拓展实现Lua sleep函数

    这篇文章主要介绍了C语言拓展实现Lua sleep函数,本文使用C语言写出sleep函数,编译后在Lua中调用,需要的朋友可以参考下...

    C语言教程网7692021-02-25
  • C/C++C语言数据结构之双向循环链表的实例

    C语言数据结构之双向循环链表的实例

    这篇文章主要介绍了C语言数据结构之双向循环链表的实例的相关资料,需要的朋友可以参考下...

    C语言教程网7592021-05-20
  • C/C++Opencv实现图像灰度线性变换

    Opencv实现图像灰度线性变换

    这篇文章主要为大家详细介绍了Opencv实现图像灰度线性变换,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    东城青年5282021-07-29