赞
踩
"""This script contains basic utilities for Deep3DFaceRecon_pytorch """ from __future__ import print_function import numpy as np import torch from PIL import Image import os import importlib import argparse from argparse import Namespace import torchvision #字符串转布尔 def str2bool(v): #isinstance用于检查给定对象是否是指定类的实例 if isinstance(v, bool): return v #lower() 的应用。这个方法返回原始字符串的小写版本 #然后检查它是否属于一个包含表示布尔值 "True" 的字符串的元组。 if v.lower() in ('yes', 'true', 't', 'y', '1'): return True elif v.lower() in ('no', 'false', 'f', 'n', '0'): return False else: #抛出自定义异常 raise argparse.ArgumentTypeError('Boolean value expected.') #**kwargs任意数量的关键字参数 def copyconf(default_opt, **kwargs): conf = Namespace(**vars(default_opt)) for key in kwargs: setattr(conf, key, kwargs[key]) return conf def genvalconf(train_opt, **kwargs): conf = Namespace(**vars(train_opt)) attr_dict = train_opt.__dict__ for key, value in attr_dict.items(): if 'val' in key and key.split('_')[0] in attr_dict: setattr(conf, key.split('_')[0], value) for key in kwargs: setattr(conf, key, kwargs[key]) return conf def find_class_in_module(target_cls_name, module): #这一行将目标类名中的所有下划线(_)替换为空字符串,并将整个字符串转换为小写。 target_cls_name = target_cls_name.replace('_', '').lower() #importlib 库的 import_module 函数来动态导入指定的模块。clslib 现在是一个指向该模块的引用 clslib = importlib.import_module(module) cls = None #这一行遍历模块 clslib 的字典属性(__dict__),这个字典包含了模块中定义的所有变量、函数和类。name 是字典中的键(名称),clsobj 是相应的值(对象)。 for name, clsobj in clslib.__dict__.items(): if name.lower() == target_cls_name: cls = clsobj assert cls is not None, "In %s, there should be a class whose name matches %s in lowercase without underscore(_)" % (module, target_cls_name) return cls def tensor2im(input_image, imtype=np.uint8): #这一行检查输入的图像是否为 NumPy 数组。如果不是 NumPy 数组。 if not isinstance(input_image, np.ndarray): #如果输入图像是一个 PyTorch 张量, if isinstance(input_image, torch.Tensor): # get the data from a variable image_tensor = input_image.data else: return input_image #将 image_tensor 裁剪到 [0, 1] 范围,将其从 GPU(如果在 GPU 上)移动到 CPU,将其转换为 float 类型,然后将其从张量转换为 NumPy 数组,赋值给 image_numpy。 image_numpy = image_tensor.clamp(0.0, 1.0).cpu().float().numpy() #如果图像是灰度图,使用 np.tile() 函数将其复制成一个 3 通道的 RGB 图像 if image_numpy.shape[0] == 1: # grayscale to RGB image_numpy = np.tile(image_numpy, (3, 1, 1)) #使用 np.transpose() 函数将图像数组的维度顺序从 (通道, 高度, 宽度) 转换为 (高度, 宽度, 通道),并将像素值的范围从 [0, 1] 缩放到 [0, 255]。 image_numpy = np.transpose(image_numpy, (1, 2, 0)) * 255.0 else: # if it is a numpy array, do nothing image_numpy = input_image return image_numpy.astype(imtype) #计算并打印神经网络中所有参数梯度的平均绝对值 def diagnose_network(net, name='network'): mean = 0.0 count = 0 #遍历网络中的每个参数。 for param in net.parameters(): #如果当前参数的梯度非空,则计算梯度的绝对值,然后计算其平均值,并将其累加到 mean 变量中。 if param.grad is not None: mean += torch.mean(torch.abs(param.grad.data)) count += 1 if count > 0: mean = mean / count print(name) print(mean) #将输入的 NumPy 图像数组保存到磁盘上的指定路径 #aspect_ratio(宽高比,默认为 1.0,表示不改变宽高比)。 def save_image(image_numpy, image_path, aspect_ratio=1.0): #将 NumPy 图像数组转换为 PIL 图像对象:使用 PIL 提供的方法来操作和保存图像。 image_pil = Image.fromarray(image_numpy) h, w, _ = image_numpy.shape if aspect_ratio is None: pass #如果宽高比大于 1.0,将图像宽度乘以宽高比,然后调整图像大小 #使用 PIL 图像对象的 resize() 方法调整图像大小,新的宽度为 int(w * aspect_ratio)。 #这里使用 BICUBIC 插值方法进行调整。 elif aspect_ratio > 1.0: image_pil = image_pil.resize((h, int(w * aspect_ratio)), Image.BICUBIC) elif aspect_ratio < 1.0: image_pil = image_pil.resize((int(h / aspect_ratio), w), Image.BICUBIC) image_pil.save(image_path) #用于打印输入 NumPy 数组的一些统计信息 def print_numpy(x, val=True, shp=False): x = x.astype(np.float64) if shp: print('shape,', x.shape) if val: x = x.flatten() print('mean = %3.3f, min = %3.3f, max = %3.3f, median = %3.3f, std=%3.3f' % ( np.mean(x), np.min(x), np.max(x), np.median(x), np.std(x))) #用于创建一个或多个不存在的空目录。让我们逐句解释这段代码: def mkdirs(paths): if isinstance(paths, list) and not isinstance(paths, str): for path in paths: mkdir(path) else: mkdir(paths) #其目的是在指定路径不存在时创建一个空目录 def mkdir(path): #检查传入的 path 是否已经存在 if not os.path.exists(path): #创建目录 os.makedirs(path) #调整张量中每个图像的大小,并返回一个调整后的张量。 def correct_resize_label(t, size): device = t.device#获取输入张量 t 的设备(CPU 或 GPU) t = t.detach().cpu() resized = [] for i in range(t.size(0)): one_t = t[i, :1] one_np = np.transpose(one_t.numpy().astype(np.uint8), (1, 2, 0)) one_np = one_np[:, :, 0] one_image = Image.fromarray(one_np).resize(size, Image.NEAREST) #将调整大小后的 PIL.Image 对象转换回 NumPy 数组,然后转换为 Torch 张量,并将数据类型设置为 long resized_t = torch.from_numpy(np.array(one_image)).long() resized.append(resized_t) return torch.stack(resized, dim=0).to(device) #它用于将输入的 PyTorch 张量(图像)调整到指定的尺寸 def correct_resize(t, size, mode=Image.BICUBIC): device = t.device t = t.detach().cpu() resized = [] for i in range(t.size(0)): one_t = t[i:i + 1] one_image = Image.fromarray(tensor2im(one_t)).resize(size, Image.BICUBIC) #将张量的值范围从 [0, 1] 调整为 [-1, 1] resized_t = torchvision.transforms.functional.to_tensor(one_image) * 2 - 1.0 resized.append(resized_t) return torch.stack(resized, dim=0).to(device) #用于在图像上绘制人脸关键点,landmark(关键点坐标)、step(用于定义关键点绘制时的像素步长,默认为 2)。 def draw_landmarks(img, landmark, color='r', step=2): if color =='r': c = np.array([255., 0, 0]) else: c = np.array([0, 0, 255.]) _, H, W, _ = img.shape img, landmark = img.copy(), landmark.copy() #landmark[..., 1] 选取了所有关键点的 y 坐标 landmark[..., 1] = H - 1 - landmark[..., 1] #将关键点坐标四舍五入并转换为 int32 类型。 landmark = np.round(landmark).astype(np.int32) #遍历所有关键点。 for i in range(landmark.shape[1]): x, y = landmark[:, i, 0], landmark[:, i, 1] #遍历关键点周围的像素,从 -step 到 step(不包括 step)。 for j in range(-step, step): #遍历关键点周围的像素 for k in range(-step, step): #计算新的 x 坐标 u,将其限制在图像宽度范围内 u = np.clip(x + j, 0, W - 1) #计算新的 y 坐标 v,将其限制在图像高度范围内。 v = np.clip(y + k, 0, H - 1) for m in range(landmark.shape[0]): img[m, v[m], u[m]] = c return img
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。