C# PortraitModeFilter (人物图片)背景模糊

news2024/11/26 22:22:30

效果

项目

代码

using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Windows.Forms;
using UMapx.Core;
using UMapx.Imaging;

namespace PortraitModeFilter_模糊背景
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();
        }

        string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
        string image_path = "";
        string startupPath;
        DateTime dt1 = DateTime.Now;
        DateTime dt2 = DateTime.Now;
        string model_path;
        Mat image;
        Bitmap src;
        Bitmap mask;
        int modelSize = 512;

        SessionOptions options;
        InferenceSession onnx_session;
        Tensor<byte> input_tensor;
        List<NamedOnnxValue> input_ontainer;
        IDisposableReadOnlyCollection<DisposableNamedOnnxValue> result_infer;
        DisposableNamedOnnxValue[] results_onnxvalue;
        Tensor<long> result_tensors;
        long[] result_array;

        double strength = 1;// 0 到 1

        OpenFileDialog ofd;
        private void button1_Click(object sender, EventArgs e)
        {
            if (ofd.ShowDialog() != DialogResult.OK) return;
            pictureBox1.Image = null;
            image_path = ofd.FileName;
            src = new Bitmap(image_path);
            pictureBox1.Image = src;
            textBox1.Text = "";
            image = new Mat(image_path);
            pictureBox2.Image = null;
            trackBar1.Enabled = false;
        }

        private void Form2_Load(object sender, EventArgs e)
        {
            trackBar1.Enabled = false;

            startupPath = Application.StartupPath;

            ofd = new OpenFileDialog();
            ofd.Filter = fileFilter;

            model_path = startupPath + "\\deeplabv3_mnv2_pascal_train_aug.onnx";

            //创建输出会话,用于输出模型读取信息
            options = new SessionOptions();
            options.LogSeverityLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_INFO;
            // 设置为CPU上运行
            options.AppendExecutionProvider_CPU(0);

            // 创建推理模型类,读取本地模型文件
            onnx_session = new InferenceSession(model_path, options);

            // 创建输入容器
            input_ontainer = new List<NamedOnnxValue>();

            // 创建输入容器
            input_ontainer = new List<NamedOnnxValue>();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (image_path == "")
            {
                return;
            }

            textBox1.Text = "生成中……";
            pictureBox2.Image = null;

            Application.DoEvents();

            //缩放图片大小
            int oldwidth = image.Cols;
            int oldheight = image.Rows;
            int maxEdge = Math.Max(image.Rows, image.Cols);
            float ratio = 1.0f * modelSize / maxEdge;
            int newHeight = (int)(image.Rows * ratio);
            int newWidth = (int)(image.Cols * ratio);
            Mat resize_image = image.Resize(new OpenCvSharp.Size(newWidth, newHeight));

            input_tensor = new DenseTensor<byte>(new[] { 1, newHeight, newWidth, 3 });

            // 输入Tensor
            for (int y = 0; y < resize_image.Height; y++)
            {
                for (int x = 0; x < resize_image.Width; x++)
                {
                    input_tensor[0, y, x, 2] = resize_image.At<Vec3b>(y, x)[0];
                    input_tensor[0, y, x, 1] = resize_image.At<Vec3b>(y, x)[1];
                    input_tensor[0, y, x, 0] = resize_image.At<Vec3b>(y, x)[2];
                }
            }

            //将 input_tensor 放入一个输入参数的容器,并指定名称
            input_ontainer.Add(NamedOnnxValue.CreateFromTensor(onnx_session.InputNames[0].ToString(), input_tensor));

            dt1 = DateTime.Now;
            //运行 Inference 并获取结果
            result_infer = onnx_session.Run(input_ontainer);
            dt2 = DateTime.Now;

            //将输出结果转为DisposableNamedOnnxValue数组
            results_onnxvalue = result_infer.ToArray();

            //读取第一个节点输出并转为Tensor数据
            result_tensors = results_onnxvalue[0].AsTensor<Int64>();

            result_array = result_tensors.ToArray();

            //得到掩码图
            mask = SegmentationMap(result_array, newWidth, newHeight);

            mask = new Bitmap(mask, new System.Drawing.Size(oldwidth, oldheight));

            trackBar1.Enabled = true;

            //模糊背景
            pictureBox2.Image = Filter(src, mask);

            textBox1.Text = "推理耗时:" + (dt2 - dt1).TotalMilliseconds + "ms";

        }

        /// <summary>
        /// Converts an RGB tensor array to a color image.
        /// </summary>
        /// <param name="tensor">RGBA tensor array</param>
        /// <param name="width">Bitmap width</param>
        /// <param name="height">Bitmap height</param>
        public unsafe Bitmap SegmentationMap(long[] tensor, int width, int height)
        {
            Bitmap Data = new Bitmap(width, height);
            BitmapData bmData = Data.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            int stride = bmData.Stride;
            byte* p = (byte*)bmData.Scan0.ToPointer();
            int pos = 0;

            for (int j = 0; j < height; j++)
            {
                int k, jstride = j * stride;

                for (int i = 0; i < width; i++, pos++)
                {
                    k = jstride + i * 3;

                    var z = (tensor[pos] == 15) ? (byte)255 : (byte)0;

                    // rgb
                    p[k + 2] = z;
                    p[k + 1] = z;
                    p[k + 0] = z;
                }
            }

            Data.UnlockBits(bmData);

            return Data;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            if (pictureBox2.Image == null)
            {
                return;
            }
            Bitmap output = new Bitmap(pictureBox2.Image);
            var sdf = new SaveFileDialog();
            sdf.Title = "保存";
            sdf.Filter = "Images (*.jpg)|*.jpg|Images (*.png)|*.png|Images (*.bmp)|*.bmp|Images (*.emf)|*.emf|Images (*.exif)|*.exif|Images (*.gif)|*.gif|Images (*.ico)|*.ico|Images (*.tiff)|*.tiff|Images (*.wmf)|*.wmf";
            if (sdf.ShowDialog() == DialogResult.OK)
            {
                switch (sdf.FilterIndex)
                {
                    case 1:
                        {
                            output.Save(sdf.FileName, ImageFormat.Jpeg);
                            break;
                        }
                    case 2:
                        {
                            output.Save(sdf.FileName, ImageFormat.Png);
                            break;
                        }
                    case 3:
                        {
                            output.Save(sdf.FileName, ImageFormat.Bmp);
                            break;
                        }
                    case 4:
                        {
                            output.Save(sdf.FileName, ImageFormat.Emf);
                            break;
                        }
                    case 5:
                        {
                            output.Save(sdf.FileName, ImageFormat.Exif);
                            break;
                        }
                    case 6:
                        {
                            output.Save(sdf.FileName, ImageFormat.Gif);
                            break;
                        }
                    case 7:
                        {
                            output.Save(sdf.FileName, ImageFormat.Icon);
                            break;
                        }
                    case 8:
                        {
                            output.Save(sdf.FileName, ImageFormat.Tiff);
                            break;
                        }
                    case 9:
                        {
                            output.Save(sdf.FileName, ImageFormat.Wmf);
                            break;
                        }
                }
                MessageBox.Show("保存成功,位置:" + sdf.FileName);
            }
        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            strength = trackBar1.Value / 100.0;
            label1.Text = $"Strenght: {strength}";
            pictureBox2.Image = Filter(src, mask);
        }

        BoxBlur _boxBlur = new BoxBlur();
        AlphaChannelFilter _alphaChannelFilter = new AlphaChannelFilter();
        Merge _merge = new Merge(0, 0, 255);

        Bitmap Filter(Bitmap image, Bitmap mask)
        {
            int radius = (int)(strength * 2 * ((Math.Max(image.Height, image.Width) / 100) + 1));

            // deep person lab
            var alphaMask = (Bitmap)src.Clone();
            var portrait = (Bitmap)src.Clone();
            var segmentantionMask = (Bitmap)mask.Clone();

            // gaussian blur approximation
            _boxBlur.Size = new SizeInt(radius, radius);
            _boxBlur.Apply(portrait);
            _boxBlur.Apply(segmentantionMask);

            _boxBlur.Size = new SizeInt(radius / 2, radius / 2);
            _boxBlur.Apply(portrait);
            _boxBlur.Apply(segmentantionMask);

            // merging images
            _alphaChannelFilter.Apply(alphaMask, segmentantionMask);
            _merge.Apply(portrait, alphaMask);
            alphaMask.Dispose();
            segmentantionMask.Dispose();

            return portrait;
        }
    }
}

