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, 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,当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, Func<Vec3b, bool> 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<Vec3b>(i, j)))
{
bg.At<Vec3b>(i, j) = src.At<Vec3b>(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, 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;
}
}
}
}

  素材:

      

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

  

  完成!!!

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

  并欢迎大家留言...

  

C# OpenCVSharp图像入门_给绿幕图片视频加背景的更多相关文章

  1. 在Android用vulkan完成蓝绿幕扣像

    效果图(1080P处理) 因为摄像头开启自动曝光,画面变动时,亮度变化导致扣像在转动时如上. 源码地址vulkan_extratest 这个demo主要测试二点,一是测试ndk camera集成效果, ...

  2. AI目标分割能力,无需绿幕即可实现快速视频抠图

    绿幕抠图是影视制作过程中常见的技术手段,常用于视频中抠除并替换背景,通过后期加工实现视频剪辑制作的更多可能性.然而,绿幕抠图技术制作成本费时费力,无法应用于日常生活. 华为视频编辑服务近期上线目标分割 ...

  3. 09_android入门_采用android-async-http开源项目的GET方式或POST方式实现登陆案例

    根据08_android入门_android-async-http开源项目介绍及使用方法的介绍,我们通过最常见的登陆案例进行介绍android-async-http开源项目中有关类的使用.希望对你学习 ...

  4. Spring_MVC_教程_快速入门_深入分析

    Spring MVC 教程,快速入门,深入分析 博客分类: SPRING Spring MVC 教程快速入门  资源下载: Spring_MVC_教程_快速入门_深入分析V1.1.pdf Spring ...

  5. 09_android入门_採用android-async-http开源项目的GET方式或POST方式实现登陆案例

    依据08_android入门_android-async-http开源项目介绍及用法的介绍,我们通过最常见的登陆案例进行介绍android-async-http开源项目中有关类的使用.希望对你学习an ...

  6. 『TensorFlow』第九弹_图像预处理_不爱红妆爱武装

    部分代码单独测试: 这里实践了图像大小调整的代码,值得注意的是格式问题: 输入输出图像时一定要使用uint8编码, 但是数据处理过程中TF会自动把编码方式调整为float32,所以输入时没问题,输出时 ...

  7. 07_android入门_採用HttpClient的POST方式、GET方式分别实现登陆案例

    1.简单介绍 HttpClient 是 Apache Jakarta Common 下的子项目,能够用来提供高效的.最新的.功能丰富的支持 HTTP 协议的客户端编程工具包,而且它支持 HTTP 协议 ...

  8. OpenCvSharp 图像旋转

    /// <summary> /// 图像旋转 /// </summary> private Mat MatRotate(Mat src, float angle) { Mat ...

  9. 【笔记目录2】【jessetalk 】ASP.NET Core快速入门_学习笔记汇总

    当前标签: ASP.NET Core快速入门 共2页: 上一页 1 2  任务27:Middleware管道介绍 GASA 2019-02-12 20:07 阅读:15 评论:0 任务26:dotne ...

  10. Camtasia绿幕素材的视频合成

    随着科技和互联网的快速发展,让越来越多的人喜欢上了视频的各项制作,那么怎么让两个视频进行合成并一起播放呢?操作很简单,下面来讲解具体的操作步骤.小编选用的是Camtasia2019版本的视频编辑软件进 ...

随机推荐

  1. 2021-09-07:单词接龙 II。按字典 wordList 完成从单词 beginWord 到单词 endWord 转化,一个表示此过程的 转换序列 是形式上像 beginWord -> s1 -

    2021-09-07:单词接龙 II.按字典 wordList 完成从单词 beginWord 到单词 endWord 转化,一个表示此过程的 转换序列 是形式上像 beginWord -> s ...

  2. Vue3.3 的新功能的一些体验

    Vue3 在大版本 3.3 里面推出来了一些新功能(主要是语法糖),网上有各种文章,但是看起来似乎是一样的. 我觉得吧,有新特性了,不能光看,还要动手尝试一下. DefineOptions 宏定义 先 ...

  3. 由C# yield return引发的思考

    前言 当我们编写 C# 代码时,经常需要处理大量的数据集合.在传统的方式中,我们往往需要先将整个数据集合加载到内存中,然后再进行操作.但是如果数据集合非常大,这种方式就会导致内存占用过高,甚至可能导致 ...

  4. Java中如何中断线程

    在Java中,可以使用以下方法中断线程: 1. 使用`interrupt()`方法:每个线程对象都有一个`interrupt()`方法,用于中断该线程.当调用线程的`interrupt()`方法时,它 ...

  5. Kubernetes(k8s)一次性任务:Job

    目录 一.系统环境 二.前言 三.Kubernetes Job简介 四.创建一次性任务job 4.1 创建一个简单任务的job 4.2 创建需要执行多次的job任务 五.测试job失败重试次数 六.j ...

  6. 大型 3D 互动开发和优化实践

    开发背景 得益于"元宇宙"概念在前段时间的爆火,各家公司都推出了使用 3D 场景的活动或频道. 3D 场景相比传统的 2D 页面优点是多一个维度,同屏展示的内容可以更多,能完整的展 ...

  7. CKS 考试题整理 (07)-RBAC - RoleBinding

    Context 绑定到 Pod 的 ServiceAccount 的 Role 授予过度宽松的权限,完成以下项目以减少权限集. Task 一个名为 web-pod 的现有 Pod 已在 namespa ...

  8. 3. Servlet原理

    Servlet 是 Java Web 应用程序中的重要组件之一,它是一个 Java 类,用于处理客户端 HTTP 请求和生成 HTTP 响应.Servlet 的原理如下: 服务器启动时,Servlet ...

  9. 7. RESTful

    1. RESTful简介 ‍ REST:Representational State Transfer,表现层资源状态转移. ①资源 ‍ 资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源 ...

  10. Docker安装MariaDB--九五小庞

    1 docker search mariadb 搜索mariadb镜像(非必须) 2 docker pull mariadb 下载docker镜像(下载的是latest版本)想要下载指定版本执行的命令 ...