国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

人臉修復(fù)祛馬賽克算法CodeFormer——C++與Python模型部署

這篇具有很好參考價(jià)值的文章主要介紹了人臉修復(fù)祛馬賽克算法CodeFormer——C++與Python模型部署。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

一、人臉修復(fù)算法

1.算法簡(jiǎn)介

CodeFormer是一種基于AI技術(shù)深度學(xué)習(xí)的人臉復(fù)原模型,由南洋理工大學(xué)和商湯科技聯(lián)合研究中心聯(lián)合開(kāi)發(fā),它能夠接收模糊或馬賽克圖像作為輸入,并生成更清晰的原始圖像。算法源碼地址:https://github.com/sczhou/CodeFormer
這種技術(shù)在圖像修復(fù)、圖像增強(qiáng)和隱私保護(hù)等領(lǐng)域可能會(huì)有廣泛的應(yīng)用。算法是由南洋理工大學(xué)和商湯科技聯(lián)合研究中心聯(lián)合開(kāi)發(fā)的,結(jié)合了VQGAN和Transformer。
VQGAN是一個(gè)生成模型,通常用于圖像生成任務(wù)。它使用了向量量化技術(shù),將圖像編碼成一系列離散的向量,然后通過(guò)解碼器將這些向量轉(zhuǎn)化為圖像。這種方法通常能夠生成高質(zhì)量的圖像,尤其在與Transformer等神經(jīng)網(wǎng)絡(luò)結(jié)合使用時(shí)。
Transformer是一種廣泛用于自然語(yǔ)言處理和計(jì)算機(jī)視覺(jué)等領(lǐng)域的神經(jīng)網(wǎng)絡(luò)架構(gòu)。它在序列數(shù)據(jù)處理中表現(xiàn)出色,也可以用于圖像生成和處理任務(wù)。
codeformer,計(jì)算機(jī)視覺(jué),C++,python,c++,python,CodeFormer,人臉修復(fù),人臉祛除巴賽克,深度學(xué)習(xí),人臉超分

在監(jiān)控、安全和隱私保護(hù)領(lǐng)域,人臉圖像通常會(huì)受到多種因素的影響,其中包括光照、像素限制、聚焦問(wèn)題和人體運(yùn)動(dòng)等。這些因素可能導(dǎo)致圖像模糊、變形或者包含大量的噪聲。在這種情況下,嘗試恢復(fù)清晰的原始人臉圖像是一個(gè)極具挑戰(zhàn)性的任務(wù)。
盲人臉復(fù)原是一個(gè)不適定問(wèn)題(ill-posed problem),這意味著存在多個(gè)可能的解決方案,而且從有限的觀察數(shù)據(jù)中無(wú)法唯一確定真實(shí)的原始圖像。因此,在這個(gè)領(lǐng)域中,通常需要依賴(lài)先進(jìn)的計(jì)算機(jī)視覺(jué)和圖像處理技術(shù),以及深度學(xué)習(xí)模型,來(lái)嘗試改善模糊或受損圖像的質(zhì)量。
一些方法和技術(shù)可以用于處理盲人臉復(fù)原問(wèn)題,包括但不限于:
深度學(xué)習(xí)模型: 使用卷積神經(jīng)網(wǎng)絡(luò)(CNN)和生成對(duì)抗網(wǎng)絡(luò)(GAN)等深度學(xué)習(xí)模型,可以嘗試從模糊或變形的人臉圖像中恢復(fù)原始細(xì)節(jié)。
超分辨率技術(shù): 超分辨率方法旨在從低分辨率圖像中重建高分辨率圖像,這也可以用于人臉圖像復(fù)原。
先驗(yàn)知識(shí): 利用先驗(yàn)知識(shí),如人臉結(jié)構(gòu)、光照模型等,可以幫助提高復(fù)原的準(zhǔn)確性。
多模態(tài)融合: 結(jié)合不同傳感器和信息源的數(shù)據(jù),可以提高復(fù)原的魯棒性。
然而,即使使用這些技術(shù),由于問(wèn)題的不適定性,完全恢復(fù)清晰的原始人臉圖像仍然可能是一項(xiàng)極具挑戰(zhàn)性的任務(wù),特別是在極端條件下。在實(shí)際應(yīng)用中,可能需要權(quán)衡圖像質(zhì)量和可用的信息,以達(dá)到最佳的結(jié)果。

