信息发布→ 登录 注册 退出

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

发布时间:2026-01-11

点击量:
目录
  • 前言
  • 一、图像预处理
  • 二、HSV色彩空间转换
    • 1. cvtColor色彩空间转换
    • 2. inRange抠图
  • 三、背景替换
    • 四、源码
      • 总结

        前言

        本文将使用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、通过像素赋值操作达到背景替换效果。

        在线客服
        服务热线

        服务热线

        4008888355

        微信咨询
        二维码
        返回顶部
        ×二维码

        截屏,微信识别二维码

        打开微信

        微信号已复制,请打开微信添加咨询详情!