OpenCV绿幕视频背景替换
Zero___Chen 人气:0前言
本文将使用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、通过像素赋值操作达到背景替换效果。
加载全部内容