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

 更新时间:2022年01月11日 10:27:24   作者:Zero___Chen  
这篇文章主要介绍了如何利用OpenCV实现绿幕视频背景替换功能,文中的示例代码讲解详细,对我们学习OpenCV有一定的帮助,感兴趣的可以学习一下

前言

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

一、图像预处理

背景

绿幕视频

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

	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色彩空间转换

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

2. inRange抠图

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

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

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

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

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

三、背景替换

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

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;
}

最终效果如图所示。

四、源码

#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绿幕视频背景替换内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++分析构造函数与析造函数的特点梳理

    C++分析构造函数与析造函数的特点梳理

    本文对类的构造函数和析构函数进行总结,主要包括了构造函数的初始化、重载、使用参数和默认参数,拷贝构造函数和析构函数,希望能帮助读者在程序开发中更好的理解类,属于C/C++基础
    2022-05-05
  • C++实现通讯录系统项目实战

    C++实现通讯录系统项目实战

    这篇文章主要为大家详细介绍了C++实现通讯录系统项目实战,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • C++设计模式中的工厂模式详细介绍

    C++设计模式中的工厂模式详细介绍

    工厂模式,是一种实例化对象的方式,只要输入需要实例化对象的名字,就可以通过工厂对象的相应工厂函数来制造你需要的对象
    2022-09-09
  • C++通过共享内存ShellCode实现跨进程传输

    C++通过共享内存ShellCode实现跨进程传输

    在计算机安全领域,ShellCode是一段用于利用系统漏洞或执行特定任务的机器码,本文主要为大家介绍了C++如何通过共享内存ShellCode实现跨进程传输,需要的可以参考下
    2023-12-12
  • C++11新特性之变长参数模板详解

    C++11新特性之变长参数模板详解

    本文主要介绍了C++11变长参数模板,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-08-08
  • C++中求余运算符(%)示例详解

    C++中求余运算符(%)示例详解

    求余运算符“%”,二元运算符,具有左结合性。参与运算的量均为整型。求余运算的结果等于两个数相除后的余数。看似很简单的运算符,却也真要掌握用好它也不容易,这篇文章主要介绍了C++中求余运算符(%)的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-01-01
  • C++回调函数实现计算器和qsort

    C++回调函数实现计算器和qsort

    这篇文章主要介绍了C++回调函数实现计算器和qsort,回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数
    2022-08-08
  • C语言实现opencv提取直线、轮廓及ROI实例详解

    C语言实现opencv提取直线、轮廓及ROI实例详解

    这篇文章主要介绍了C语言实现opencv提取直线、轮廓及ROI实例详解,具有一定借鉴价值,需要的朋友可以参考下
    2018-01-01
  • C++中的封装、继承、多态理解

    C++中的封装、继承、多态理解

    这篇文章主要介绍了C++中的封装、继承、多态介绍,需要的朋友可以参考下
    2020-01-01
  • C++加密解密php代码的方法

    C++加密解密php代码的方法

    这篇文章主要介绍了C++加密解密php代码的方法,实例分析了基于C++实现加密解密的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07

最新评论