OpenCV之图像分割(六) 绿幕背景视频抠图

论坛 期权论坛 编程之家     
选择匿名的用户   2021-5-29 23:40   66   0

算法设计步骤:

由RGB图像转到HSV(H:色调,S:饱和度,V:亮度),利用hsv在绿幕背景中的颜色范围是,使用inRang函数进行二值

代码:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

Mat replace_and_blend(Mat &frame, Mat &mask);
Mat background_01;
Mat background_02;
int main(int argc, char** argv) {
 // start here... 
 background_01 = imread("bg001.jpg");
 background_02 = imread("bg004.jpg");
 Mat sizeImg = imread("标准尺寸.png");
 if (background_01.empty() || background_02.empty())
 {
  printf("could not load image...\n");
  return -1;
 }
 resize(background_01, background_01, Size(sizeImg.cols, sizeImg.rows), 0, 0, INTER_LINEAR);
 resize(background_02, background_02, Size(sizeImg.cols, sizeImg.rows), 0, 0, INTER_LINEAR);

 VideoCapture capture;
 capture.open("01.mp4");
 if (!capture.isOpened()) {
  printf("could not find the video file...\n");
  return -1;
 }
 char* title = "input video";
 char* resultWin = "result video";
 namedWindow(title, 0);
 namedWindow(resultWin, 0);
 Mat frame, hsv, mask;
 Mat mask_erode, mask_blur, mask_close;
 int count = 0;
 while (capture.read(frame)) {
  cvtColor(frame, hsv, COLOR_BGR2HSV);
  /*
  从读取像素到转到hsv空间,后经过inRang的处理,这个处理类似于threshold二值(只能处理单通道的图像),
  通过上下限的方式二值(可处理单通道或多通道),经过这个处理后得到一个二值化的Mat,因为inRang后的图像边缘存在噪点
  使用通过形态学闭操作消除小白点,得到的图像进行边缘羽化处理
  羽化处理:使用腐蚀的方法将人物的mask向外腐蚀一个边界像素,
  然后用高斯模糊,进行梯度边缘处理,得到最终的预处理效果
  */
  inRange(hsv, Scalar(35, 43, 46), Scalar(155, 255, 255), mask);
  // 形态学操作
  Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
  morphologyEx(mask, mask_close, MORPH_CLOSE, k);
  erode(mask_close, mask_erode, k);
  GaussianBlur(mask_erode, mask_blur, Size(3, 3), 0, 0);

  Mat result = replace_and_blend(frame, mask_blur);
  char c = waitKey(30);
  if (c == 27) {
   break;
  }
  imshow(resultWin, result);
  imshow(title, frame);
 }

 waitKey(0);
 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 dims = frame.channels();

 // replace and blend
 int m = 0;
 double wt = 0;

 int r = 0, g = 0, b = 0;
 int r1 = 0, g1 = 0, b1 = 0;
 int r2 = 0, g2 = 0, b2 = 0;

 for (int row = 0; row < h; row++) {
  uchar* current = frame.ptr<uchar>(row);
  uchar* bgrow = background_02.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.0 - wt);
    g = g1*wt + g2*(1.0 - wt);
    r = r1*wt + r2*(1.0 - wt);

    *targetrow++ = b;
    *targetrow++ = g;
    *targetrow++ = r;
   }
  }
 }

 return result;
}

效果:

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP