Opencv实现绿幕视频背景替换功能

所属分类: 软件编程 / C 语言 阅读数: 49
收藏 0 赞 0 分享

基于hsv颜色空间的实时背景替换: 

#include<opencv2\opencv.hpp>
using namespace cv;
Mat replace_and_blend(Mat &frame, Mat&mask);
Mat background,frame, hsv, mask,result;
int main(int arc, char** argv) { 
 background = imread("2.jpg");
 namedWindow("input", CV_WINDOW_AUTOSIZE);
 imshow("src", background);
 
 VideoCapture capture;
 capture.open("1.mp4");
 
    CvSize size = cvSize(capture.get(CV_CAP_PROP_FRAME_WIDTH), capture.get(CV_CAP_PROP_FRAME_HEIGHT)); 
 VideoWriter writer("qq.avi", VideoWriter::fourcc('M', 'J', 'P', 'G'),12.0, size, true);
  
 while (capture.read(frame)) {
 imshow("input", frame);
 cvtColor(frame, hsv, CV_BGR2HSV);
 inRange(hsv, Scalar(35, 43, 46), Scalar(77, 255, 255), mask);//颜色过滤,得到mask绿色部分为1,其它部分都为0
 imshow("mask", mask);
 Mat kernel = getStructuringElement(MORPH_RECT,Size(3,3));
 morphologyEx(mask, mask, MORPH_DILATE, kernel);
 GaussianBlur(mask, mask, Size(3, 3), 0, 0);//0,0会根据Size自动算的
 
 result = replace_and_blend(frame, mask);
        writer.write(result);
 char c = waitKey(1);
 if (c == 27) {
  break;
 } 
 imshow("input", frame);
 imshow("result", result);
 }
 waitKey(0);
 return 0;
}
 
//通过颜色过滤得到的掩码为单通道图像
Mat replace_and_blend(Mat &frame, Mat &mask)
{
 int rows = frame.rows;
 int cols = frame.cols;
 result = Mat::zeros(frame.size(), frame.type());
 for (int i = 0; i < rows; i++)
 {
 uchar *pf = frame.ptr(i);//人物前景
 uchar *pm = mask.ptr(i);//掩码
 uchar *pb = background.ptr(i);//背景
 uchar *pr = result.ptr(i);//结果
 
 for (int j = 0; j < cols; j++)
 {
  pm++;
  if (*pm == 255)//背景
  {
  pr[3 * j] = pb[3 * j];
  pr[3 * j + 1] = pb[3 * j + 1];
  pr[3 * j + 2] = pb[3 * j + 2];
  }
  else if (*pm == 0)//前景
  {
  pr[3 * j] = pf[3 * j];
  pr[3 * j + 1] = pf[3 * j + 1];
  pr[3 * j + 2] = pf[3 * j + 2];
  }
  else //融合部分
  {
  int m = *pm;
  double w = m / 255.0;
  pr[3 * j] = w *pb[3 * j] + (1-w) * pf[3 * j];
  pr[3 * j + 1] = w * pb[3 * j + 1] + (1-w) * pf[3 * j + 1];
  pr[3 * j + 2] = w * pb[3 * j + 2] + (1-w) * pf[3 * j + 2];
                //或者取前景和背景的平均值
  /*pr[3 * j] = (pb[3 * j] + pf[3 * j])/2;
  pr[3 * j + 1] = (pb[3 * j + 1] + pf[3 * j + 1])/2;
  pr[3 * j + 2] = (pb[3 * j + 2] + pf[3 * j + 2])/2;*/
  }
 }
 }
 return result; 
}

 
/*
Mat replace_and_blend(Mat &frame, Mat&mask) {
 result = Mat::zeros(frame.size(), frame.type());
 int h = frame.rows;
 int w = frame.cols;
 int dims = frame.channels();
 int m ;
 double wt ;
 int b , g, r;
 int b1, g1, r1;
 int b2 , g2, r2 ;
 //指针操作速度最快,直接访问地址
 for (int row = 0; row < h; row++) {
 uchar* current = frame.ptr<uchar>(row);
 uchar* bgrow = background.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 = wt*b1 + (1 - wt)*b2;
  g = wt*g1 + (1 - wt)*g2;
  r = wt*r1 + (1 - wt)*r2;
  *targetrow++ = b;
  *targetrow++ = g;
  *targetrow++ = r;
  }
 } 
 }
 return result;
}
*/

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

C语言数组入门之数组的声明与二维数组的模拟

这篇文章主要介绍了C语言数组入门之数组的声明与二维数组的模拟,数组学习的同时也要相应理解C语言指针的作用,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言中变量与其内存地址对应的入门知识简单讲解

这篇文章主要介绍了C语言中变量与其内存地址对应的入门知识简单讲解,同时这也是掌握指针部分知识的基础,需要的朋友可以参考下
收藏 0 赞 0 分享

讲解C语言编程中指针赋值的入门实例

这篇文章主要介绍了讲解C语言编程中指针赋值的入门实例,通过const int i与int *const pi这样两个例子来分析指针的赋值和地址指向,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言中的结构体的入门学习教程

这篇文章主要介绍了C语言中的结构体的入门学习教程,以struct语句定义的结构体是C语言编程中的重要基础,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言编程入门之程序头文件的简要解析

这篇文章主要介绍了C语言编程入门之程序头文件的简要解析,包括头文件重复包含问题等方面的说明,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言编程中的联合体union入门学习教程

这篇文章主要介绍了C语言编程中的联合体union入门学习教程,也是C语言入门学习中的基础知识,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言中数组作为函数的参数以及返回值的使用简单入门

这篇文章主要介绍了C语言中数组作为函数的参数以及返回值的使用简单入门,这里以一维数组作为基本条件进行例子讲解,需要的朋友可以参考下
收藏 0 赞 0 分享

MySQL的内存表的基础学习教程

这篇文章主要介绍了MySQL的内存表的基础学习教程,包括内存表的创建以及使用限制等等,需要的朋友可以参考下
收藏 0 赞 0 分享

C++中头文件的概念与基本编写方法

这篇文章主要介绍了C++中头文件的概念与基本编写方法,是C++入门学习中的基础知识,需要的朋友可以参考下
收藏 0 赞 0 分享

jQuery移动页面开发中主题按钮的设计示例

这篇文章主要介绍了jQuery移动页面开发中主题按钮的设计示例,jQuery是当今最具人气的JavaScript开发类库,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多