利用OpenCV實(shí)現(xiàn)綠幕視頻背景替換
前言
本文將使用OpenCV C++ 進(jìn)行綠幕視頻背景替換。
一、圖像預(yù)處理
背景
綠幕視頻
首先,我們需要使用resize API將背景圖尺寸修改與視頻尺寸大小。這樣才能進(jìn)行后續(xù)的像素賦值操作。
Mat bg = imread("background.jpg"); //背景圖 VideoCapture capture; //讀取待處理的綠幕視頻 capture.open("5.flv"); if (!capture.isOpened()) { cout << "Can not open video!" << endl; system("pause"); return -1; } int width = capture.get(CAP_PROP_FRAME_WIDTH); int height = capture.get(CAP_PROP_FRAME_HEIGHT); resize(bg, bg, Size(width, height), 1, 1, INTER_CUBIC); //將背景圖resize成視頻尺寸大小
二、HSV色彩空間轉(zhuǎn)換
1. cvtColor色彩空間轉(zhuǎn)換
cvtColor(frame, HSV, COLOR_BGR2HSV); //將原圖轉(zhuǎn)換成HSV色彩空間
2. inRange摳圖
經(jīng)百度查表,我們可以獲取綠色HSV顏色分量范圍
//綠色HSV顏色分量范圍 int hmin = 35, smin = 43, vmin = 46; int hmax = 77, smax = 255, vmax = 255;
由于我們已經(jīng)將原圖轉(zhuǎn)換為HSV色彩空間,故可以使用inRange API將前景從綠幕中摳出來(lái)。inRange將兩閾值內(nèi)的像素置為255(即綠色被置為白色),閾值外的像素置為0(其他顏色被置為黑色)。故由此我們可以將前景摳出來(lái)。
//經(jīng)過inRange API處理,輸出一張二值圖像,即將前景從綠幕中扣出來(lái)啦 inRange(HSV, Scalar(hmin, smin, vmin), Scalar(hmax, smax, vmax), mask);
mask圖像,即從綠幕中摳出來(lái)的前景圖。
三、背景替換
我們通過修改圖像像素值達(dá)到替換背景目的。通過遍歷視頻圖像像素值,當(dāng)mask像素值為0時(shí),表示此時(shí)圖像像素為前景,將綠幕視頻當(dāng)前像素點(diǎn)賦給目標(biāo)圖像dst;當(dāng)mask像素值為255時(shí),表示此時(shí)圖像像素為背景,將背景圖當(dāng)前像素點(diǎn)賦給目標(biāo)圖像dst。
Mat Replace_Background(Mat frame, Mat mask, Mat bg) { Mat dst = Mat::zeros(frame.size(), frame.type()); for (int i = 0; i < frame.rows; i++) { for (int j = 0; j < frame.cols; j++) { int p = mask.at<uchar>(i, j); //傳入的mask是張二值圖,p為當(dāng)前mask像素值 if (p == 0) { //代表mask此時(shí)為前景,將綠幕視頻中的前景像素賦給dst dst.at<Vec3b>(i, j) = frame.at<Vec3b>(i, j); } else if (p == 255) { //代表mask此時(shí)為背景,將背景圖像素賦給dst dst.at<Vec3b>(i, j) = bg.at<Vec3b>(i,j); } } } return dst; }
最終效果如圖所示。
四、源碼
#include<iostream> #include<opencv2/opencv.hpp> using namespace std; using namespace cv; Mat Replace_Background(Mat frame, Mat mask, Mat bg) { Mat dst = Mat::zeros(frame.size(), frame.type()); for (int i = 0; i < frame.rows; i++) { for (int j = 0; j < frame.cols; j++) { int p = mask.at<uchar>(i, j); //傳入的mask是張二值圖,p為當(dāng)前mask像素值 if (p == 0) { //代表mask此時(shí)為前景,將綠幕視頻中的前景像素賦給dst dst.at<Vec3b>(i, j) = frame.at<Vec3b>(i, j); } else if (p == 255) { //代表mask此時(shí)為背景,將背景圖像素賦給dst dst.at<Vec3b>(i, j) = bg.at<Vec3b>(i,j); } } } return dst; } int main() { Mat bg = imread("background.jpg"); //背景圖 VideoCapture capture; //讀取待處理的綠幕視頻 capture.open("5.flv"); if (!capture.isOpened()) { cout << "Can not open video!" << endl; system("pause"); return -1; } int width = capture.get(CAP_PROP_FRAME_WIDTH); int height = capture.get(CAP_PROP_FRAME_HEIGHT); resize(bg, bg, Size(width, height), 1, 1, INTER_CUBIC); //將背景圖resize成視頻尺寸大小 Mat frame, HSV, mask, dst; //綠色HSV顏色分量范圍 int hmin = 35, smin = 43, vmin = 46; int hmax = 77, smax = 255, vmax = 255; while (capture.read(frame)) { cvtColor(frame, HSV, COLOR_BGR2HSV); //將原圖轉(zhuǎn)換成HSV色彩空間 //經(jīng)過inRange API處理,輸出一張二值圖像,即將前景從綠幕中扣出來(lái)啦 inRange(HSV, Scalar(hmin, smin, vmin), Scalar(hmax, smax, vmax), mask); dst = Replace_Background(frame, mask, bg); imshow("demo", frame); //imwrite("frame.jpg", frame); imshow("mask", mask); //imwrite("mask.jpg", mask); imshow("dst", dst); //imwrite("dst.jpg", dst); char key = waitKey(10); if (key == 27) { break; } } destroyAllWindows(); capture.release(); system("pause"); return 0; }
總結(jié)
本文使用OpenCV C++進(jìn)行綠幕視頻背景替換,關(guān)鍵步驟有以下幾點(diǎn)。
1、將原圖轉(zhuǎn)換成HSV色彩空間。
2、使用inRange API將前景從綠幕中摳出來(lái),得到一張二值圖。
3、通過像素賦值操作達(dá)到背景替換效果。
到此這篇關(guān)于利用OpenCV實(shí)現(xiàn)綠幕視頻背景替換的文章就介紹到這了,更多相關(guān)OpenCV綠幕視頻背景替換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++分析構(gòu)造函數(shù)與析造函數(shù)的特點(diǎn)梳理
本文對(duì)類的構(gòu)造函數(shù)和析構(gòu)函數(shù)進(jìn)行總結(jié),主要包括了構(gòu)造函數(shù)的初始化、重載、使用參數(shù)和默認(rèn)參數(shù),拷貝構(gòu)造函數(shù)和析構(gòu)函數(shù),希望能幫助讀者在程序開發(fā)中更好的理解類,屬于C/C++基礎(chǔ)2022-05-05C++實(shí)現(xiàn)通訊錄系統(tǒng)項(xiàng)目實(shí)戰(zhàn)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)通訊錄系統(tǒng)項(xiàng)目實(shí)戰(zhàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06C++設(shè)計(jì)模式中的工廠模式詳細(xì)介紹
工廠模式,是一種實(shí)例化對(duì)象的方式,只要輸入需要實(shí)例化對(duì)象的名字,就可以通過工廠對(duì)象的相應(yīng)工廠函數(shù)來(lái)制造你需要的對(duì)象2022-09-09C++通過共享內(nèi)存ShellCode實(shí)現(xiàn)跨進(jìn)程傳輸
在計(jì)算機(jī)安全領(lǐng)域,ShellCode是一段用于利用系統(tǒng)漏洞或執(zhí)行特定任務(wù)的機(jī)器碼,本文主要為大家介紹了C++如何通過共享內(nèi)存ShellCode實(shí)現(xiàn)跨進(jìn)程傳輸,需要的可以參考下2023-12-12C++回調(diào)函數(shù)實(shí)現(xiàn)計(jì)算器和qsort
這篇文章主要介紹了C++回調(diào)函數(shù)實(shí)現(xiàn)計(jì)算器和qsort,回調(diào)函數(shù)就是一個(gè)通過函數(shù)指針調(diào)用的函數(shù)。如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個(gè)函數(shù),當(dāng)這個(gè)指針被用來(lái)調(diào)用其所指向的函數(shù)時(shí),我們就說(shuō)這是回調(diào)函數(shù)2022-08-08C語(yǔ)言實(shí)現(xiàn)opencv提取直線、輪廓及ROI實(shí)例詳解
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)opencv提取直線、輪廓及ROI實(shí)例詳解,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01