opencv进阶 ——(九)图像处理之人脸修复祛马赛克算法CodeFormer

算法简介

CodeFormer是一种基于AI技术深度学习的人脸复原模型,由南洋理工大学和商汤科技联合研究中心联合开发,它能够接收模糊或马赛克图像作为输入,并生成更清晰的原始图像。算法源码地址:https://github.com/sczhou/CodeFormer

Face Restoration

Face Color Enhancement and Restoration

Face Inpainting

模型部署

        如果想用C++进行模型推理部署,首先要把模型转换成onnx,转成onnx就可以使用onnxruntime c++库进行部署,或者使用OpenCV的DNN也可以。

        1、可在以下地址下载模型:https://github.com/sczhou/CodeFormer/releases/tag/v0.1.0

        2、下载CodeFormer源码,在工程目录下添加onnx转换python代码

import torch
from basicsr.utils.registry import ARCH_REGISTRYif __name__ == '__main__':device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')net = ARCH_REGISTRY.get('CodeFormer')(dim_embd=512, codebook_size=1024, n_head=8, n_layers=9, connect_list=['32', '64', '128', '256']).to(device)# ckpt_path = 'weights/CodeFormer/codeformer.pth'ckpt_path = './codeformer.pth'checkpoint = torch.load(ckpt_path)['params_ema']net.load_state_dict(checkpoint)net.eval()input_tensor = torch.zeros((1, 3, 512, 512)).to(device)torch.onnx.export(net,  # 模型实例input_tensor,  # 输入张量"./codeformer.onnx",  # 输出的ONNX模型路径export_params=True,  # 是否包含模型参数opset_version=11,  # ONNX操作集版本do_constant_folding=True,  # 是否进行常量折叠优化input_names=['input'],  # 输入名称output_names=['output'],  # 输出名称dynamic_axes={'input': {0: 'batch_size'}, 'output': {0: 'batch_size'}}  # 声明动态轴)

        3、采用onnxruntime加载模型,示例代码如下

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <fstream>
#include <numeric>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
//#include <cuda_provider_factory.h>  ///nvidia-cuda加速
#include <onnxruntime_cxx_api.h>using namespace cv;
using namespace std;
using namespace Ort;class CodeFormer
{
public:CodeFormer(string modelpath);Mat detect(Mat cv_image);
private:void preprocess(Mat srcimg);vector<float> input_image_;vector<double> input2_tensor;int inpWidth;int inpHeight;int outWidth;int outHeight;float min_max[2] = { -1,1 };//存储初始化获得的可执行网络Env env = Env(ORT_LOGGING_LEVEL_ERROR, "CodeFormer");Ort::Session *ort_session = nullptr;SessionOptions sessionOptions = SessionOptions();vector<char*> input_names;vector<char*> output_names;vector<vector<int64_t>> input_node_dims; // >=1 outputsvector<vector<int64_t>> output_node_dims; // >=1 outputs
};CodeFormer::CodeFormer(string model_path)
{//OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CUDA(sessionOptions, 0);  ///nvidia-cuda加速sessionOptions.SetGraphOptimizationLevel(ORT_ENABLE_BASIC);std::wstring widestr = std::wstring(model_path.begin(), model_path.end());   ///如果在windows系统就这么写ort_session = new Session(env, widestr.c_str(), sessionOptions);   ///如果在windows系统就这么写///ort_session = new Session(env, model_path.c_str(), sessionOptions);  ///如果在linux系统,就这么写size_t numInputNodes = ort_session->GetInputCount();size_t numOutputNodes = ort_session->GetOutputCount();AllocatorWithDefaultOptions allocator;for (int i = 0; i < numInputNodes; i++){input_names.push_back(ort_session->GetInputName(i, allocator));Ort::TypeInfo input_type_info = ort_session->GetInputTypeInfo(i);auto input_tensor_info = input_type_info.GetTensorTypeAndShapeInfo();auto input_dims = input_tensor_info.GetShape();input_node_dims.push_back(input_dims);}for (int i = 0; i < numOutputNodes; i++){output_names.push_back(ort_session->GetOutputName(i, allocator));Ort::TypeInfo output_type_info = ort_session->GetOutputTypeInfo(i);auto output_tensor_info = output_type_info.GetTensorTypeAndShapeInfo();auto output_dims = output_tensor_info.GetShape();output_node_dims.push_back(output_dims);}this->inpHeight = input_node_dims[0][2];this->inpWidth = input_node_dims[0][3];this->outHeight = output_node_dims[0][2];this->outWidth = output_node_dims[0][3];input2_tensor.push_back(0.5);
}void CodeFormer::preprocess(Mat srcimg)
{Mat dstimg;cvtColor(srcimg, dstimg, COLOR_BGR2RGB);resize(dstimg, dstimg, Size(this->inpWidth, this->inpHeight), INTER_LINEAR);this->input_image_.resize(this->inpWidth * this->inpHeight * dstimg.channels());int k = 0;for (int c = 0; c < 3; c++){for (int i = 0; i < this->inpHeight; i++){for (int j = 0; j < this->inpWidth; j++){float pix = dstimg.ptr<uchar>(i)[j * 3 + c];this->input_image_[k] = (pix / 255.0 - 0.5) / 0.5;k++;}}}
}Mat CodeFormer::detect(Mat srcimg)
{int im_h = srcimg.rows;int im_w = srcimg.cols;this->preprocess(srcimg);array<int64_t, 4> input_shape_{ 1, 3, this->inpHeight, this->inpWidth };vector<int64_t> input2_shape_ = { 1 };auto allocator_info = MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);vector<Value> ort_inputs;ort_inputs.push_back(Value::CreateTensor<float>(allocator_info, input_image_.data(), input_image_.size(), input_shape_.data(), input_shape_.size()));ort_inputs.push_back(Value::CreateTensor<double>(allocator_info, input2_tensor.data(), input2_tensor.size(), input2_shape_.data(), input2_shape_.size()));vector<Value> ort_outputs = ort_session->Run(RunOptions{ nullptr }, input_names.data(), ort_inputs.data(), ort_inputs.size(), output_names.data(), output_names.size());post_processfloat* pred = ort_outputs[0].GetTensorMutableData<float>();//Mat mask(outHeight, outWidth, CV_32FC3, pred); /经过试验,直接这样赋值,是不行的const unsigned int channel_step = outHeight * outWidth;vector<Mat> channel_mats;Mat rmat(outHeight, outWidth, CV_32FC1, pred); // RMat gmat(outHeight, outWidth, CV_32FC1, pred + channel_step); // GMat bmat(outHeight, outWidth, CV_32FC1, pred + 2 * channel_step); // Bchannel_mats.push_back(rmat);channel_mats.push_back(gmat);channel_mats.push_back(bmat);Mat mask;merge(channel_mats, mask); // CV_32FC3 allocated///不用for循环遍历Mat里的每个像素值,实现numpy.clip函数mask.setTo(this->min_max[0], mask < this->min_max[0]);mask.setTo(this->min_max[1], mask > this->min_max[1]);   也可以用threshold函数,阈值类型THRESH_TOZERO_INVmask = (mask - this->min_max[0]) / (this->min_max[1] - this->min_max[0]);mask *= 255.0;mask.convertTo(mask, CV_8UC3);cvtColor(mask, mask, COLOR_BGR2RGB);return mask;
}int main()
{CodeFormer mynet("codeformer.onnx");string imgpath = "input.png";Mat srcimg = imread(imgpath);Mat dstimg = mynet.detect(srcimg);resize(dstimg, dstimg, Size(srcimg.cols, srcimg.rows), INTER_LINEAR);//imwrite("result.jpg", dstimg)namedWindow("srcimg", WINDOW_NORMAL);imshow("srcimg", srcimg);namedWindow("dstimg", WINDOW_NORMAL);imshow("dstimg", dstimg);waitKey(0);destroyAllWindows();
}

