利用OpenCV實現(xiàn)綠幕視頻背景替換
前言
本文將使用OpenCV C++ 進行綠幕視頻背景替換。
一、圖像預(yù)處理
背景
綠幕視頻
首先,我們需要使用resize API將背景圖尺寸修改與視頻尺寸大小。這樣才能進行后續(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將前景從綠幕中摳出來。inRange將兩閾值內(nèi)的像素置為255(即綠色被置為白色),閾值外的像素置為0(其他顏色被置為黑色)。故由此我們可以將前景摳出來。
//經(jīng)過inRange API處理,輸出一張二值圖像,即將前景從綠幕中扣出來啦 inRange(HSV, Scalar(hmin, smin, vmin), Scalar(hmax, smax, vmax), mask);
mask圖像,即從綠幕中摳出來的前景圖。
三、背景替換
我們通過修改圖像像素值達(dá)到替換背景目的。通過遍歷視頻圖像像素值,當(dāng)mask像素值為0時,表示此時圖像像素為前景,將綠幕視頻當(dāng)前像素點賦給目標(biāo)圖像dst;當(dāng)mask像素值為255時,表示此時圖像像素為背景,將背景圖當(dāng)前像素點賦給目標(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此時為前景,將綠幕視頻中的前景像素賦給dst dst.at<Vec3b>(i, j) = frame.at<Vec3b>(i, j); } else if (p == 255) { //代表mask此時為背景,將背景圖像素賦給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此時為前景,將綠幕視頻中的前景像素賦給dst dst.at<Vec3b>(i, j) = frame.at<Vec3b>(i, j); } else if (p == 255) { //代表mask此時為背景,將背景圖像素賦給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處理,輸出一張二值圖像,即將前景從綠幕中扣出來啦 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++進行綠幕視頻背景替換,關(guān)鍵步驟有以下幾點。
1、將原圖轉(zhuǎn)換成HSV色彩空間。
2、使用inRange API將前景從綠幕中摳出來,得到一張二值圖。
3、通過像素賦值操作達(dá)到背景替換效果。
到此這篇關(guān)于利用OpenCV實現(xiàn)綠幕視頻背景替換的文章就介紹到這了,更多相關(guān)OpenCV綠幕視頻背景替換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++分析構(gòu)造函數(shù)與析造函數(shù)的特點梳理
本文對類的構(gòu)造函數(shù)和析構(gòu)函數(shù)進行總結(jié),主要包括了構(gòu)造函數(shù)的初始化、重載、使用參數(shù)和默認(rèn)參數(shù),拷貝構(gòu)造函數(shù)和析構(gòu)函數(shù),希望能幫助讀者在程序開發(fā)中更好的理解類,屬于C/C++基礎(chǔ)2022-05-05C++實現(xiàn)通訊錄系統(tǒng)項目實戰(zhàn)
這篇文章主要為大家詳細(xì)介紹了C++實現(xiàn)通訊錄系統(tǒng)項目實戰(zhàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-06-06C++通過共享內(nèi)存ShellCode實現(xiàn)跨進程傳輸
在計算機安全領(lǐng)域,ShellCode是一段用于利用系統(tǒng)漏洞或執(zhí)行特定任務(wù)的機器碼,本文主要為大家介紹了C++如何通過共享內(nèi)存ShellCode實現(xiàn)跨進程傳輸,需要的可以參考下2023-12-12C++回調(diào)函數(shù)實現(xiàn)計算器和qsort
這篇文章主要介紹了C++回調(diào)函數(shù)實現(xiàn)計算器和qsort,回調(diào)函數(shù)就是一個通過函數(shù)指針調(diào)用的函數(shù)。如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個函數(shù),當(dāng)這個指針被用來調(diào)用其所指向的函數(shù)時,我們就說這是回調(diào)函數(shù)2022-08-08C語言實現(xiàn)opencv提取直線、輪廓及ROI實例詳解
這篇文章主要介紹了C語言實現(xiàn)opencv提取直線、輪廓及ROI實例詳解,具有一定借鑒價值,需要的朋友可以參考下2018-01-01