视频绿幕替换
将视频中绿幕背景替换为其它图片,新闻报道中常用
处理方法
- GMM或者KMeans方法太慢,视频容易卡顿
- 基于色彩处理方法
- RGB到HSV色彩空间,颜色过滤获取掩膜,速度快
HSV空间各种颜色分布范围
代码
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace std;
using namespace cv;
Mat frame,hsv,mask,dst;
Mat bkimg;
Mat replace_and_blend(Mat &frame,Mat &mask);
int main(void)
{
bkimg = imread("/work/opencv_pic/lijing.jpg");
if(bkimg.empty())
{
cout << "back img is empty"<< endl;
return -1;
}
namedWindow("原始视频",0);
resizeWindow("原始视频",640,360);
moveWindow("原始视频",50,20);
namedWindow("效果视频",0);
resizeWindow("效果视频",640,360);
moveWindow("效果视频",2000,20);
namedWindow("背景图片",0);
resizeWindow("背景图片",640,360);
moveWindow("背景图片",300,800);
imshow("背景图片",bkimg);
VideoCapture cap;
if(!cap.open("/work/opencv_video/绿屏抠像花瓣雨素材.mp4"))
{
cout<<"open video fail" <<endl;
return -1;
}
while(true)
{
cap>>frame;
if(frame.empty())
{
cout << "frame is empty"<<endl;
break;
}
imshow("原始视频",frame);
cvtColor(frame,hsv,COLOR_BGR2HSV);
//颜色选择
inRange(hsv,Scalar(35,43,46),Scalar(77,255,255),mask);
//图形学处理 平滑mask;
Mat kernel = getStructuringElement(MORPH_RECT,Size(3,3));
morphologyEx(mask,mask,MORPH_OPEN,kernel);
//高斯处理 边缘更平滑 效果更好看
GaussianBlur(mask,mask,Size(3,3),0,0);
dst = replace_and_blend(frame,mask);
imshow("效果视频",dst);
if(waitKey(1)>0)
break;
}
destroyAllWindows();
return 0;
}
Mat replace_and_blend(Mat &frame,Mat &mask)
{
Mat result = Mat::zeros(frame.size(),frame.type());
int h = frame.rows;
int w = frame.cols;
int m = 0;
double wt = 0;
int b=0,g=0,r=0;
int b1=0,g1=0,r1=0;
int b2=0,g2=0,r2=0;
for(int row=0;row <h;row++)
{
uchar *current = frame.ptr<uchar>(row);
uchar *bgrow = bkimg.ptr<uchar>(row);
uchar *maskrow = mask.ptr<uchar>(row);
uchar *targetrow = result.ptr<uchar>(row);
for(int col=0;col<w;col++)
{
m = *maskrow++;
if(m == 255) //如果是背景 替换为背景数据
{
*targetrow++ = *bgrow++;
*targetrow++ = *bgrow++;
*targetrow++ = *bgrow++;
current += 3;
}else if(m == 0) //如果是前景 保留原来数据
{
*targetrow++ = *current++;
*targetrow++ = *current++;
*targetrow++ = *current++;
bgrow += 3;
}else //由于形态学平滑造成的过渡区 颜色采用加权均衡化
{
b1 = *bgrow++;
g1 = *bgrow++;
r1 = *bgrow++;
b2 = *current++;
g2 = *current++;
r2 = *current++;
wt = m/255.0;
b = b1*wt + b2*(1-wt);
g = g1*wt + g2*(1-wt);
r = b1*wt + r2*(1-wt);
*targetrow++ = b;
*targetrow++ = g;
*targetrow++ = r;
}
}
}
return result; //返回结果
}