2.算法效果

在官方公布修復(fù)的人臉效果里面,可以看到算法在各種輸入的修復(fù)效果:
老照片修復(fù)
codeformer,計(jì)算機(jī)視覺(jué),C++,python,c++,python,CodeFormer,人臉修復(fù),人臉祛除巴賽克,深度學(xué)習(xí),人臉超分
人臉修復(fù)
codeformer,計(jì)算機(jī)視覺(jué),C++,python,c++,python,CodeFormer,人臉修復(fù),人臉祛除巴賽克,深度學(xué)習(xí),人臉超分
黑白人臉圖像增強(qiáng)修復(fù)
codeformer,計(jì)算機(jī)視覺(jué),C++,python,c++,python,CodeFormer,人臉修復(fù),人臉祛除巴賽克,深度學(xué)習(xí),人臉超分
人臉恢復(fù)
codeformer,計(jì)算機(jī)視覺(jué),C++,python,c++,python,CodeFormer,人臉修復(fù),人臉祛除巴賽克,深度學(xué)習(xí),人臉超分

二、模型部署

如果想用C++進(jìn)行模型推理部署,首先要把模型轉(zhuǎn)換成onnx,轉(zhuǎn)成onnx就可以使用onnxruntime c++庫(kù)進(jìn)行部署,或者使用OpenCV的DNN也可以,轉(zhuǎn)成onnx后,還可以再轉(zhuǎn)成ncnn模型使用ncnn進(jìn)行模型部署。原模型可以從官方開(kāi)源界面可以下載。
模型推理這塊有兩種做法,一是不用判斷有沒(méi)有人臉,直接對(duì)全圖進(jìn)行超分,但這種方法好像對(duì)本來(lái)是清晰的圖像會(huì)出現(xiàn)bug,就是生成一些無(wú)法理解的處理。

1. C++使用onnxruntime部署模型

#include "CodeFormer.h"

CodeFormer::CodeFormer(std::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系統(tǒng)就這么寫(xiě)
	ort_session = new Ort::Session(env, widestr.c_str(), sessionOptions);   ///如果在windows系統(tǒng)就這么寫(xiě)
	///ort_session = new Session(env, model_path.c_str(), sessionOptions);  ///如果在linux系統(tǒng),就這么寫(xiě)

	size_t numInputNodes = ort_session->GetInputCount();
	size_t numOutputNodes = ort_session->GetOutputCount();
	Ort::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(cv::Mat &srcimg)
{
	cv::Mat dstimg;
	cv::cvtColor(srcimg, dstimg, cv::COLOR_BGR2RGB);
	resize(dstimg, dstimg, cv::Size(this->inpWidth, this->inpHeight), cv::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++;
			}
		}
	}
}