下载

可执行程序exe下载

源码下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1092669.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python文本转语音

概述 目前有文本转语音的技术&#xff0c;可以用在配音领域&#xff0c;我个人因为一些需求&#xff0c;所以开始寻找这方面的资源&#xff0c;目前各大平台&#xff0c;比如腾讯&#xff0c;讯飞&#xff0c;阿里&#xff0c;百度等都有这样的API服务&#xff0c;我个人是是使…

Multi Scale Supervised 3D U-Net for Kidney and Tumor Segmentation

目录 摘要1 引言2 方法2.1 预处理和数据增强2.2 网络的体系结构2.3 训练过程2.4 推理与后处理 3 实验与结果4 结论与讨论 摘要 U-Net在各种医学图像分割挑战中取得了巨大成功。一些新的、带有花里胡哨功能的架构可能在某些数据集中在使用最佳超参数时取得成功&#xff0c;但它们…

力扣-463.岛屿的周长

Idea 注意观察&#xff0c;每一个完整的方块&#xff0c;边长都是加4&#xff0c;一旦这个方块有其他的方块相邻的话&#xff0c;那么这两个方块总边长就要减少2. 因此我们遍历二维数组的时候&#xff0c;判断岛屿方块的上面还有左方是否有相邻即可 class Solution { public:in…

