• C# OpenCVSharp图像入门_给绿幕图片视频加背景


      OpenCV的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉库。OpenCV是由英特尔公司发起并参与开发,以BSD许可证授权发行,可以在商业和研究领域中免费使用。OpenCV可用于开发实时的图像处理计算机视觉以及模式识别程序。该程序库也可以使用英特尔公司的IPP进行加速处理。

      OpenCVSharp是一个.Net平台使用的OpenCV封装库。现在网上关于openCV的教程基本都是c++和python,如果是C#方向,可以跟着这两个语言的步骤自己写demo。

      开始我们今天的课程。

    一、分析

      这个功能只要是给绿幕人物加上背景,比如:在直播的时候,因为私密或者其他原因,不想透露出背景

      设想只需要购买一块绿幕,然后上网挑选一张自己喜欢的背景照片,就可以拥有一个好看的背景。

      如何替换视频背景呢?我们一步一步入门!!

      1)绿幕相片扣出人物

      2)人物放进背景图片

      3)操作视频帧图片,实现替换绿幕。

      需要安装的nuget包,注意查看依赖项选版本

    OpenCvSharp4
    OpenCvSharp4.runtime.win

    二、绿幕相片扣出人物

      只展示核心代码

      1)识别绿幕函数(一般操作图片是使用指针的,为了更好理解,我们这里先At执行,后面会讲使用指针改进)

    复制代码
            //删除绿幕
            private unsafe void RemoveImageScreen(Mat src, Funcbool> func)
            {
                for (int i = 0; i < src.Rows; i++)
                {
                    for (int j = 0; j < src.Cols; j++)
                    {
                        if (func(src.At(i, j)))
                        {
                            src.At(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,当G最大时且大于30时,可以根据实际调节这个阈值
                                return true;
                            return false;
                        });
                    pictBox_result.Image = BitmapConverter.ToBitmap(mat_bg);
            }
    复制代码

      效果展示:(我是跟着杨神的思路写的这个程序,素材就直接用杨神了,这篇是入门级别,可以看完我这篇再去观摩杨神的)

      杨中科(就是下图这个帅哥):https://www.bilibili.com/read/cv8850462?spm_id_from=333.999.0.0

      

     三、人物放进背景图片

      合并图片函数

    复制代码
            private unsafe void MergeImageAt(Mat bg, Mat src, Funcbool> func)
            {
                Cv2.Resize(bg, bg, src.Size());//以背景人物大小为准
                for (int i = 0; i < bg.Rows; i++)
                {
                    for (int j = 0; j < bg.Cols; j++)
                    {
                        if (func(src.At(i, j)))
                        {
                            bg.At(i, j) = src.At(i, j);
                        }
                    }
                }
            }
    复制代码

      续上上一步,加上合并图片的步骤

    复制代码
                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);
                }
    复制代码

      效果如图:

      

     四、操作视频帧图片,实现替换绿幕

      和图片的区别,就是需要先逐帧获取 视频/摄像机 的图片,然后按上述操作进行

      直接附上完整Demo(已经将两个函数改为指针操作,大家可以先试试原来的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))
                        {
                            //如果是视频文件,从头部开始播放
                            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, Funcbool> 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, Funcbool> 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;
                }
            }
        }
    }
    复制代码

      素材:

          

      效果展示:(这是视频的一张截图)

      

      完成!!!

      图片去绿幕的效果还是很粗糙的,后续会持续更新改进方法,希望大家点赞+关注

      并欢迎大家留言...

      

     

     

     

     

  • 相关阅读:
    pod原理
    python 基于PHP+MySQL的驾校信息管理系统
    02.bpmn-js 样例项目解析----商业价值
    EXSI-NFS实验
    Vue-组件及组件间的通信方式
    编写一个简单的linux kernel rootkit
    Docker中安装mysqld-exporter
    【字符串中处理类String的使用】
    iOS——KVO底层学习
    基于python的学生成绩管理系统毕业设计源码071143
  • 原文地址:https://www.cnblogs.com/wskxy/p/17592827.html