cv::Mat CodeFormer::detect(cv::Mat &srcimg)
{
	int im_h = srcimg.rows;
	int im_w = srcimg.cols;
	this->preprocess(srcimg);
	std::array<int64_t, 4> input_shape_{ 1, 3, this->inpHeight, this->inpWidth };
	std::vector<int64_t> input2_shape_ = { 1 };

	auto allocator_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
	std::vector<Ort::Value> ort_inputs;
	ort_inputs.push_back(Ort::Value::CreateTensor<float>(allocator_info, input_image_.data(), input_image_.size(), input_shape_.data(), input_shape_.size()));
	ort_inputs.push_back(Ort::Value::CreateTensor<double>(allocator_info, input2_tensor.data(), input2_tensor.size(), input2_shape_.data(), input2_shape_.size()));
	std::vector<Ort::Value> ort_outputs = ort_session->Run(Ort::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>();
	//cv::Mat mask(outHeight, outWidth, CV_32FC3, pred); /經(jīng)過(guò)試驗(yàn),直接這樣賦值,是不行的
	const unsigned int channel_step = outHeight * outWidth;
	std::vector<cv::Mat> channel_mats;
	cv::Mat rmat(outHeight, outWidth, CV_32FC1, pred); // R
	cv::Mat gmat(outHeight, outWidth, CV_32FC1, pred + channel_step); // G
	cv::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);
	cv::Mat mask;
	merge(channel_mats, mask); // CV_32FC3 allocated

	///不用for循環(huán)遍歷cv::Mat里的每個(gè)像素值,實(shí)現(xiàn)numpy.clip函數(shù)
	mask.setTo(this->min_max[0], mask < this->min_max[0]);
	mask.setTo(this->min_max[1], mask > this->min_max[1]);   也可以用threshold函數(shù),閾值類(lèi)型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, cv::COLOR_BGR2RGB);
	return mask;
}


void CodeFormer::detect_video(const std::string& video_path,const std::string& output_path, unsigned int writer_fps)
{
	cv::VideoCapture video_capture(video_path);

	if (!video_capture.isOpened())
	{
		std::cout << "Can not open video: " << video_path << "\n";
		return;
	}

	cv::Size S = cv::Size((int)video_capture.get(cv::CAP_PROP_FRAME_WIDTH),
		(int)video_capture.get(cv::CAP_PROP_FRAME_HEIGHT));

	cv::VideoWriter output_video(output_path, cv::VideoWriter::fourcc('m', 'p', '4', 'v'),
		30.0, S);
	
	if (!output_video.isOpened())
	{
		std::cout << "Can not open writer: " << output_path << "\n";
		return;
	}

	cv::Mat cv_mat;
	while (video_capture.read(cv_mat))
	{
		cv::Mat cv_dst = detect(cv_mat);

		output_video << cv_dst;
	}
	video_capture.release();
	output_video.release();
}

先試試官方給的樣本的效果:
codeformer,計(jì)算機(jī)視覺(jué),C++,python,c++,python,CodeFormer,人臉修復(fù),人臉祛除巴賽克,深度學(xué)習(xí),人臉超分
薄馬賽克的超分效果:
codeformer,計(jì)算機(jī)視覺(jué),C++,python,c++,python,CodeFormer,人臉修復(fù),人臉祛除巴賽克,深度學(xué)習(xí),人臉超分
codeformer,計(jì)算機(jī)視覺(jué),C++,python,c++,python,CodeFormer,人臉修復(fù),人臉祛除巴賽克,深度學(xué)習(xí),人臉超分
厚馬賽克的超分效果不是很好,就是有點(diǎn)貼臉的感覺(jué):
codeformer,計(jì)算機(jī)視覺(jué),C++,python,c++,python,CodeFormer,人臉修復(fù),人臉祛除巴賽克,深度學(xué)習(xí),人臉超分
如果是已經(jīng)是清晰的圖像,超分之后不是很理想,基本上是不能用的,onnx這個(gè)效果只能優(yōu)化人臉:

codeformer,計(jì)算機(jī)視覺(jué),C++,python,c++,python,CodeFormer,人臉修復(fù),人臉祛除巴賽克,深度學(xué)習(xí),人臉超分
codeformer,計(jì)算機(jī)視覺(jué),C++,python,c++,python,CodeFormer,人臉修復(fù),人臉祛除巴賽克,深度學(xué)習(xí),人臉超分文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-774213.html

2.onnx模型python推理

import os
import cv2
import argparse
import glob
import torch
import torch.onnx
from torchvision.transforms.functional import normalize
from basicsr.utils import imwrite, img2tensor, tensor2img
from basicsr.utils.download_util import load_file_from_url
from basicsr.utils.misc import gpu_is_available, get_device
from facelib.utils.face_restoration_helper import FaceRestoreHelper
from facelib.utils.misc import is_gray
import onnxruntime as ort