效果展示

面部恢复

面部色彩增强与恢复

面部修复

破旧照片修复效果

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是Spark RDD?(RDD的介绍与创建)

什么是Spark RDD&#xff1f;(RDD的介绍与创建) 一、RDD介绍 1、特点2、RDD的存储和指向3、RDD与DAG4、RDD的特性5、RDD分区6、RDD操作类型 二、RDD创建 1、引入必要的 Spark 库2、配置 Spark3、RDD创建4、示例代码 一、RDD介绍 RDD: 弹性分布式数据集&#xff08;Resilient…

Go微服务: 基于rocketmq:5.2.0搭建RocketMQ环境,以及示例参考

概述 参考最新官方文档&#xff1a;https://rocketmq.apache.org/zh/docs/quickStart/03quickstartWithDockercompose以及&#xff1a;https://rocketmq.apache.org/zh/docs/deploymentOperations/04Dashboard综合以上两个文档来搭建环境 搭建RocketMQ环境 1 ) 基于 docker-c…

K8S==ingress配置自签名证书

安装openssl Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions 生成证书 openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout example.local.key -out example.local.crt -subj "/CNexample.local/Oexample.local"创建K8S secr…

【JVM】已验鼎真,鉴定为:妈妈加载的(双亲委派模型)

【JVM】已验鼎真&#xff0c;鉴定为&#xff1a;妈妈加载的&#xff08;双亲委派模型&#xff09; 在Java的世界中&#xff0c;类加载器&#xff08;ClassLoader&#xff09;是Java虚拟机&#xff08;JVM&#xff09;用来动态加载类的基础组件。双亲委派模型&#xff08;Paren…

