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_REGISTRY

if __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 outputs
	vector<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_process
	float* 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); // R
	Mat gmat(outHeight, outWidth, CV_32FC1, pred + channel_step); // G
	Mat bmat(outHeight, outWidth, CV_32FC1, pred + 2 * channel_step); // B
	channel_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_INV

	mask = (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();
}

效果展示

面部恢复

面部色彩增强与恢复

面部修复

破旧照片修复效果

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SAP PP学习笔记14 - MTS(Make-to-Stock) 按库存生产(策略10),以及生产计划的概要

上面讲了SAP里面的基础知识&#xff0c;BOM&#xff0c;作业手顺&#xff08;工艺路线&#xff09;&#xff0c;作业区&#xff08;工作中心&#xff09;&#xff0c;MRP&#xff0c;MPS等概念&#xff0c;现在该到用的时候了。 SAP PP学习笔记07 - 简单BOM&#xff0c;派生BO…

【教程】如何实现WordPress网站降级(用于解决插件和主题问题)

在最新可用版本上运行WordPress安装、插件和主题是使用该平台的关键最佳实践。还建议使用最新版本的PHP。但是,在某些情况下,这是不谨慎或不可能的。 如果您发现自己处于这种情况,您可能需要撤消更新并降级您的WordPress网站(或其中的一部分)。幸运的是,有一些方法可用于…

uniapp 怎么设置凸起的底部tabbar

1. uniapp 怎么设置凸起的底部tabbar 1.1. 方案一系统提供 1.1.1. 使用uniapp官方提供的属性midButton 使用时&#xff0c;list数组须为偶数 &#xff08;1&#xff09;pages.json "tabBar": {"custom": true,"color": "#8F8F94",&q…

推荐网站(19)anytools图片分辨率处理网站

今天&#xff0c;我要向您推荐一个非常实用的在线图片处理工具网站——AnyTools。这个网站提供了一站式的图片分辨率处理服务&#xff0c;并且具备添加各种过滤器的功能&#xff0c;非常适合需要快速调整图片大小和风格优化的场合。 多分辨率支持&#xff1a;用户可以自定义图片…

(南京观海微电子)——LVD屏介绍

LVDS&#xff08;Low Voltage Differential Signaling&#xff0c;即 低电压差分信号 &#xff09; 接口又称 RS-644 总线接口&#xff0c;是20世纪90年代才提出的一种 数据传输 和接口技术。 LVDS接口是美国NS美国国家半导体公司为克服以 TTL电平 方式传输宽带高码率数据时功…

Linux--线程的互斥

线程系列&#xff1a; 一、线程的认识&#xff1a;线程的认识&#xff1a;误进解线程的概念和线程的基本控制 二、Linux–线程的分离、线程库的地址关系的理解、线程的简单封装 线程的互斥 线程互斥&#xff08;Thread Mutual Exclusion&#xff09;是多线程编程中的一个重要概…

软件测试进阶

目录 一、自动化测试 1.概念 2.Selenium 2.1 概念 2.1.1 Selenium是什么&#xff1f; 2.1.2 Selenium特点 2.1.3 工作原理 2.2 SeleniumJava环境搭配 2.3 定位元素 2.3.1 CSS语法 2.3.2 XPath语法 2.4 应用 2.4.1 点击提交文本 2.4.2 模拟输入 2.4.3 清除文本 2…

驰骋低代码开发平台概念与主张

驰骋低代码开发平台概念与主张 一、引言 在数字化转型的浪潮中&#xff0c;低代码开发平台因其高效、灵活、成本效益显著的特点&#xff0c;逐渐成为企业快速构建应用系统的首选。作为国内领先的开源低代码开发平台&#xff0c;驰骋低代码致力于为企业和开发者提供一套全面、…

(南京观海微电子)——屏幕材质及优缺点对比

LED/LCD LCD&#xff08;Liquid Crystal Ddisplay&#xff09;即“液晶显示器”&#xff0c;由两块偏光镜、两块薄膜晶体管以及彩色滤光片、光源&#xff08;荧光灯&#xff09;、显示面板组成的成像元器件。 LED&#xff08;Light Emitting Diode&#xff09;即“发光二极管…

