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

相关文章

  • 输入一个字符串,取出其中的整数(实现代码)

    输入一个字符串,取出其中的整数(实现代码)

    输入一个字符串,内含所有数字和非数字字符。将其中连续的数字作为一个整数,依次存放到一个数组中,统计共有多少个整数,并输出这些数
    2013-09-09
  • C++中atof 函数的介绍

    C++中atof 函数的介绍

    这篇文章主要给大家分享的是C++中atof 函数的介绍,在 stdlib.h 中 atof 函数,可用于将 char 字符串转为 float / double 浮点数类型,想具体了解语法的小伙伴可以参考下面文章的内容,希望对大家有所帮助
    2021-11-11
  • Qt TCP网络通信学习

    Qt TCP网络通信学习

    用于数据传输的低层网络协议,多个物联网协议都是基于TCP协议的,这篇文章为大家介绍了Qt TCP网络通信,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • C语言实现查看进程是否存在的方法示例

    C语言实现查看进程是否存在的方法示例

    这篇文章主要介绍了C语言实现查看进程是否存在的方法,涉及C语言针对进程操作的相关实现技巧,需要的朋友可以参考下
    2017-07-07
  • C++图论之Bellman-Ford算法和SPFA算法的实现

    C++图论之Bellman-Ford算法和SPFA算法的实现

    贝尔曼-福特算法(Bellman-Ford)是由理查德·贝尔曼和莱斯特·福特创立的,求解单源最短路径问题的一种算法。SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径。本文将详解两个算法的实现,需要的可以参考一下
    2022-06-06
  • C语言实现电子邮件地址验证程序

    C语言实现电子邮件地址验证程序

    这篇文章主要介绍了C语言实现电子邮件地址验证程序,利用的是POSIX正则表达式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2015-11-11
  • 详解C++引用变量时那些你不知道的东西

    详解C++引用变量时那些你不知道的东西

    这篇文章主要为大家详细介绍了C++引用变量时那些你不知道的东西——引用变量延迟绑定,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2022-11-11
  • C语言 指针综合解析

    C语言 指针综合解析

    指针可以表示一个变更的地址,在计算机程序中,通常表示内存地址,存储数据的地址,下面这篇文章主要给大家综合的介绍了关于C语言指针的本质与用法
    2021-11-11
  • C++ STL反向迭代器的实现

    C++ STL反向迭代器的实现

    本文主要介绍了C++ STL反向迭代器的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • C&C++设计风格选择 命名规范

    C&C++设计风格选择 命名规范

    本文难免带有主观选择倾向,但是会尽量保持客观的态度归纳几种主流的命名风格,仅供参考
    2018-04-04

最新评论