Java基础27,28(多线程,ThreadMethod ,线程安全问题,线程状态,线程池)

目录 一、多线程 1. 概述 2. 进程与线程 2.1 程序 2.2 进程 2.3 线程 2.4 进程与线程的区别 3. 线程基本概念 4.并发与并行 5. 线程的创建方式 方式一&#xff1a;继承Thread类 方式二&#xff1a;实现Runable接口 方式三&#xff1a;实现Callable接口 方式四&…

C#操作MySQL从入门到精通(10)——对查询数据进行通配符过滤

前言 我们有时候需要查询数据,并且这个数据包含某个字符串,这时候我们再使用where就无法实现了,所以mysql中提供了一种模糊查询机制,通过Like关键字来实现,下面进行详细介绍: 本次查询的表中数据如下: 1、使用(%)通配符 %通配符的作用是,表示任意字符出现任意次数…

【简单讲解TalkingData的数据统计】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

Python04:python代码设置作者/创建时间/文件名称

我们新建一个py文件时&#xff0c;如果希望文件开头有固定的内容&#xff0c;怎么设置呢&#xff1f; 比如代码作者、文件创建时间等。。。 1、点击左上角【Python】–>【Settings】设置 2、在弹出的新窗口找到【File and Code Templates】–>【Python Script】–>在右…

鸿蒙小案例-音乐播放器

之前参加鸿蒙比赛的音乐播放器 效果展示 HF音乐效果展示 功能列 有一些功能没写上去&#xff0c;自行发掘 说明&#xff1a; 1.API:网易云接口&#xff0c;QQ个人接口&#xff0c; 需要请看gitee 2.本地关系型数据由bug,提的工单已确认&#xff0c;建议使用API11,12,9的不稳…

java代码审计之fastjson反序列化漏洞

fastjson反序列化漏洞分析 Fastjson 是一个 Java 库&#xff0c;可以将 Java 对象转换为 JSON 格式&#xff0c;当然它也可以将 JSON 字符串转换为 Java 对象。Fastjson 可以操作任何 Java 对象&#xff0c;即使是一些预先存在的没有源码的对象。该产品主要提供了两个接口&…

