首页 > 编程语言 >C#加神经网络实现视频换背景

C#加神经网络实现视频换背景

时间:2024-07-21 23:55:50浏览次数:13  
标签:视频 C# bitmapData 像素 int 神经网络 Alpha byte

机器配置:
1.cpu:i3-2375M
2.操作系统:win 7 64位旗舰版 SP1

程序运行环境:
Microsoft .NET Framework 4.8(wpf运行时)
Microsoft Visual C++2015-2022 Redistributable(x86)-14.40.33810(onnx运行时)

依赖:
Microsoft.ML.OnnxRuntime 1.11(备注1)

效果:实现类似视频会议换背景功能。
原理:若给定一张宽为w像素高为h像素的含人像图片pic,神经网络模型将会估计图片的每一个像素pic[i,j]为背景像素的概率,
若大于0.5说明这个像素过半概率是背景像素,小于0.5说明不到一半的概率属于背景,也就是这个像素属于人像像素;
而图片总共含有w×h个像素,因此最终判断的结果也将会是一个w×h大小的二维小数数组Alpha,其中的元素Alpha[i,j]存放着像素pic[i,j]为背景像素的概率。

完整项目源码https://gitee.com/ReadmeHo/back-ground-change.git

程序主要结构:

1.ModelWorker类,封装了Onnx神经网络模型的初始化与推理方法。
2.ModelHelper类,把图像转为张量,根据神经网络的推理结果抠出人像前景并和自定义背景合成新图像返回。
3.Handle类,组合ModelWorker和ModelHelper进行工作。

主要具体实现:
神经网络模型(备注2)接受一个1×3×h×w的四维张量作为输入,
所以主要思路是把BitmapData(备注3)转换成元素类型为float的1×3×h×w的四维张量,张量中每一个数的范围为-1到1。
神经网络每次判断一张图片,因此第一维是1,图像的每个像素具有rgb三个通道,因此第二维是3,
而第三维和第四维分别为图像的高h和宽w。
因为像素的rgb各使用一个字节存储,所以每个通道会有0到255一共256个可能的整数取值,而神经网络允许的每个张量元素输入范围是-1到1,因此还需要归一化操作把整数的通道值映射成-1到1之间的小数

public static Tensor<float> BitmapDataToTensor(BitmapData bitmapData)
{
    int row = bitmapData.Height;
    int col = bitmapData.Width;
    Tensor<float> re = new DenseTensor<float>(new[] { 1, 3, row, col });
    unsafe
    {
        byte* ptr = (byte*)bitmapData.Scan0;
        Parallel.For(0, row, i =>
        {
            int line = bitmapData.Stride * i;
            Parallel.For(0, col, j =>
            {
                int position = line + j + (j << 1);
                byte* ptr2 = ptr + position;
                re[0, 0, i, j] = normalizationCache[ptr2[2]];
                re[0, 1, i, j] = normalizationCache[ptr2[1]];
                re[0, 2, i, j] = normalizationCache[ptr2[0]];
            });
        });
    }
    return re;
}

输入是bitmapData(摄像头采集到的实时带人像图像),bgData(自定义背景图片)
抠图并把前景和背景合成新图像输出,神经网络模型会输出一个1×1×宽×高的四维float张量Alpha,因为前两维的长度都是1,所以可以看做是二维数组。
根据上文原理中的解释可知,程序将会根据Alpha数组的每个元素的值来区分bitmapData的对应相同坐标像素是否属于人像,若属于则直接把这个像素覆盖bgData对应坐标的像素,也就是把同时实现抠图和合成。

public static void Composition(BitmapData bitmapData, BitmapData bgData, Tensor<float> Alpha)
{
    unsafe
    {
        byte* iptr2 = (byte*)bitmapData.Scan0;
        byte* iptr3 = (byte*)bgData.Scan0;
        Parallel.For(0, bitmapData.Height, i =>
        {
            int line = bitmapData.Stride * i;
            Parallel.For(0, bitmapData.Width, j =>
            {
                if (Alpha[0, 0, i, j] < 0.5)
                {
                    int position = line + j + (j << 1);
                    byte* ptr2 = iptr2 + position;
                    byte* ptr3 = iptr3 + position;
                    ptr3[0] = ptr2[0];
                    ptr3[1] = ptr2[1];
                    ptr3[2] = ptr2[2];
                }
            });
        });
    }
}

计算加速
为了尽可能减少不必要的计算,以及最大程度挖掘硬件性能,需要采用多个办法实现加速
1.最直接的,尽量使用小的图像,以归一化操作为例,1280×720的图片所需计算量是640×360的图片的四倍。
2.使用硬编码数组缓存归一化数值,归一化时,一个w×h的图片需要把所有像素的所有通道的值由0到255映射到-1到1的范围内,那么就需要w×h×3次浮点运算,因为rgb的值只有256种可能取值,所以用一个长度为256的float数组normalizationCache存放事先计算好的数值,以rgb的值作为数组下标索引,这样图像归一化的时候就可以直接查数组而不用进行浮点运算。
3.使用移位代替乘法,因为移位操作和加法操作比乘法操作快很多,比如j * 3这个计算,改为j + (j << 1),在遍历一个图片所有像素
的时候,需要进行w×h次乘法操作,通过把乘法改为一个移位加一个加法可以节省出几十毫秒的时间。
4.使用指针直接访问内存中的图片像素,而不是通过bitmap的访问像素方法。
6.使用Parallel.For代替for循环。
5.启用onnx运行时的多线程和切换到并行模式