冒泡排序与快速排序

博主主页: 码农派大星. 数据结构专栏:Java数据结构 数据库专栏:MySQL数据库 关注博主带你了解更多数据结构知识 1.冒泡排序 冒泡排序 private static void swap(int[] arrary,int i,int j){int tmp arrary[i];arrary[i] arrary[j];arrary[j] tmp;public static void bubbl…

[docker] docker 安全知识 - docker api, 权限提升 资源管理

[docker] docker 安全知识 - docker api, 权限提升 & 资源管理 这是 docker 安全的最后一篇 暴露 docker api 在 [docker] docker 安全知识 - docker 系统性简介 中曾经提到&#xff0c;docker cli 使用 restful api 与客户端和 docker daemon 之间交流。默认情况下&…

国内的期权模拟账户怎么申请?

国内的期权模拟账户可以在券商和期权分仓平台处申请开通&#xff0c;期权相比于股票具有杠杆投资、风险控制等新特性。 期权模拟交易客户端能够提供期权的开平仓交易、备兑开仓&#xff0f;平仓、行权等交易指令&#xff0c;下文为大家介绍国内的期权模拟账户怎么申请&#xff…

安卓模拟键盘蓝牙电脑apk

蓝牙连接电脑就可以使用了。 下载地址&#xff1a;点击下载https://download.csdn.net/download/jasonhongcn/89382597

【基础算法总结】模拟算法

模拟算法 1.替换所有的问号2.提莫攻击3.Z 字形变换4.外观数列5.数青蛙 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 模拟算法 —> 比葫芦…

npm发布、更新、删除包

如何将自己开发的依赖包发布到npmjs上供别人使用&#xff1f;五个步骤搞定&#xff01; 实现步骤&#xff1a; 创建自己的工具包项目&#xff0c;进行开发。注册npmjs账号。执行npm login在控制台登录&#xff0c;填写用户信息。执行npm publish发布包。更新及删除。 步骤一…

Leetcode - 周赛399

目录 一&#xff0c;3162. 优质数对的总数 I 二&#xff0c;3163. 压缩字符串 III 三&#xff0c;3164. 优质数对的总数 II 四&#xff0c; 3165. 不包含相邻元素的子序列的最大和 一&#xff0c;3162. 优质数对的总数 I 假设 x 是 nums1 数组中的值&#xff0c;y 是 nums2…

Docker部署SiYuan笔记-Unraid

使用unraid的docker部署SiYuan笔记&#xff0c;简单记录 笔记说明 Siyuan笔记是一款基于markdown语法的笔记工具&#xff0c;具有活跃的社区和多设备支持。大部分功能都是免费&#xff0c;源代码开源&#xff0c;支持插件安装&#xff0c;具有很不错的使用体验。 Docker地址&a…

【应用层】 DNS 域名协议解析

文章目录 DNS(Domain Name System)出现及演化 ⏳DNS 概括&#x1f50d;DNS定义DNS 作用 DNS工作原理⚙️域名解析DNS解析的详细工作流程 DNS域名解析方式&#x1f504;静态DNS域名解析动态DNS域名解析 DNS域名解析过程的深入分析 &#x1f9d0;递归查询迭代查询 公共DNS服务器的…

Python 机器学习 基础 之 处理文本数据 【停用词/用tf-idf缩放数据/模型系数/多个单词的词袋/高级分词/主题建模/文档聚类】的简单说明

Python 机器学习 基础 之 处理文本数据 【停用词/用tf-idf缩放数据/模型系数/多个单词的词袋/高级分词/主题建模/文档聚类】的简单说明 目录 Python 机器学习 基础 之 处理文本数据 【停用词/用tf-idf缩放数据/模型系数/多个单词的词袋/高级分词/主题建模/文档聚类】的简单说明…

AI帮写:探索国内AI写作工具的创新与实用性

随着AI技术的快速发展&#xff0c;AI写作正成为创作的新风口。但是面对GPT-4这样的国际巨头&#xff0c;国内很多小伙伴往往望而却步&#xff0c;究其原因&#xff0c;就是它的使用门槛高&#xff0c;还有成本的考量。 不过&#xff0c;随着GPT技术的火热&#xff0c;国内也涌…