创新入门|营销中的视频内容:不可或缺的策略

视频在营销中日益重要。你是否也发现,视频内容最近似乎无处不在?它占据着社交媒体的推文、网站首页,甚至电子邮件中的位置。事实上,并不是你一个人有这样的感受。在过去十年中,视频作为一种营销手段日益成熟和强大。这是因为,人类天生就是视觉动物。我们大脑处理视觉信息的速度…

Priority_queue

一、priority_queue的介绍和使用 1.1 priority_queue的介绍 1.优先队列是一种容器适配器&#xff0c;根据严格的弱排序标准&#xff0c;它的第一个元素总是它所包含的元素中最大的。 2.优先队列类似于堆&#xff0c; 在堆中可以随时插入元素&#xff0c; 并且只能检索最大堆…

硕士课程 可穿戴设备之作业一

作业一 第一个代码使用的方法是出自于[1]。 框架结构 如下图&#xff0c;不过根据对代码的解读&#xff0c;发现作者在代码中省去了对SSR部件的实现&#xff0c;下文再说。 Troika框架由三个关键部件组成&#xff1a;信号分解&#xff0c;SSR和光谱峰值跟踪。&#xff08;粗…

word 无法自动检测拼写

word 有时候不能分辨是哪种语言,比如把英语错认为法语 。 例如&#xff1a;Interlaayer spacace,发现误认为是法语。 1、选中Interlaayer spacace 2、点击语言下拉按钮 选择设置校对语言 发现校对语言为法语 3、手动修改校对语言为英语&#xff0c;并点击确认。 4、发现现…

升级鸿蒙4.2新变化,新增 WLAN 网络自动连接开关!

手机已经成为现代人生活中不可或缺的一部分&#xff0c;手机里的功能可以满足大部分人的生活场景&#xff0c;但是最依赖的应该就是手机网络&#xff0c;手机网络突然变差怎么办——消息发不出去&#xff1f;刷新闻速度变慢&#xff1f;仔细检查后&#xff0c;发现其实不是手机…

【一步一步了解Java系列】:重磅多态

看到这句话的时候证明&#xff1a;此刻你我都在努力 加油陌生人 个人主页&#xff1a;Gu Gu Study专栏&#xff1a;一步一步了解Java 喜欢的一句话&#xff1a; 常常会回顾努力的自己&#xff0c;所以要为自己的努力留下足迹 喜欢的话可以点个赞谢谢了。 作者&#xff1a;小闭…

E10:流程主表表单字段值变化触发事件

效果– //window.WeFormSDK.showMessage("这是一个E10的提示", 3, 2); const onClickCreate () > console.log("create"); const onClickSave () > console.log("save"); const onClickCancel () > dialogComponent?.destroy();/…

Python量化交易学习——Part4:基于基本面的单因子选股策略

技术分析与基本面分析是股票价格分析最基础也是最经典的两个部分。技术分析是针对交易曲线及成交量等指标进行分析,基本面分析是基于公司的基本素质进行分析。 一般来说选股要先选行业,在选个股,之后根据技术分析选择买卖节点,因此针对行业及个股的基本面分析是选股的基础。…

排序算法集合

1. 冒泡排序 排序的过程分为多趟&#xff0c;在每一趟中&#xff0c;从前向后遍历数组的无序部分&#xff0c;通过交换相邻两数位置的方式&#xff0c;将无序元素中最大的元素移动到无序部分的末尾&#xff08;第一趟中&#xff0c;将最大的元素移动到数组倒数第一的位置&…

【scikit-learn010】sklearn算法模型清单实战及经验总结(已更新)

1.一直以来想写下基于scikit-learn训练AI算法的系列文章,作为较火的机器学习框架,也是日常项目开发中常用的一款工具,最近刚好挤时间梳理、总结下这块儿的知识体系。 2.熟悉、梳理、总结下scikit-learn框架模型算法包相关技术点及经验。 3.欢迎批评指正,欢迎互三,跪谢一键…