Linux 64位 C++协程池原理分析及代码实现

导语 本文介绍了协程的作用、结构、原理&#xff0c;并使用C和汇编实现了64位系统下的协程池。文章内容避免了协程晦涩难懂的部分&#xff0c;用大量图文来分析原理&#xff0c;适合新手阅读学习。 GitHub源码 1. Web服务器问题 现代分布式Web后台服务逻辑通常由一系列RPC请…

算法村开篇

大家好我是苏麟从今天开始我将带来算法的一些习题和心得体会等等...... 算法村介绍 我们一步步地学习算法本专栏会以闯关的方式来学习算法 循序渐进地系统的学习算法并掌握大部分面试知识 , 期待和大家一起进步 . 索大祝大家学有所成 , 前程似锦.

PyCharm运行Nosetests并导出测试报告

1. Pycharm运行Nosetests PyCharm可以使用两种方法&#xff0c;运行Nosetests测试文件&#xff1a; 1) 图形用户界面GUI a) 在PyCharm中&#xff0c;选中测试文件&#xff0c;如Tests/test_demo.py b) 鼠标右键选择Run Nosetests in test_demo.py即可执行测试 注1&#xff…

【大数据Hive】hive select 语法使用详解

目录 一、前言 二、Hive select 完整语法树 三、Hive select 操作演示 3.1 数据准备 3.1.1 创建一张表 3.1.2 将数据load加载到t_usa_covid19表 3.1.3 再创建一张分区表 3.1.4 使用动态分区插入数据 3.2 select 常用语法 3.2.1 查询所有字段或者指定字段 3.2.2 查询…

【数据库系统概论】第七章数据库设计

7.1数据库设计概述 数据库设计定义是什么&#xff1f; 数据库设计(database design)&#xff1a;数据库设计是指对于一个给定的应用环境&#xff0c;构造(设计)优化的数据库逻辑模式和物理结构&#xff0c;并据此建立数据库及其应用系统&#xff0c;使之能够有效地存储和管理…

