C# 人像卡通化 Onnx photo2cartoon

news2024/11/20 0:40:32

效果

项目

代码

using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace 人像卡通化
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            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;
        Mat result_image;
        int modelSize = 256;

        SessionOptions options;
        InferenceSession onnx_session;
        Tensor<float> input_tensor;
        List<NamedOnnxValue> input_ontainer;
        IDisposableReadOnlyCollection<DisposableNamedOnnxValue> result_infer;
        DisposableNamedOnnxValue[] results_onnxvalue;

        Tensor<float> result_tensors;
        float[] result_array;

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

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

            textBox1.Text = "";
            pictureBox2.Image = null;

            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));
            int width = resize_image.Cols;
            int height = resize_image.Rows;
            if (width != modelSize || height != modelSize)
            {
                resize_image = resize_image.CopyMakeBorder(0, modelSize - newHeight, 0, modelSize - newWidth, BorderTypes.Constant, new Scalar(255, 255, 255));
            }

            Cv2.CvtColor(resize_image, resize_image, ColorConversionCodes.BGR2RGB);

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

            //将 input_tensor 放入一个输入参数的容器,并指定名称
            input_ontainer.Add(NamedOnnxValue.CreateFromTensor("input", 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<float>();

            result_array = result_tensors.ToArray();

            float[] temp_r = new float[256 * 256];
            float[] temp_g = new float[256 * 256];
            float[] temp_b = new float[256 * 256];

            Array.Copy(result_array, temp_r, 256 * 256);
            Array.Copy(result_array, 256 * 256, temp_g, 0, 256 * 256);
            Array.Copy(result_array, 256 * 256 * 2, temp_b, 0, 256 * 256);

            Mat rmat = new Mat(256, 256, MatType.CV_32F, temp_r);
            Mat gmat = new Mat(256, 256, MatType.CV_32F, temp_g);
            Mat bmat = new Mat(256, 256, MatType.CV_32F, temp_b);

            rmat = (rmat + 1f) * 127.5f;
            gmat = (gmat + 1f) * 127.5f;
            bmat = (bmat + 1f) * 127.5f;

            result_image = new Mat();
            Cv2.Merge(new Mat[] { rmat, gmat, bmat }, result_image);

            if (!result_image.Empty())
            {
                //还原图像大小
                if (width != modelSize || height != modelSize)
                {
                    Rect rect = new Rect(0, 0, width, height);
                    result_image = result_image.Clone(rect);
                }
                result_image = result_image.Resize(new OpenCvSharp.Size(oldwidth, oldheight));

                pictureBox2.Image = new Bitmap(result_image.ToMemoryStream());
                textBox1.Text = "推理耗时:" + (dt2 - dt1).TotalMilliseconds + "ms";
            }
            else
            {
                textBox1.Text = "无信息";
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            startupPath = System.Windows.Forms.Application.StartupPath;
            model_path = startupPath + "\\photo2cartoon_weights.onnx";

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

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

            // 输入Tensor
            input_tensor = new DenseTensor<float>(new[] { 1, 3, 256, 256 });

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

Demo下载

说明

1、该例子只是人像转卡通像,转之前需要如下前置处理(为了效果更好)

  • 检测人脸及关键点。
  • 根据关键点旋转校正人脸。
  • 将关键点边界框按固定的比例扩张并裁剪出人脸区域。
  • 使用人像分割模型将背景置白。

2、该模型不能用于分割半身像,因为该模型是专用模型,需先裁剪出人脸区域再输入

人像分割参考:

C# PaddleInference.PP-HumanSeg 人像分割 替换背景色-CSDN博客

人脸检测参考:

C# DlibDotNet 人脸识别、人脸68特征点识别、人脸5特征点识别、人脸对齐,三角剖分,人脸特征比对-CSDN博客

3、参考

GitHub - minivision-ai/photo2cartoon-paddle: 人像卡通化探索项目 (photo-to-cartoon translation project)

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

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

相关文章

NLP项目:维基百科文章爬虫和分类【02】 - 语料库转换管道

一、说明 我的NLP项目在维基百科条目上下载、处理和应用机器学习算法。相关上一篇文章中&#xff0c;展示了项目大纲&#xff0c;并建立了它的基础。首先&#xff0c;一个 Wikipedia 爬网程序对象&#xff0c;它按名称搜索文章&#xff0c;提取标题、类别、内容和相关页面&…

【毕设选题】深度学习 机器视觉 车位识别车道线检测 - python opencv

0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业答辩的要求&#xff0c;这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过…

第二证券:如何选股票的龙头股?

在股票商场中&#xff0c;每个出资者的方针都是可以出资到那些未来可以表现出色并带领整个工作开展的龙头股。选股关于出资者来说非常要害&#xff0c;由于选股不妥或许会导致出资失利。那么&#xff0c;怎么选股票的龙头股呢&#xff1f;本文从多个角度进行剖析&#xff0c;协…

platformIO开发arduino

第一先安装arduino,再在arduino库里面安装第三方库。然后下载vscode,在vscode上安装platformIO&#xff0c;然后点击Quick Access下的Import Arduino Project 然后选择自己的arudino项目&#xff0c;一般在用户的Document下面 进入带有.ino后缀的文件夹里然后点击import就可以将…

C语言每日一题(10) 回形矩阵

题目链接 分析思路 我采用的设计思路是从外围开始向里面赋值&#xff0c;关键在于循环的判断条件&#xff0c;从外围的上下左右行依次赋值&#xff0c;然后再向里继续。 1.取得中心值的方法是&#xff1a;用n/2再向上取整&#xff0c;注意类型的转换&#xff0c;因为如果是整…

软件工程与计算总结(六)需求分析方法

本贴介绍需求分析方法&#xff0c;涉及到诸多实践性的东西&#xff0c;掌握各种图表的绘制是重中之重~ 一.需求分析基础 1.原因 需求获取中得到的信息仅仅解释了用户对软件系统的理解与期待&#xff0c;使用的是实际业务的表达方式&#xff0c;还不是开发者能够立即加以实现…

Ubuntu20.04安装Ipopt的流程介绍及报错解决方法(亲测简单有效)

本文主要介绍在Ubuntu20.04中安装Ipopt库的流程&#xff0c;及过程报错的解决方法&#xff0c;已经有很多关于Ipopt安装的博客&#xff0c;但经过我的测试&#xff0c;很多都失效了&#xff0c;因此&#xff0c;经过探索&#xff0c;我找到可流畅的安装Ipopt的方法&#xff0c;…

一站式数据可视化与分析平台JVS智能BI强大的数据节点功能

在商业智能&#xff08;BI&#xff09;中&#xff0c;数据集是数据的集合&#xff0c;用于分析和报告。数据节点是数据集中的一个重要组成部分&#xff0c;它代表数据集中的一个特定数据点或数据元素。通过使用数据节点&#xff0c;可以对数据进行过滤、分组和计算&#xff0c;…

Netty通信在中间件组件中的广泛使用-Dubbo3举例

Netty是一个高性能异步IO通信框架&#xff0c;封装了NIO&#xff0c;对各种bug做了很好的优化解决。所以很多中间件底层的通信都会使用Netty&#xff0c;比如说&#xff1a;Dubbo3&#xff0c;rocketmq&#xff0c;ElasticSearch等。 比方说&#xff0c;我们使用dubbo作为rpc跨…

批量混剪系统视频闪闪批量剪辑:只需几段素材片段即可批量混剪大量成片,快速制作大量成片的秘密

视频闪闪批量混剪系统&#xff1a;快速制作大量成片的秘密 在今天这个视频内容爆炸的时代&#xff0c;如何快速处理大量的素材并生成优质的成片&#xff0c;是许多视频制作人员面临的挑战。而视频闪闪批量混剪系统&#xff0c;却能帮助你轻松解决这一难题。 视频闪闪批量混剪…

Qt多工程同名字段自动翻译工具

开发背景 项目里不同工程经常会引用同一批公共类&#xff0c;这些类里如果有字段需要翻译&#xff0c;需要在不同的项目里都翻译一遍&#xff0c;比较麻烦冗余。 特此开发了这个小翻译工具&#xff0c;能读取程序目录下的所有ts文件&#xff0c;以类名归类&#xff0c;不同项目…

登陆认证权限控制(1)——从session到token认证的变迁 session的问题分析 + CSRF攻击的认识

前言 登陆认证&#xff0c;权限控制是一个系统必不可少的部分&#xff0c;一个开放访问的系统能否在上线后稳定持续运行其实很大程度上取决于登陆认证和权限控制措施是否到位&#xff0c;不然可能系统刚刚上线就会夭折。 本篇博客回溯登陆认证的变迁历史&#xff0c;阐述sess…

查找算法 —— 斐波拉契查找法

一、介绍 斐波拉契查找法是以分割范围进行查找的&#xff0c;分割的方式是按照斐波拉契级数的方式来分割。好处是&#xff1a;只用到加减运算&#xff0c;计算效率较高一些。 要使用斐波拉契查找首先需要定义一颗斐波拉契查找树&#xff0c;建立规则如下&#xff1a; 1.斐波拉契…

德国鞋履品牌【Birkenstock】申请15亿美元纳斯达克IPO上市

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;德国鞋履品牌【Birkenstock】近期已向美国证券交易委员会&#xff08;SEC&#xff09;提交招股书&#xff0c;申请在纳斯达克IPO上市&#xff0c;股票代码为&#xff08;BIRK&#xff09;,Birkens…

Vue-1.9工程化开发和脚手架

开发Vue的两种方式&#xff1a; 1.核心包传统开发模式&#xff1a;基于html/css/js文件&#xff0c;直接引入核心包&#xff0c;开发Vue 2.工程化开发模式&#xff1a;基于构建工具&#xff08;例如&#xff1a;webpack&#xff09;的环境中开发Vue 问题&#xff1a; 1&…

如何安装TortoiseSVN并实现公网提交文件至本地SVN服务器?

文章目录 前言1. TortoiseSVN 客户端下载安装2. 创建检出文件夹3. 创建与提交文件4. 公网访问测试 前言 TortoiseSVN是一个开源的版本控制系统&#xff0c;它与Apache Subversion&#xff08;SVN&#xff09;集成在一起&#xff0c;提供了一个用户友好的界面&#xff0c;方便用…

设计模式16、中介者模式 Mediator

解释说明&#xff1a;中介者模式&#xff08;Mediator Pattern&#xff09;用一个中介对象来封装一系列的对象交互 中介者使各对象不需要显式地相互引用&#xff0c;从而使其耦合松散&#xff0c;而且可以独立地改变它们之间的交互。 抽象中介者&#xff08;Mediator&#xff0…

Kaadas凯迪仕助力亚运盛会,尽展品牌硬核科技与智能锁行业风采

9月23日至10月8日&#xff0c;亚洲最大规模体育赛事亚运会在杭州举办。作为国际性体育赛事&#xff0c;除赛中的各类竞赛项目外&#xff0c;杭州亚运会前后相关活动也吸引了大众目光的聚焦。 Kaadas凯迪仕智能锁作为此次杭州亚运会官方指定智能门锁&#xff0c;以#凯迪仕守护每…

IP真人识别方法与代理IP检测技术

随着互联网的发展&#xff0c;IP地址在网络安全和数据分析中扮演着重要的角色。为了维护网络的安全性和识别真实用户&#xff0c;IP地址的真实性和来源成为了一个关键问题。 什么是IP真人识别&#xff1f; IP真人识别是一种技术&#xff0c;旨在确定IP地址背后的用户是否为真实…

深入理解RBAC

RBAC是一种基于角色实现访问控制的权限管理机制&#xff0c;通过定义角色和权限、用户和角色、角色和角色之间的关系&#xff0c;实现多层次、细粒度、可复用的权限管理系统。原文: Role-based Access Control (RBAC) Model[1] Bernard HermantUnsplash Avery Pennarun写的&quo…