from basicsr.utils.registry import ARCH_REGISTRY

pretrain_model_url = {
    'restoration': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/codeformer.pth',
}

if __name__ == '__main__':
    # device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    device = get_device()
    parser = argparse.ArgumentParser()

    parser.add_argument('-i', '--input_path', type=str, default='./inputs/whole_imgs', 
            help='Input image, video or folder. Default: inputs/whole_imgs')
    parser.add_argument('-o', '--output_path', type=str, default=None, 
            help='Output folder. Default: results/<input_name>_<w>')
    parser.add_argument('-w', '--fidelity_weight', type=float, default=0.5, 
            help='Balance the quality and fidelity. Default: 0.5')
    parser.add_argument('-s', '--upscale', type=int, default=2, 
            help='The final upsampling scale of the image. Default: 2')
    parser.add_argument('--has_aligned', action='store_true', help='Input are cropped and aligned faces. Default: False')
    parser.add_argument('--only_center_face', action='store_true', help='Only restore the center face. Default: False')
    parser.add_argument('--draw_box', action='store_true', help='Draw the bounding box for the detected faces. Default: False')
    # large det_model: 'YOLOv5l', 'retinaface_resnet50'
    # small det_model: 'YOLOv5n', 'retinaface_mobile0.25'
    parser.add_argument('--detection_model', type=str, default='retinaface_resnet50', 
            help='Face detector. Optional: retinaface_resnet50, retinaface_mobile0.25, YOLOv5l, YOLOv5n, dlib. \
                Default: retinaface_resnet50')
    parser.add_argument('--bg_upsampler', type=str, default='None', help='Background upsampler. Optional: realesrgan')
    parser.add_argument('--face_upsample', action='store_true', help='Face upsampler after enhancement. Default: False')
    parser.add_argument('--bg_tile', type=int, default=400, help='Tile size for background sampler. Default: 400')
    parser.add_argument('--suffix', type=str, default=None, help='Suffix of the restored faces. Default: None')
    parser.add_argument('--save_video_fps', type=float, default=None, help='Frame rate for saving video. Default: None')

    args = parser.parse_args()

    # ------------------------ input & output ------------------------
    w = args.fidelity_weight
    input_video = False
    if args.input_path.endswith(('jpg', 'jpeg', 'png', 'JPG', 'JPEG', 'PNG')): # input single img path
        input_img_list = [args.input_path]
        result_root = f'results/test_img_{w}'
    # elif args.input_path.endswith(('mp4', 'mov', 'avi', 'MP4', 'MOV', 'AVI')): # input video path
    #     from basicsr.utils.video_util import VideoReader, VideoWriter
    #     input_img_list = []
    #     vidreader = VideoReader(args.input_path)
    #     image = vidreader.get_frame()
    #     while image is not None:
    #         input_img_list.append(image)
    #         image = vidreader.get_frame()
    #     audio = vidreader.get_audio()
    #     fps = vidreader.get_fps() if args.save_video_fps is None else args.save_video_fps   
    #     video_name = os.path.basename(args.input_path)[:-4]
    #     result_root = f'results/{video_name}_{w}'
    #     input_video = True
    #     vidreader.close()
    # else: # input img folder
    #     if args.input_path.endswith('/'):  # solve when path ends with /
    #         args.input_path = args.input_path[:-1]
    #     # scan all the jpg and png images
    #     input_img_list = sorted(glob.glob(os.path.join(args.input_path, '*.[jpJP][pnPN]*[gG]')))
    #     result_root = f'results/{os.path.basename(args.input_path)}_{w}'
    else:
        raise ValueError("wtf???")

    if not args.output_path is None: # set output path
        result_root = args.output_path

    test_img_num = len(input_img_list)
    if test_img_num == 0:
        raise FileNotFoundError('No input image/video is found...\n' 
            '\tNote that --input_path for video should end with .mp4|.mov|.avi')

    # # ------------------ set up background upsampler ------------------
    # if args.bg_upsampler == 'realesrgan':
    #     bg_upsampler = set_realesrgan()
    # else:
    #     bg_upsampler = None

    # # ------------------ set up face upsampler ------------------
    # if args.face_upsample:
    #     if bg_upsampler is not None:
    #         face_upsampler = bg_upsampler
    #     else:
    #         face_upsampler = set_realesrgan()
    # else:
    #     face_upsampler = None

    # ------------------ set up CodeFormer restorer -------------------
    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 = load_file_from_url(url=pretrain_model_url['restoration'], 
                                    model_dir='weights/CodeFormer', progress=True, file_name=None)
    checkpoint = torch.load(ckpt_path)['params_ema']
    net.load_state_dict(checkpoint)
    net.eval()

    # # ------------------ set up FaceRestoreHelper -------------------
    # # large det_model: 'YOLOv5l', 'retinaface_resnet50'
    # # small det_model: 'YOLOv5n', 'retinaface_mobile0.25'
    # if not args.has_aligned: 
    #     print(f'Face detection model: {args.detection_model}')
    # # if bg_upsampler is not None: 
    # #     print(f'Background upsampling: True, Face upsampling: {args.face_upsample}')
    # # else:
    # #     print(f'Background upsampling: False, Face upsampling: {args.face_upsample}')
    # else:
    #     raise ValueError("wtf???")

    face_helper = FaceRestoreHelper(
        args.upscale,
        face_size=512,
        crop_ratio=(1, 1),
        # det_model = args.detection_model,
        # save_ext='png',
        # use_parse=True,
        # device=device
    )

    # -------------------- start to processing ---------------------
    for i, img_path in enumerate(input_img_list):
        # # clean all the intermediate results to process the next image
        # face_helper.clean_all()
        
        if isinstance(img_path, str):
            img_name = os.path.basename(img_path)
            basename, ext = os.path.splitext(img_name)
            print(f'[{i+1}/{test_img_num}] Processing: {img_name}')
            img = cv2.imread(img_path, cv2.IMREAD_COLOR)
        # else: # for video processing
        #     basename = str(i).zfill(6)
        #     img_name = f'{video_name}_{basename}' if input_video else basename
        #     print(f'[{i+1}/{test_img_num}] Processing: {img_name}')
        #     img = img_path

        if args.has_aligned: 
            # the input faces are already cropped and aligned
            img = cv2.resize(img, (512, 512), interpolation=cv2.INTER_LINEAR)
            # face_helper.is_gray = is_gray(img, threshold=10)
            # if face_helper.is_gray:
            #     print('Grayscale input: True')
            face_helper.cropped_faces = [img]
        # else:
        #     face_helper.read_image(img)
        #     # get face landmarks for each face
        #     num_det_faces = face_helper.get_face_landmarks_5(
        #         only_center_face=args.only_center_face, resize=640, eye_dist_threshold=5)
        #     print(f'\tdetect {num_det_faces} faces')
        #     # align and warp each face
        #     face_helper.align_warp_face()
        else:
            raise ValueError("wtf???")

        # face restoration for each cropped face
        for idx, cropped_face in enumerate(face_helper.cropped_faces):
            # prepare data
            cropped_face_t = img2tensor(cropped_face / 255., bgr2rgb=True, float32=True)
            normalize(cropped_face_t, (0.5, 0.5, 0.5), (0.5, 0.5, 0.5), inplace=True)
            cropped_face_t = cropped_face_t.unsqueeze(0).to(device)

            try:
                with torch.no_grad():
                    # output = net(cropped_face_t, w=w, adain=True)[0]
                    # output = net(cropped_face_t)[0]
                    output = net(cropped_face_t, w)[0]
                    restored_face = tensor2img(output, rgb2bgr=True, min_max=(-1, 1))
                del output
                # torch.cuda.empty_cache()
            except Exception as error:
                print(f'\tFailed inference for CodeFormer: {error}')
                restored_face = tensor2img(cropped_face_t, rgb2bgr=True, min_max=(-1, 1))
            
            # now, export the "net" codeformer to onnx
            print("Exporting CodeFormer to ONNX...")
            torch.onnx.export(net,
                # (cropped_face_t,),
                (cropped_face_t,w),
                "codeformer.onnx", 
                # verbose=True,
                export_params=True,
                opset_version=11,
                do_constant_folding=True,
                input_names = ['x','w'],
                output_names = ['y'],
            )

            # now, try to load the onnx model and run it
            print("Loading CodeFormer ONNX...")
            ort_session = ort.InferenceSession("codeformer.onnx", providers=['CPUExecutionProvider'])
            print("Running CodeFormer ONNX...")
            ort_inputs = {
                ort_session.get_inputs()[0].name: cropped_face_t.cpu().numpy(),
                ort_session.get_inputs()[1].name: torch.tensor(w).double().cpu().numpy(),
            }
            ort_outs = ort_session.run(None, ort_inputs)
            restored_face_onnx = tensor2img(torch.from_numpy(ort_outs[0]), rgb2bgr=True, min_max=(-1, 1))
            restored_face_onnx = restored_face_onnx.astype('uint8')

            restored_face = restored_face.astype('uint8')

            print("Comparing CodeFormer outputs...")
            # see how similar the outputs are: flatten and then compute all the differences
            diff = (restored_face_onnx.astype('float32') - restored_face.astype('float32')).flatten()
            # calculate min, max, mean, and std
            min_diff = diff.min()
            max_diff = diff.max()
            mean_diff = diff.mean()
            std_diff = diff.std()
            print(f"Min diff: {min_diff}, Max diff: {max_diff}, Mean diff: {mean_diff}, Std diff: {std_diff}")

            # face_helper.add_restored_face(restored_face, cropped_face)
            face_helper.add_restored_face(restored_face_onnx, cropped_face)

        # # paste_back
        # if not args.has_aligned:
        #     # upsample the background
        #     if bg_upsampler is not None:
        #         # Now only support RealESRGAN for upsampling background
        #         bg_img = bg_upsampler.enhance(img, outscale=args.upscale)[0]
        #     else:
        #         bg_img = None
        #     face_helper.get_inverse_affine(None)
        #     # paste each restored face to the input image
        #     if args.face_upsample and face_upsampler is not None: 
        #         restored_img = face_helper.paste_faces_to_input_image(upsample_img=bg_img, draw_box=args.draw_box, face_upsampler=face_upsampler)
        #     else:
        #         restored_img = face_helper.paste_faces_to_input_image(upsample_img=bg_img, draw_box=args.draw_box)

        # save faces
        for idx, (cropped_face, restored_face) in enumerate(zip(face_helper.cropped_faces, face_helper.restored_faces)):
            # save cropped face
            if not args.has_aligned: 
                save_crop_path = os.path.join(result_root, 'cropped_faces', f'{basename}_{idx:02d}.png')
                imwrite(cropped_face, save_crop_path)
            # save restored face
            if args.has_aligned:
                save_face_name = f'{basename}.png'
            else:
                save_face_name = f'{basename}_{idx:02d}.png'
            if args.suffix is not None:
                save_face_name = f'{save_face_name[:-4]}_{args.suffix}.png'
            save_restore_path = os.path.join(result_root, 'restored_faces', save_face_name)
            imwrite(restored_face, save_restore_path)

        # # save restored img
        # if not args.has_aligned and restored_img is not None:
        #     if args.suffix is not None:
        #         basename = f'{basename}_{args.suffix}'
        #     save_restore_path = os.path.join(result_root, 'final_results', f'{basename}.png')
        #     imwrite(restored_img, save_restore_path)

    # # save enhanced video
    # if input_video:
    #     print('Video Saving...')
    #     # load images
    #     video_frames = []
    #     img_list = sorted(glob.glob(os.path.join(result_root, 'final_results', '*.[jp][pn]g')))
    #     for img_path in img_list:
    #         img = cv2.imread(img_path)
    #         video_frames.append(img)
    #     # write images to video
    #     height, width = video_frames[0].shape[:2]
    #     if args.suffix is not None:
    #         video_name = f'{video_name}_{args.suffix}.png'
    #     save_restore_path = os.path.join(result_root, f'{video_name}.mp4')
    #     vidwriter = VideoWriter(save_restore_path, height, width, fps, audio)
         
    #     for f in video_frames:
    #         vidwriter.write_frame(f)
    #     vidwriter.close()

    print(f'\nAll results are saved in {result_root}')