SessionOptions o = new SessionOptions();
o.InterOpNumThreads = 4;//不同操作之间线程数
o.IntraOpNumThreads = 4;//每个操作线程数
o.ExecutionMode = ExecutionMode.ORT_PARALLEL;//并行模式

注意事项:
1.背景图像长宽要和摄像头录像长宽一样

相关链接:
1.模型下载地址:https://bj.bcebos.com/paddle2onnx/model_zoo/ppseg_lite_portrait_398x224_with_softmax.onnx
2.onnx文档:https://onnxruntime.ai/docs/

备注
1.Microsoft.ML.OnnxRuntime 1.11是经过我测试可以在win 7上运行的最高版本,有的win7 有可能会报错,如果用1.1.2版本目前在我用过的所有win7 机器都能跑。
2.此项目使用的是ppseg_lite_portrait_398x224_with_softmax.onnx这个模型,这个模型是暂时我能找到的最快的人像识别抠图模型。
3.为什么是用BitmapData而不是Bitmap请看加速计算部分

标签:视频,C#,bitmapData,像素,int,神经网络,Alpha,byte
From: https://www.cnblogs.com/ReadmeHo/p/18280705

相关文章

  • 深入浅出C语言指针(基础篇)
    目录引言一、认识指针指针是什么? 二、指针变量和地址1.取地址操作符2.指针变量3.解引用操作符 4.指针变量的大小 三、指针和指针类型1.指针的类型2.指针+-整数3.指针的解引用四、const修饰指针变量 1.const修饰指向的数据2.const修饰指针本身3.const同......
  • 一文掌握 Tailwind CSS 基础
    一文掌握TailwindCSS基础工欲善其事,必先利其器先推荐一些好用的工具:TailWindCSS代码提示功能的vscode插件:TailwindCSSIntelliSense再推荐一个TailwindCSS速查网站:https://tailwind.muzhifan.top/本文假定读者已经有一定的CSS基础1宽高1.使用预定义类名如......
  • P4824 [USACO15FEB] Censoring S
    原题链接题解手写栈存放已经匹配过的位置和每个位置匹配的进度,每次匹配成功就回溯,相当于删除子串code#include<bits/stdc++.h>#definelllonglongusingnamespacestd;intcon[1000006],pre[1000006]={0},st[1000006]={0};voidsolve(){strings1,s2;cin>>s......
  • CF1990E Catch the Mole
    题意给你一颗树,大小为\(n\)。初始有一颗黑点在树上某个节点,你每次可以查询\(x\)表示黑点是否在\(x\)的子树内,且若答案为否则黑点会移动到父亲节点上。你需要在160次查询内找到黑点当前在哪个节点(不要求求出初始位置)。\(n\le5000\),EasyVer.查询次数300。分析由于每......
  • pyecharts 指定“chart_id” 绑定事件
    作者:JasonBourn_8228链接:https://www.jianshu.com/p/10167a735d3a来源:简书 问题,点击地图的板块时,需求弹出此板块的信息解决办法:查阅pyecharts官网手册:https://pyecharts.org/#/zh-cn/global_options?id=initopts%ef%bc%9a%e5%88%9d%e5%a7%8b%e5%8c%96%e9%85%8d%e7%bd%ae%e9......
  • 基于深度学习网络的USB摄像头实时视频采集与手势检测识别matlab仿真
    1.算法运行效果图预览(完整程序运行后无水印) 训练过程如下:   将摄像头对准手势,然后进行识别,识别结果如下:   本课题中,使用的USB摄像头为:   2.算法运行软件版本MATLAB2022a 3.部分核心程序程序中包括MATLAB读取摄像头的配置方法,摄像头配置工具......
  • rabbitmq发送消息localdatetime报错:Java 8 date/time type `java.time.LocalDateTime`
    两种解决方案:通过全局配置LocalDateTime的序列化/***json序列化增强解决Jackson序列化不了Java8日期*/@BeanpublicMessageConvertermessageConverter(){ObjectMapperom=newObjectMapper();om.setVisibility(PropertyAccessor.ALL,JsonAut......
  • 【普及组】广度优先搜索BFS——到达型搜索问题_C++算法竞赛
    文章目录1.走迷宫例1.洛谷B3625迷宫寻路例2.洛谷P1825[USACO11OPEN]CornMazeS例3.[ABC348D]MedicinesonGrid(AtCoder)2.生活背景下的常见问题例.P3958[NOIP2017提高组]奶酪3.输出路径例.洛谷P6207[USACO06OCT]CowsonSkatesGEnd提示:本文建议有一定......
  • [Java源码]Object
    ClassObjectjava.lang.ObjectpublicclassObjectClassObjectistherootoftheclasshierarchy.EveryclasshasObjectasasuperclass.Allobjects,includingarrays,implementthemethodsofthisclass.Since:JDK1.0SeeAlso:ClassConstructorSumm......
  • (82)DC命令--->(01)DC综合命令
    1目录(a)IC简介(b)数字IC设计流程(c)Verilog简介(d)DC综合命令(e)结束1IC简介(a)在IC设计中,设计师使用电路设计工具(如EDA软件)来设计和模拟各种电路,例如逻辑电路、模拟电路、数字信号处理电路等。然后,根据设计电路的规格要求,进行布局设计和布线,确定各个电路元件的位置和连线方式。......