【排序算法】详解冒泡排序及其多种优化稳定性分析

文章目录 算法原理细节分析优化1优化2算法复杂度分析稳定性分析总结 算法原理 冒泡排序(Bubble Sort) 就是从序列中的第一个元素开始&#xff0c;依次对相邻的两个元素进行比较&#xff0c;如果前一个元素大于后一个元素则交换它们的位置。如果前一个元素小于或等于后一个元素…

RootSIFT---SIFT图像特征的扩展

RootSIFT是论文 Three things everyone should know to improve object retrieval - 2012所提出的 A Comparative Analysis of RootSIFT and SIFT Methods for Drowsy Features Extraction - 2020 当比较直方图时&#xff0c;使用欧氏距离通常比卡方距离或Hellinger核时的性能…

分析智能平台VMware Greenplum 7 正式发布!

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

芯片学习记录TLP104

TLP104 芯片介绍 引脚信息 引脚1阳极3阴极4GNDGND5输出6VCC5V&#xff08;4.5~30&#xff09; 推荐使用条件 *此项目表示操作范围&#xff0c;而不是建议的操作条件。 注&#xff1a;建议的操作条件作为设计指南&#xff0c;以获得预期的性能设备。此外&#xff0c;每个项目…

HTML5播放 M3U8的hls流地址

在HTML5页面上播放M3U8的hls流地址 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>视频播放</title> <script src"https://cdn.jsdelivr.net/npm/hls.jslatest"></script> &…

Spring6注解管理Bean

文章目录 过程搭建子模块spring6-ioc-annotation使用注解定义 BeanAutowired注入①场景一&#xff1a;属性注入②场景二&#xff1a;set注入③场景三&#xff1a;构造方法注入④场景四&#xff1a;形参上注入⑤场景五&#xff1a;只有一个构造函数&#xff0c;无注解⑥场景六 A…

Vue3 + Quasar系列-代码配置以及报错汇总记录(不断更新中)

1. Vue3 Quasar系列-代码配置打包去掉hash后缀 去掉hash https://quasar.dev/quasar-cli-vite/developing-pwa/configuring-pwa 2. Vue3 Quasar改变主题背景 quasar的样式和其他的框架修改不太一样&#xff0c;需要我们使用动态的方式来进行变更&#xff0c;一般来说有两…

计算机毕业设计 高校实习信息发布网站的设计与实现 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

宝塔使用腾讯COS存储实现自动备份服务器网站数据图文教程

一、进入宝塔安装腾讯COS 点击设置打开后需要配置以下cos参数 二、腾讯云创建COS存储桶 选择私有读写&#xff0c;其他默认就行 三、创建访问密钥 四、配置宝塔中腾讯COS相关设置 很多人是配置错误导致无法正常链接cos region为cos存储桶所属地域 Bucker为存储桶名称 五、…

力扣-461.汉明距离

Method 1 直接比较x&#xff0c;y二进制中的每一位&#xff0c;如果不同则cnt加一&#xff0c;并且x&#xff0c;y每次右移一位 class Solution { public:int hammingDistance(int x, int y) {int cnt 0;while(x > 0 && y > 0) {if((x & 1) ! (y & 1)…

MySQL 2023 MySQL Summit 大会感受,我们距离MySQL 新技术越来越远

开头还是介绍一下群&#xff0c;如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, Oceanbase, Sql Server等有问题&#xff0c;有需求都可以加群&#xff0c;群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;…

2023.10.14 培训总结

培训内容 数字模型联合仿真及集成测试技术 MBSE(Model-Based-System-Engiaeering&#xff09; 参数化建模参数化仿真 产生的疑问 支持面向对象支持CAE CFD工具优化工具 飞机的业务功能 开发分布式架构 新技术 WSDL协议DDS 发布/订阅SAOPCORBA 明显开发者 Chris Garrett 美…