到了這里,關(guān)于人臉修復(fù)祛馬賽克算法CodeFormer——C++與Python模型部署的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • AI繪圖實(shí)戰(zhàn)(五):放大并修復(fù)老照片、馬賽克照片、身份證件照 | Stable Diffusion成為設(shè)計(jì)師生產(chǎn)力工具

    AI繪圖實(shí)戰(zhàn)(五):放大并修復(fù)老照片、馬賽克照片、身份證件照 | Stable Diffusion成為設(shè)計(jì)師生產(chǎn)力工具

    S:你安裝stable diffusion就是為了看小姐姐么? I :當(dāng)然不是,當(dāng)然是為了公司的發(fā)展謀出路~~ 預(yù)先學(xué)習(xí) : 安裝及其問(wèn)題解決參考:《Windows安裝Stable Diffusion WebUI及問(wèn)題解決記錄》; 運(yùn)行使用時(shí)問(wèn)題《Windows使用Stable Diffusion時(shí)遇到的各種問(wèn)題整理》; 模型運(yùn)用及參數(shù)《Stable D

    2024年02月01日
    瀏覽(35)
  • 馬賽克處理

    馬賽克處理

    去取馬賽克的網(wǎng)址: Redact ? Photo - Free And Private Image Redaction In The Browser https://redact.photo/ REDACT.PHOTO ?(照片馬賽克處理在線(xiàn)工具)簡(jiǎn)介 REDACT.PHOTO是一個(gè)照片馬賽克處理在線(xiàn)工具,能夠幫助我們非常方便的為照片搭上馬賽克,并且完全免費(fèi),而且該在線(xiàn)工具采用的馬賽克是隨機(jī)

    2024年02月05日
    瀏覽(26)
  • 圖像處理: 馬賽克藝術(shù)

    圖像處理: 馬賽克藝術(shù)

    ?馬賽克 ? ? ??藝術(shù)中的一種表面裝飾,由緊密排列的、通常顏色各異的小塊材料(如石頭、礦物、玻璃、

    2024年02月07日
    瀏覽(20)
  • 神器 | 教你去除視頻馬賽克

    神器 | 教你去除視頻馬賽克

    大家有時(shí)候看一些視頻教材或者圖片的時(shí)候,有些比較隱私的會(huì)做打碼處理,其實(shí)去馬賽克這個(gè)事,一直都是一個(gè)令大家比較頭疼的問(wèn)題。 相信很多小伙伴也會(huì)發(fā)現(xiàn),無(wú)論是圖片還是視頻,都不可能完美得去除掉,至少目前可以這么說(shuō)。 今天小呆分享的這款可以一定程度上

    2024年02月09日
    瀏覽(28)
  • Pooling與馬賽克的秘密

    Pooling與馬賽克的秘密

    ??說(shuō)到Pooling,相信學(xué)習(xí)過(guò)CNN的朋友們都不會(huì)感到陌生。Pooling在中文當(dāng)中的意思是“池化”,在神經(jīng)網(wǎng)絡(luò)當(dāng)中非常常見(jiàn),通常用的比較多的一種是Max Pooling,具體操作如下圖: ?? 結(jié)合圖像理解,相信你也會(huì)大概明白其中的本意。不過(guò)Pooling并不是只可以選取2x2的窗口大小,

    2024年02月05日
    瀏覽(29)
  • ps導(dǎo)出bmp|jpg馬賽克

    ps導(dǎo)入圖片-濾鏡-像素化-馬賽克 圖像-模式-索引顏色-確定合并 文件-存儲(chǔ)為-導(dǎo)出bmp格式 備注: 封面來(lái)源于免費(fèi)素材網(wǎng)2.8 million+ Stunning Free Images to Use Anywhere - Pixabay - Pixabay ai馬賽克網(wǎng)站PixelMe : Convert your photo into pixelart. (pixel-me.tokyo))

    2024年02月12日
    瀏覽(22)
  • FFmpeg進(jìn)階-給視頻添加馬賽克效果

    FFmpeg進(jìn)階-給視頻添加馬賽克效果

    很多時(shí)候?yàn)榱穗[藏視頻中的敏感信息如人臉、身份證號(hào)、車(chē)牌號(hào)等,我們會(huì)采用馬賽克算法對(duì)視頻幀中的一部分內(nèi)容進(jìn)行處理。這里介紹一下如何采用FFmpeg實(shí)現(xiàn)馬賽克效果。 馬賽克效果算法的原理如下: 1.分塊處理:首先將圖像劃分為多個(gè)小塊或區(qū)域 2.像素替換:對(duì)于每個(gè)小塊,

    2024年02月21日
    瀏覽(29)
  • ArcGIS三體陰影(影像三維)顯示馬賽克?

    ArcGIS三體陰影(影像三維)顯示馬賽克?

    我們經(jīng)常基于ArcGIS通過(guò)DEM來(lái)做山體陰影 但是有時(shí)候你一放大就會(huì)出現(xiàn)很強(qiáng)的馬賽克的效果 還有我們?cè)诶肁rcScene建三維場(chǎng)景 即使數(shù)據(jù)分辨率很高也會(huì)出現(xiàn)馬賽克效果 那怎么來(lái)解決這個(gè)問(wèn)題呢 讓我們的山體陰影顯示更加細(xì)膩 三維沒(méi)有馬賽克的效果呢? 右鍵圖層選擇如下顯示

    2024年02月01日
    瀏覽(25)
  • AI 繪畫(huà) | Stable Diffusion 去除照片馬賽克

    AI 繪畫(huà) | Stable Diffusion 去除照片馬賽克

    本篇文章教會(huì)你如何讓幾秒鐘去除圖片中的馬賽克,還是依托于Stable Diffusion WEB UI的強(qiáng)大擴(kuò)展插件ControlNet,快來(lái)學(xué)起來(lái)吧,如果有問(wèn)題請(qǐng)?jiān)谠u(píng)論區(qū)留言。 首先在圖生圖,選擇一個(gè)寫(xiě)實(shí)風(fēng)格的大模型(我這里選擇是majicMIX realistic 麥橘寫(xiě)實(shí)_v7.safetensors,你也可以到 https://www.libli

    2024年02月03日
    瀏覽(31)
  • 【Unity ShaderGraph】| 如何快速制作一個(gè) 馬賽克效果 實(shí)戰(zhàn)

    【Unity ShaderGraph】| 如何快速制作一個(gè) 馬賽克效果 實(shí)戰(zhàn)

    前言 本文將使用Unity 的ShaderGraph制作一個(gè) 馬賽克 的效果,可以直接拿到項(xiàng)目中使用。 對(duì)ShaderGraph還不了解的小伙伴可以參考這篇文章:【Unity ShaderGraph】| Shader Graph入門(mén)介紹 | 簡(jiǎn)介 | 配置環(huán)境 | 窗口介紹 | 簡(jiǎn)單案例 下面就開(kāi)始看一下具體的制作流程,然后自己動(dòng)手制作一個(gè)吧

    2024年02月08日
    瀏覽(22)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包