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

算法设计步骤:

由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;
}

效果:

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值