OpenCV的全稱是Open Source Computer Vision Library,是一個(gè)跨平臺(tái)的計(jì)算機(jī)視覺(jué)庫(kù)。OpenCV是由英特爾公司發(fā)起并參與開(kāi)發(fā),以BSD許可證授權(quán)發(fā)行,可以在商業(yè)和研究領(lǐng)域中免費(fèi)使用。OpenCV可用于開(kāi)發(fā)實(shí)時(shí)的圖像處理計(jì)算機(jī)視覺(jué)以及模式識(shí)別程序。該程序庫(kù)也可以使用英特爾公司的IPP進(jìn)行加速處理。
OpenCVSharp是一個(gè).Net平臺(tái)使用的OpenCV封裝庫(kù)?,F(xiàn)在網(wǎng)上關(guān)于openCV的教程基本都是c++和python,如果是C#方向,可以跟著這兩個(gè)語(yǔ)言的步驟自己寫(xiě)demo。
開(kāi)始我們今天的課程。
一、分析
這個(gè)功能只要是給綠幕人物加上背景,比如:在直播的時(shí)候,因?yàn)樗矫芑蛘咂渌颍幌胪嘎冻霰尘?/span>
設(shè)想只需要購(gòu)買(mǎi)一塊綠幕,然后上網(wǎng)挑選一張自己喜歡的背景照片,就可以擁有一個(gè)好看的背景。
如何替換視頻背景呢?我們一步一步入門(mén)?。?/span>
1)綠幕相片扣出人物
2)人物放進(jìn)背景圖片
3)操作視頻幀圖片,實(shí)現(xiàn)替換綠幕。
需要安裝的nuget包,注意查看依賴項(xiàng)選版本
OpenCvSharp4
OpenCvSharp4.runtime.win
二、綠幕相片扣出人物
只展示核心代碼
1)識(shí)別綠幕函數(shù)(一般操作圖片是使用指針的,為了更好理解,我們這里先At執(zhí)行,后面會(huì)講使用指針改進(jìn))
//刪除綠幕 private unsafe void RemoveImageScreen(Mat src, Func<Vec3b, bool> func) { for (int i = 0; i < src.Rows; i++) { for (int j = 0; j < src.Cols; j++) { if (func(src.At<Vec3b>(i, j))) { src.At<Vec3b>(i, j) = new Vec3b(0, 0, 0); } } } }
2)選擇圖片并清除綠幕
using (ResourcesTracker t = new ResourcesTracker()) { Bitmap bitmap = new Bitmap(pictBox_origin.Image); var mat = BitmapConverter.ToMat(bitmap); RemoveImageScreen(mat, p => { int max = Math.Max(p.Item0, Math.Max(p.Item1, p.Item2)); if (max == p.Item1 && p.Item1 > 30) //BGR,當(dāng)G最大時(shí)且大于30時(shí),可以根據(jù)實(shí)際調(diào)節(jié)這個(gè)閾值 return true; return false; }); pictBox_result.Image = BitmapConverter.ToBitmap(mat_bg);
}
效果展示:(我是跟著楊神的思路寫(xiě)的這個(gè)程序,素材就直接用楊神了,這篇是入門(mén)級(jí)別,可以看完我這篇再去觀摩楊神的)
楊中科(就是下圖這個(gè)帥哥):https://www.bilibili.com/read/cv8850462?spm_id_from=333.999.0.0
?三、人物放進(jìn)背景圖片
合并圖片函數(shù)
private unsafe void MergeImageAt(Mat bg, Mat src, Func<Vec3b, bool> func) { Cv2.Resize(bg, bg, src.Size());//以背景人物大小為準(zhǔn) for (int i = 0; i < bg.Rows; i++) { for (int j = 0; j < bg.Cols; j++) { if (func(src.At<Vec3b>(i, j))) { bg.At<Vec3b>(i, j) = src.At<Vec3b>(i, j); } } } }
續(xù)上上一步,加上合并圖片的步驟
using (ResourcesTracker t = new ResourcesTracker()) { Bitmap bitmap = new Bitmap(pictBox_origin.Image); var mat = BitmapConverter.ToMat(bitmap); var mat_bg = t.T(Cv2.ImRead("images/bg2.jpg")); RemoveImageScreen(mat, p => { int max = Math.Max(p.Item0, Math.Max(p.Item1, p.Item2)); if (max == p.Item1 && p.Item1 > 30) return true; return false; }); MergeImageAt( mat_bg, mat, p => { if (p == new Vec3b(0, 0, 0)) { return false; } return true; } ); pictBox_result.Image = BitmapConverter.ToBitmap(mat_bg); }
效果如圖:
?四、操作視頻幀圖片,實(shí)現(xiàn)替換綠幕
和圖片的區(qū)別,就是需要先逐幀獲取 視頻/攝像機(jī) 的圖片,然后按上述操作進(jìn)行
直接附上完整Demo(已經(jīng)將兩個(gè)函數(shù)改為指針操作,大家可以先試試原來(lái)的At操作,可以明顯看到視頻是慢速播放)
using OpenCvSharp; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MyOpenCV { public static class RemoveGreenScreen { public static unsafe void Start() { //VideoCapture videoCapture = new VideoCapture(1, VideoCaptureAPIs.DSHOW);//攝像頭 VideoCapture videoCapture = new VideoCapture(@"images/綠幕視頻.mp4"); using (videoCapture) using (Mat frameMat = new Mat()) using (Mat mat_bg = Cv2.ImRead("images/bg.png")) { if (videoCapture.CaptureType == CaptureType.Camera)//如果是攝像頭 { videoCapture.FrameWidth = 800; videoCapture.FrameHeight = 600; videoCapture.FourCC = "MJPG"; } while (true) { if (!videoCapture.Read(frameMat)) { //如果是視頻文件,從頭部開(kāi)始播放 if (videoCapture.CaptureType == CaptureType.File) { videoCapture.PosFrames = 0; } continue; } RemoveImageScreen(frameMat, p => { int max = Math.Max(p.Item0, Math.Max(p.Item1, p.Item2)); if (max == p.Item1 && p.Item1 > 30) return true; return false; }); var bg_clone = mat_bg.Clone(); MergeImage(bg_clone, frameMat, p => { if (p == new Vec3b(0, 0, 0)) { return false; } return true; }); Cv2.ImShow("press any key to quit", bg_clone); if (Cv2.WaitKey(1) > 0) { break; } } } Cv2.DestroyAllWindows(); } private static unsafe void RemoveImageScreen(Mat src, Func<Vec3b, bool> func) { Vec3b* start = (Vec3b*)src.DataStart; Vec3b* end = (Vec3b*)src.DataEnd; for (Vec3b* p = start; p <= end; p++) { if (func(*p)) { *p = new Vec3b(0, 0, 0); } } } private static unsafe void MergeImage(Mat bg, Mat src, Func<Vec3b, bool> func) { Cv2.Resize(bg, bg, src.Size()); Vec3b* bg_pointer = (Vec3b*)bg.DataStart; Vec3b* start = (Vec3b*)src.DataStart; Vec3b* end = (Vec3b*)src.DataEnd; for (Vec3b* p = start; p <= end; p++, bg_pointer++) { *bg_pointer = func(*p) ? *p : *bg_pointer; } } } }
素材:
? ??
效果展示:(這是視頻的一張截圖)
完成?。?!
圖片去綠幕的效果還是很粗糙的,后續(xù)會(huì)持續(xù)更新改進(jìn)方法,希望大家點(diǎn)贊+關(guān)注
并歡迎大家留言...
?文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-637917.html
?
?
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-637917.html
到了這里,關(guān)于C# OpenCVSharp圖像入門(mén)_給綠幕圖片視頻加背景的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!