(五)OpenCV图像分割_09_绿幕背景视频抠图

南笙酒味 提交于 2020-02-19 07:08:20
  1. 分割算法选择
    背景融合 – 高斯模糊
    遮罩层生成
  2. 不使用GMM或者K-means:处理非常慢
    而基于色彩的处理方法
    RGB与HSV色彩空间
  3. 过程:
    加载视频、帧图像、转为HSV、模型Mask、背景融合替换、显示帧图像、下一帧(循环获取帧图像)、终止
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

Mat bg;//背景图  大小要与 视频流 大小一致
Mat Repalce_and_Belnd(Mat& frame, Mat& mask);

int main(int argc, char** argv)
{
	VideoCapture capture;
	capture.open("../path.mp4");
	if (!capture.isOpened())
	{
		printf("could not find the video file...\n");
		return -1;
	}
	bg = imread("../background.jpg");
	if (bg.empty())
	{
		cout << "could not load image..." << endl;
		return -1;
	}

	Mat frame,hsv,mask;
	while (capture.read(frame))
	{
		cvtColor(frame, hsv, COLOR_BGR2HSV);
		//测试矩阵hsv的元素是否在其他两个矩阵的值之间
		inRange(hsv, 
			Scalar(35, 43, 46), //lowberb//提取HSV中Green的值
			Scalar(155, 255, 255),//upperb
			mask);//mask = lowberb <= hsv <= upperb
		//形态学操作
		Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
		morphologyEx(mask,mask, MORPH_CLOSE, kernel);
		erode(mask, mask, kernel);
		//高斯模糊
		GaussianBlur(mask, mask, Size(3, 3), 0, 0);

		//混合图像通道
		Mat dst = Repalce_and_Belnd(frame, mask);


		char c = waitKey(1);
		if (c == 27) 
		{
			break;
		}
		//imshow("mask", mask);
		//imshow("src_Video", frame);
		imshow("Blend_video", dst);
	}
	waitKey(0);
	return 0;
}

Mat Repalce_and_Belnd(Mat& frame, Mat& mask)
{
	Mat dst = Mat::zeros(frame.size(), frame.type());
	int width = frame.cols;
	int height = frame.rows;
	int dims = frame.channels();
	//通道混合
	for (int row = 0; row < height; row++)
	{
		uchar* frame_row	= frame.ptr<uchar>(row);
		uchar* bg_row		= bg.ptr<uchar>(row);
		uchar* mask_row		= mask.ptr<uchar>(row);
		uchar* dst_row		= dst.ptr<uchar>(row);
		for (int col = 0; col < width; col++)
		{
			int temp = *mask_row++;//当前mask像素索引值
			if (temp == 255)//背景 赋予背景图的像素
			{
				*dst_row++ = *bg_row++;//b
				*dst_row++ = *bg_row++;//g
				*dst_row++ = *bg_row++;//r
				//同时*frame_row跳过一个像素值(bgr),即+3
				frame_row += 3;
			}
			else if (temp == 0)//前景 赋予原视频frame的像素
			{
				*dst_row++ = *frame_row++;//b
				*dst_row++ = *frame_row++;//g
				*dst_row++ = *frame_row++;//r
				//同时*bg_row跳过一个像素值(bgr),即+3
				bg_row += 3;
			}
			else //边缘处混合
			{
				double weight = temp / 255;//权重值
				//frame的rgb值
				int b_frame = *frame_row++;
				int g_frame = *frame_row++;
				int r_frame = *frame_row++;
				//bg的rgb值
				int b_bg = *bg_row++;
				int g_bg = *bg_row++;
				int r_bg = *bg_row++;
				int b = b_frame * weight + b_bg * (1 - weight);
				int g = g_frame * weight + g_bg * (1 - weight);
				int r = r_frame * weight + r_bg * (1 - weight);
				*dst_row++ = b;
				*dst_row++ = g;
				*dst_row++ = r;
			}
		}
	}
	return dst;
}

原视频为绿幕背景,更换同尺寸背景图片,输出结果:
在这里插入图片描述

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!