magic123 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- activation.py +21 -0
- all_metrics/metric_utils.py +459 -0
- dnnultis/__init__.py +1 -0
- dnnultis/log/__init__.py +2 -0
- dnnultis/log/logger.py +86 -0
- dnnultis/log/wandb.py +84 -0
- dpt.py +924 -0
- encoding.py +89 -0
- freqencoder/__init__.py +1 -0
- freqencoder/backend.py +42 -0
- freqencoder/freq.py +77 -0
- freqencoder/setup.py +25 -0
- freqencoder/src/bindings.cpp +8 -0
- freqencoder/src/freqencoder.cu +129 -0
- freqencoder/src/freqencoder.h +10 -0
- gradio_app.py +246 -0
- gridencoder/__init__.py +1 -0
- gridencoder/backend.py +40 -0
- gridencoder/grid.py +206 -0
- gridencoder/setup.py +24 -0
- gridencoder/src/bindings.cpp +10 -0
- gridencoder/src/gridencoder.cu +713 -0
- gridencoder/src/gridencoder.h +18 -0
- guidance/clip_utils.py +52 -0
- guidance/if_utils.py +207 -0
- guidance/sd_utils.py +707 -0
- guidance/shape_utils.py +81 -0
- guidance/zero123_utils.py +332 -0
- ldm/extras.py +77 -0
- ldm/guidance.py +96 -0
- ldm/lr_scheduler.py +98 -0
- ldm/models/autoencoder.py +443 -0
- ldm/models/diffusion/__init__.py +0 -0
- ldm/models/diffusion/classifier.py +267 -0
- ldm/models/diffusion/ddim.py +328 -0
- ldm/models/diffusion/ddpm.py +1994 -0
- ldm/models/diffusion/plms.py +259 -0
- ldm/models/diffusion/sampling_util.py +50 -0
- ldm/modules/attention.py +266 -0
- ldm/modules/diffusionmodules/__init__.py +0 -0
- ldm/modules/diffusionmodules/model.py +835 -0
- ldm/modules/diffusionmodules/openaimodel.py +996 -0
- ldm/modules/diffusionmodules/util.py +267 -0
- ldm/modules/distributions/__init__.py +0 -0
- ldm/modules/distributions/distributions.py +92 -0
- ldm/modules/ema.py +76 -0
- ldm/modules/encoders/__init__.py +0 -0
- ldm/modules/encoders/modules.py +550 -0
- ldm/modules/evaluate/adm_evaluator.py +676 -0
- ldm/modules/evaluate/evaluate_perceptualsim.py +630 -0
- ldm/modules/evaluate/frechet_video_distance.py +147 -0
- ldm/modules/evaluate/ssim.py +124 -0
- ldm/modules/evaluate/torch_frechet_video_distance.py +294 -0
- ldm/modules/image_degradation/__init__.py +2 -0
- ldm/modules/image_degradation/bsrgan.py +730 -0
- ldm/modules/image_degradation/bsrgan_light.py +650 -0
- ldm/modules/image_degradation/utils_image.py +916 -0
- ldm/modules/losses/__init__.py +1 -0
- ldm/modules/losses/contperceptual.py +111 -0
- ldm/modules/losses/vqperceptual.py +167 -0
- ldm/modules/x_transformer.py +641 -0
- ldm/thirdp/psp/helpers.py +121 -0
- ldm/thirdp/psp/id_loss.py +23 -0
- ldm/thirdp/psp/model_irse.py +86 -0
- ldm/util.py +227 -0
- magic123-0.1.0.dist-info/METADATA +426 -0
- magic123-0.1.0.dist-info/RECORD +171 -0
- magic123-0.1.0.dist-info/WHEEL +5 -0
- magic123-0.1.0.dist-info/licenses/LICENSE +201 -0
- magic123-0.1.0.dist-info/top_level.txt +22 -0
- main.py +630 -0
- meshutils.py +117 -0
- midas/__init__.py +1 -0
- midas/backbones/beit.py +196 -0
- midas/backbones/levit.py +106 -0
- midas/backbones/next_vit.py +39 -0
- midas/backbones/swin.py +13 -0
- midas/backbones/swin2.py +34 -0
- midas/backbones/swin_common.py +52 -0
- midas/backbones/utils.py +249 -0
- midas/backbones/vit.py +221 -0
- midas/base_model.py +16 -0
- midas/blocks.py +439 -0
- midas/dpt_depth.py +166 -0
- midas/midas_net.py +76 -0
- midas/midas_net_custom.py +128 -0
- midas/model_loader.py +242 -0
- midas/transforms.py +234 -0
- nerf/clip.py +127 -0
- nerf/gui.py +485 -0
- nerf/network.py +238 -0
- nerf/network_grid.py +216 -0
- nerf/network_grid_taichi.py +161 -0
- nerf/network_grid_tcnn.py +178 -0
- nerf/provider.py +329 -0
- nerf/renderer.py +1575 -0
- nerf/utils.py +1599 -0
- optimizer.py +325 -0
- preprocess_image.py +279 -0
- raymarching/__init__.py +1 -0
- raymarching/backend.py +41 -0
- raymarching/raymarching.py +398 -0
- raymarching/setup.py +36 -0
- raymarching/src/bindings.cpp +20 -0
- raymarching/src/raymarching.cu +934 -0
- raymarching/src/raymarching.h +19 -0
- render/light.py +158 -0
- render/material.py +182 -0
- render/mesh.py +241 -0
- render/mlptexture.py +111 -0
- render/obj.py +179 -0
- render/regularizer.py +82 -0
- render/render.py +311 -0
- render/renderutils/__init__.py +11 -0
- render/renderutils/bsdf.py +151 -0
- render/renderutils/c_src/bsdf.cu +710 -0
- render/renderutils/c_src/bsdf.h +84 -0
- render/renderutils/c_src/common.cpp +74 -0
- render/renderutils/c_src/common.h +41 -0
- render/renderutils/c_src/cubemap.cu +350 -0
- render/renderutils/c_src/cubemap.h +38 -0
- render/renderutils/c_src/loss.cu +210 -0
- render/renderutils/c_src/loss.h +38 -0
- render/renderutils/c_src/mesh.cu +94 -0
- render/renderutils/c_src/mesh.h +23 -0
- render/renderutils/c_src/normal.cu +182 -0
- render/renderutils/c_src/normal.h +27 -0
- render/renderutils/c_src/tensor.h +92 -0
- render/renderutils/c_src/torch_bindings.cpp +1062 -0
- render/renderutils/c_src/vec3f.h +109 -0
- render/renderutils/c_src/vec4f.h +25 -0
- render/renderutils/loss.py +41 -0
- render/renderutils/ops.py +554 -0
- render/renderutils/tests/test_bsdf.py +296 -0
- render/renderutils/tests/test_cubemap.py +47 -0
- render/renderutils/tests/test_loss.py +61 -0
- render/renderutils/tests/test_mesh.py +90 -0
- render/renderutils/tests/test_perf.py +57 -0
- render/texture.py +186 -0
- render/util.py +465 -0
- setup_cuda_ext.py +129 -0
- shencoder/__init__.py +1 -0
- shencoder/backend.py +41 -0
- shencoder/setup.py +24 -0
- shencoder/sphere_harmonics.py +87 -0
- shencoder/src/bindings.cpp +8 -0
- shencoder/src/shencoder.cu +439 -0
- shencoder/src/shencoder.h +10 -0
- taichi_modules/__init__.py +5 -0
- taichi_modules/hash_encoder.py +305 -0
- taichi_modules/intersection.py +68 -0
- taichi_modules/ray_march.py +340 -0
- taichi_modules/utils.py +224 -0
- taichi_modules/volume_render_test.py +48 -0
- taichi_modules/volume_train.py +239 -0
- taming/lr_scheduler.py +34 -0
- taming/models/cond_transformer.py +352 -0
- taming/models/dummy_cond_stage.py +22 -0
- taming/models/vqgan.py +404 -0
- taming/modules/diffusionmodules/model.py +776 -0
- taming/modules/discriminator/model.py +67 -0
- taming/modules/losses/__init__.py +2 -0
- taming/modules/losses/lpips.py +123 -0
- taming/modules/losses/segmentation.py +22 -0
- taming/modules/losses/vqperceptual.py +136 -0
- taming/modules/misc/coord.py +31 -0
- taming/modules/transformer/mingpt.py +415 -0
- taming/modules/transformer/permuter.py +248 -0
- taming/modules/util.py +130 -0
- taming/modules/vqvae/quantize.py +445 -0
- taming/util.py +157 -0
activation.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
from torch.autograd import Function
|
|
3
|
+
from torch.cuda.amp import custom_bwd, custom_fwd
|
|
4
|
+
|
|
5
|
+
class _trunc_exp(Function):
|
|
6
|
+
@staticmethod
|
|
7
|
+
@custom_fwd(cast_inputs=torch.float)
|
|
8
|
+
def forward(ctx, x):
|
|
9
|
+
ctx.save_for_backward(x)
|
|
10
|
+
return torch.exp(x)
|
|
11
|
+
|
|
12
|
+
@staticmethod
|
|
13
|
+
@custom_bwd
|
|
14
|
+
def backward(ctx, g):
|
|
15
|
+
x = ctx.saved_tensors[0]
|
|
16
|
+
return g * torch.exp(x.clamp(max=15))
|
|
17
|
+
|
|
18
|
+
trunc_exp = _trunc_exp.apply
|
|
19
|
+
|
|
20
|
+
def biased_softplus(x, bias=0):
|
|
21
|
+
return torch.nn.functional.softplus(x - bias)
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
# * evaluate use laion/CLIP-ViT-H-14-laion2B-s32B-b79K
|
|
2
|
+
# best open source clip so far: laion/CLIP-ViT-bigG-14-laion2B-39B-b160k
|
|
3
|
+
# code adapted from NeuralLift-360
|
|
4
|
+
|
|
5
|
+
import torch
|
|
6
|
+
import torch.nn as nn
|
|
7
|
+
import os
|
|
8
|
+
import torchvision.transforms as T
|
|
9
|
+
import torchvision.transforms.functional as TF
|
|
10
|
+
import matplotlib.pyplot as plt
|
|
11
|
+
# import clip
|
|
12
|
+
from transformers import CLIPFeatureExtractor, CLIPModel, CLIPTokenizer, CLIPProcessor
|
|
13
|
+
from torchvision import transforms
|
|
14
|
+
import numpy as np
|
|
15
|
+
import torch.nn.functional as F
|
|
16
|
+
from tqdm import tqdm
|
|
17
|
+
import cv2
|
|
18
|
+
from PIL import Image
|
|
19
|
+
# import torchvision.transforms as transforms
|
|
20
|
+
import glob
|
|
21
|
+
from skimage.metrics import peak_signal_noise_ratio as compare_psnr
|
|
22
|
+
import lpips
|
|
23
|
+
from os.path import join as osp
|
|
24
|
+
import argparse
|
|
25
|
+
import pandas as pd
|
|
26
|
+
|
|
27
|
+
class CLIP(nn.Module):
|
|
28
|
+
|
|
29
|
+
def __init__(self,
|
|
30
|
+
device,
|
|
31
|
+
clip_name='laion/CLIP-ViT-bigG-14-laion2B-39B-b160k',
|
|
32
|
+
size=224): #'laion/CLIP-ViT-B-32-laion2B-s34B-b79K'):
|
|
33
|
+
super().__init__()
|
|
34
|
+
self.size = size
|
|
35
|
+
self.device = f"cuda:{device}"
|
|
36
|
+
|
|
37
|
+
clip_name = clip_name
|
|
38
|
+
|
|
39
|
+
self.feature_extractor = CLIPFeatureExtractor.from_pretrained(
|
|
40
|
+
clip_name)
|
|
41
|
+
self.clip_model = CLIPModel.from_pretrained(clip_name).to(self.device)
|
|
42
|
+
self.tokenizer = CLIPTokenizer.from_pretrained(
|
|
43
|
+
'openai/clip-vit-base-patch32')
|
|
44
|
+
|
|
45
|
+
self.normalize = transforms.Normalize(
|
|
46
|
+
mean=self.feature_extractor.image_mean,
|
|
47
|
+
std=self.feature_extractor.image_std)
|
|
48
|
+
|
|
49
|
+
self.resize = transforms.Resize(224)
|
|
50
|
+
self.to_tensor = transforms.ToTensor()
|
|
51
|
+
|
|
52
|
+
# image augmentation
|
|
53
|
+
self.aug = T.Compose([
|
|
54
|
+
T.Resize((224, 224)),
|
|
55
|
+
T.Normalize((0.48145466, 0.4578275, 0.40821073),
|
|
56
|
+
(0.26862954, 0.26130258, 0.27577711)),
|
|
57
|
+
])
|
|
58
|
+
|
|
59
|
+
# * recommend to use this function for evaluation
|
|
60
|
+
@torch.no_grad()
|
|
61
|
+
def score_gt(self, ref_img_path, novel_views):
|
|
62
|
+
# assert len(novel_views) == 100
|
|
63
|
+
clip_scores = []
|
|
64
|
+
for novel in novel_views:
|
|
65
|
+
clip_scores.append(self.score_from_path(ref_img_path, [novel]))
|
|
66
|
+
return np.mean(clip_scores)
|
|
67
|
+
|
|
68
|
+
# * recommend to use this function for evaluation
|
|
69
|
+
# def score_gt(self, ref_paths, novel_paths):
|
|
70
|
+
# clip_scores = []
|
|
71
|
+
# for img1_path, img2_path in zip(ref_paths, novel_paths):
|
|
72
|
+
# clip_scores.append(self.score_from_path(img1_path, img2_path))
|
|
73
|
+
|
|
74
|
+
# return np.mean(clip_scores)
|
|
75
|
+
|
|
76
|
+
def similarity(self, image1_features: torch.Tensor,
|
|
77
|
+
image2_features: torch.Tensor) -> float:
|
|
78
|
+
with torch.no_grad(), torch.cuda.amp.autocast():
|
|
79
|
+
y = image1_features.T.view(image1_features.T.shape[1],
|
|
80
|
+
image1_features.T.shape[0])
|
|
81
|
+
similarity = torch.matmul(y, image2_features.T)
|
|
82
|
+
# print(similarity)
|
|
83
|
+
return similarity[0][0].item()
|
|
84
|
+
|
|
85
|
+
def get_img_embeds(self, img):
|
|
86
|
+
if img.shape[0] == 4:
|
|
87
|
+
img = img[:3, :, :]
|
|
88
|
+
|
|
89
|
+
img = self.aug(img).to(self.device)
|
|
90
|
+
img = img.unsqueeze(0) # b,c,h,w
|
|
91
|
+
|
|
92
|
+
# plt.imshow(img.cpu().squeeze(0).permute(1, 2, 0).numpy())
|
|
93
|
+
# plt.show()
|
|
94
|
+
# print(img)
|
|
95
|
+
|
|
96
|
+
image_z = self.clip_model.get_image_features(img)
|
|
97
|
+
image_z = image_z / image_z.norm(dim=-1,
|
|
98
|
+
keepdim=True) # normalize features
|
|
99
|
+
return image_z
|
|
100
|
+
|
|
101
|
+
def score_from_feature(self, img1, img2):
|
|
102
|
+
img1_feature, img2_feature = self.get_img_embeds(
|
|
103
|
+
img1), self.get_img_embeds(img2)
|
|
104
|
+
# for debug
|
|
105
|
+
return self.similarity(img1_feature, img2_feature)
|
|
106
|
+
|
|
107
|
+
def read_img_list(self, img_list):
|
|
108
|
+
size = self.size
|
|
109
|
+
images = []
|
|
110
|
+
# white_background = np.ones((size, size, 3), dtype=np.uint8) * 255
|
|
111
|
+
|
|
112
|
+
for img_path in img_list:
|
|
113
|
+
img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
|
|
114
|
+
# print(img_path)
|
|
115
|
+
if img.shape[2] == 4: # Handle BGRA images
|
|
116
|
+
alpha = img[:, :, 3] # Extract alpha channel
|
|
117
|
+
img = cv2.cvtColor(img,cv2.COLOR_BGRA2RGB) # Convert BGRA to BGR
|
|
118
|
+
img[np.where(alpha == 0)] = [
|
|
119
|
+
255, 255, 255
|
|
120
|
+
] # Set transparent pixels to white
|
|
121
|
+
else: # Handle other image formats like JPG and PNG
|
|
122
|
+
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
|
123
|
+
|
|
124
|
+
img = cv2.resize(img, (size, size), interpolation=cv2.INTER_AREA)
|
|
125
|
+
|
|
126
|
+
# plt.imshow(img)
|
|
127
|
+
# plt.show()
|
|
128
|
+
|
|
129
|
+
images.append(img)
|
|
130
|
+
|
|
131
|
+
images = np.stack(images, axis=0)
|
|
132
|
+
# images[np.where(images == 0)] = 255 # Set black pixels to white
|
|
133
|
+
# images = np.where(images == 0, white_background, images) # Set transparent pixels to white
|
|
134
|
+
# images = images.astype(np.float32)
|
|
135
|
+
|
|
136
|
+
return images
|
|
137
|
+
|
|
138
|
+
def score_from_path(self, img1_path, img2_path):
|
|
139
|
+
img1, img2 = self.read_img_list(img1_path), self.read_img_list(img2_path)
|
|
140
|
+
img1 = np.squeeze(img1)
|
|
141
|
+
img2 = np.squeeze(img2)
|
|
142
|
+
# plt.imshow(img1)
|
|
143
|
+
# plt.show()
|
|
144
|
+
# plt.imshow(img2)
|
|
145
|
+
# plt.show()
|
|
146
|
+
|
|
147
|
+
img1, img2 = self.to_tensor(img1), self.to_tensor(img2)
|
|
148
|
+
# print("img1 to tensor ",img1)
|
|
149
|
+
return self.score_from_feature(img1, img2)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def numpy_to_torch(images):
|
|
153
|
+
images = images * 2.0 - 1.0
|
|
154
|
+
images = torch.from_numpy(images.transpose((0, 3, 1, 2))).float()
|
|
155
|
+
return images.cuda()
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class LPIPSMeter:
|
|
159
|
+
|
|
160
|
+
def __init__(self,
|
|
161
|
+
net='alex',
|
|
162
|
+
device=None,
|
|
163
|
+
size=224): # or we can use 'alex', 'vgg' as network
|
|
164
|
+
self.size = size
|
|
165
|
+
self.net = net
|
|
166
|
+
self.results = []
|
|
167
|
+
self.device = device if device is not None else torch.device(
|
|
168
|
+
'cuda' if torch.cuda.is_available() else 'cpu')
|
|
169
|
+
self.fn = lpips.LPIPS(net=net).eval().to(self.device)
|
|
170
|
+
|
|
171
|
+
def measure(self):
|
|
172
|
+
return np.mean(self.results)
|
|
173
|
+
|
|
174
|
+
def report(self):
|
|
175
|
+
return f'LPIPS ({self.net}) = {self.measure():.6f}'
|
|
176
|
+
|
|
177
|
+
def read_img_list(self, img_list):
|
|
178
|
+
size = self.size
|
|
179
|
+
images = []
|
|
180
|
+
white_background = np.ones((size, size, 3), dtype=np.uint8) * 255
|
|
181
|
+
|
|
182
|
+
for img_path in img_list:
|
|
183
|
+
img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
|
|
184
|
+
|
|
185
|
+
if img.shape[2] == 4: # Handle BGRA images
|
|
186
|
+
alpha = img[:, :, 3] # Extract alpha channel
|
|
187
|
+
img = cv2.cvtColor(img,
|
|
188
|
+
cv2.COLOR_BGRA2BGR) # Convert BGRA to BGR
|
|
189
|
+
|
|
190
|
+
img = cv2.cvtColor(img,
|
|
191
|
+
cv2.COLOR_BGR2RGB) # Convert BGR to RGB
|
|
192
|
+
img[np.where(alpha == 0)] = [
|
|
193
|
+
255, 255, 255
|
|
194
|
+
] # Set transparent pixels to white
|
|
195
|
+
else: # Handle other image formats like JPG and PNG
|
|
196
|
+
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
|
197
|
+
|
|
198
|
+
img = cv2.resize(img, (size, size), interpolation=cv2.INTER_AREA)
|
|
199
|
+
images.append(img)
|
|
200
|
+
|
|
201
|
+
images = np.stack(images, axis=0)
|
|
202
|
+
# images[np.where(images == 0)] = 255 # Set black pixels to white
|
|
203
|
+
# images = np.where(images == 0, white_background, images) # Set transparent pixels to white
|
|
204
|
+
images = images.astype(np.float32) / 255.0
|
|
205
|
+
|
|
206
|
+
return images
|
|
207
|
+
|
|
208
|
+
# * recommend to use this function for evaluation
|
|
209
|
+
@torch.no_grad()
|
|
210
|
+
def score_gt(self, ref_paths, novel_paths):
|
|
211
|
+
self.results = []
|
|
212
|
+
for path0, path1 in zip(ref_paths, novel_paths):
|
|
213
|
+
# Load images
|
|
214
|
+
# img0 = lpips.im2tensor(lpips.load_image(path0)).cuda() # RGB image from [-1,1]
|
|
215
|
+
# img1 = lpips.im2tensor(lpips.load_image(path1)).cuda()
|
|
216
|
+
img0, img1 = self.read_img_list([path0]), self.read_img_list(
|
|
217
|
+
[path1])
|
|
218
|
+
img0, img1 = numpy_to_torch(img0), numpy_to_torch(img1)
|
|
219
|
+
# print(img0.shape,img1.shape)
|
|
220
|
+
img0 = F.interpolate(img0,
|
|
221
|
+
size=(self.size, self.size),
|
|
222
|
+
mode='area')
|
|
223
|
+
img1 = F.interpolate(img1,
|
|
224
|
+
size=(self.size, self.size),
|
|
225
|
+
mode='area')
|
|
226
|
+
|
|
227
|
+
# for debug vis
|
|
228
|
+
# plt.imshow(img0.cpu().squeeze(0).permute(1, 2, 0).numpy())
|
|
229
|
+
# plt.show()
|
|
230
|
+
# plt.imshow(img1.cpu().squeeze(0).permute(1, 2, 0).numpy())
|
|
231
|
+
# plt.show()
|
|
232
|
+
# equivalent to cv2.resize(rgba, (w, h), interpolation=cv2.INTER_AREA
|
|
233
|
+
|
|
234
|
+
# print(img0.shape,img1.shape)
|
|
235
|
+
|
|
236
|
+
self.results.append(self.fn.forward(img0, img1).cpu().numpy())
|
|
237
|
+
|
|
238
|
+
return self.measure()
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class PSNRMeter:
|
|
242
|
+
|
|
243
|
+
def __init__(self, size=800):
|
|
244
|
+
self.results = []
|
|
245
|
+
self.size = size
|
|
246
|
+
|
|
247
|
+
def read_img_list(self, img_list):
|
|
248
|
+
size = self.size
|
|
249
|
+
images = []
|
|
250
|
+
white_background = np.ones((size, size, 3), dtype=np.uint8) * 255
|
|
251
|
+
for img_path in img_list:
|
|
252
|
+
img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
|
|
253
|
+
|
|
254
|
+
if img.shape[2] == 4: # Handle BGRA images
|
|
255
|
+
alpha = img[:, :, 3] # Extract alpha channel
|
|
256
|
+
img = cv2.cvtColor(img,
|
|
257
|
+
cv2.COLOR_BGRA2BGR) # Convert BGRA to BGR
|
|
258
|
+
|
|
259
|
+
img = cv2.cvtColor(img,
|
|
260
|
+
cv2.COLOR_BGR2RGB) # Convert BGR to RGB
|
|
261
|
+
img[np.where(alpha == 0)] = [
|
|
262
|
+
255, 255, 255
|
|
263
|
+
] # Set transparent pixels to white
|
|
264
|
+
else: # Handle other image formats like JPG and PNG
|
|
265
|
+
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
|
266
|
+
|
|
267
|
+
img = cv2.resize(img, (size, size), interpolation=cv2.INTER_AREA)
|
|
268
|
+
images.append(img)
|
|
269
|
+
|
|
270
|
+
images = np.stack(images, axis=0)
|
|
271
|
+
# images[np.where(images == 0)] = 255 # Set black pixels to white
|
|
272
|
+
# images = np.where(images == 0, white_background, images) # Set transparent pixels to white
|
|
273
|
+
images = images.astype(np.float32) / 255.0
|
|
274
|
+
# print(images.shape)
|
|
275
|
+
return images
|
|
276
|
+
|
|
277
|
+
def update(self, preds, truths):
|
|
278
|
+
# print(preds.shape)
|
|
279
|
+
|
|
280
|
+
psnr_values = []
|
|
281
|
+
# For each pair of images in the batches
|
|
282
|
+
for img1, img2 in zip(preds, truths):
|
|
283
|
+
# Compute the PSNR and add it to the list
|
|
284
|
+
# print(img1.shape,img2.shape)
|
|
285
|
+
|
|
286
|
+
# for debug
|
|
287
|
+
# plt.imshow(img1)
|
|
288
|
+
# plt.show()
|
|
289
|
+
# plt.imshow(img2)
|
|
290
|
+
# plt.show()
|
|
291
|
+
|
|
292
|
+
psnr = compare_psnr(
|
|
293
|
+
img1, img2,
|
|
294
|
+
data_range=1.0) # assuming your images are scaled to [0,1]
|
|
295
|
+
# print(f"temp psnr {psnr}")
|
|
296
|
+
psnr_values.append(psnr)
|
|
297
|
+
|
|
298
|
+
# Convert the list of PSNR values to a numpy array
|
|
299
|
+
self.results = psnr_values
|
|
300
|
+
|
|
301
|
+
def measure(self):
|
|
302
|
+
return np.mean(self.results)
|
|
303
|
+
|
|
304
|
+
def report(self):
|
|
305
|
+
return f'PSNR = {self.measure():.6f}'
|
|
306
|
+
|
|
307
|
+
# * recommend to use this function for evaluation
|
|
308
|
+
def score_gt(self, ref_paths, novel_paths):
|
|
309
|
+
self.results = []
|
|
310
|
+
# [B, N, 3] or [B, H, W, 3], range[0, 1]
|
|
311
|
+
preds = self.read_img_list(ref_paths)
|
|
312
|
+
truths = self.read_img_list(novel_paths)
|
|
313
|
+
self.update(preds, truths)
|
|
314
|
+
return self.measure()
|
|
315
|
+
|
|
316
|
+
all_inputs = 'data'
|
|
317
|
+
nerf_dataset = os.listdir(osp(all_inputs, 'nerf4'))
|
|
318
|
+
realfusion_dataset = os.listdir(osp(all_inputs, 'realfusion15'))
|
|
319
|
+
meta_examples = {
|
|
320
|
+
'nerf4': nerf_dataset,
|
|
321
|
+
'realfusion15': realfusion_dataset,
|
|
322
|
+
}
|
|
323
|
+
all_datasets = meta_examples.keys()
|
|
324
|
+
|
|
325
|
+
# organization 1
|
|
326
|
+
def deprecated_score_from_method_for_dataset(my_scorer,
|
|
327
|
+
method,
|
|
328
|
+
dataset,
|
|
329
|
+
input,
|
|
330
|
+
output,
|
|
331
|
+
score_type='clip',
|
|
332
|
+
): # psnr, lpips
|
|
333
|
+
# print("\n\n\n")
|
|
334
|
+
# print(f"______{method}___{dataset}___{score_type}_________")
|
|
335
|
+
scores = {}
|
|
336
|
+
final_res = 0
|
|
337
|
+
examples = meta_examples[dataset]
|
|
338
|
+
for i in range(len(examples)):
|
|
339
|
+
|
|
340
|
+
# compare entire folder for clip
|
|
341
|
+
if score_type == 'clip':
|
|
342
|
+
novel_view = osp(pred_path, examples[i], 'colors')
|
|
343
|
+
# compare first image for other metrics
|
|
344
|
+
else:
|
|
345
|
+
if method == '3d_fuse': method = '3d_fuse_0'
|
|
346
|
+
novel_view = list(
|
|
347
|
+
glob.glob(
|
|
348
|
+
osp(pred_path, examples[i], 'colors',
|
|
349
|
+
'step_0000*')))[0]
|
|
350
|
+
|
|
351
|
+
score_i = my_scorer.score_gt(
|
|
352
|
+
[], [novel_view])
|
|
353
|
+
scores[examples[i]] = score_i
|
|
354
|
+
final_res += score_i
|
|
355
|
+
# print(scores, " Avg : ", final_res / len(examples))
|
|
356
|
+
# print("``````````````````````")
|
|
357
|
+
return scores
|
|
358
|
+
|
|
359
|
+
# results organization 2
|
|
360
|
+
def score_from_method_for_dataset(my_scorer,
|
|
361
|
+
input_path,
|
|
362
|
+
pred_path,
|
|
363
|
+
score_type='clip',
|
|
364
|
+
rgb_name='lambertian',
|
|
365
|
+
result_folder='results/images',
|
|
366
|
+
first_str='*0000*'
|
|
367
|
+
): # psnr, lpips
|
|
368
|
+
scores = {}
|
|
369
|
+
final_res = 0
|
|
370
|
+
examples = os.listdir(input_path)
|
|
371
|
+
for i in range(len(examples)):
|
|
372
|
+
# ref path
|
|
373
|
+
ref_path = osp(input_path, examples[i], 'rgba.png')
|
|
374
|
+
# compare entire folder for clip
|
|
375
|
+
if score_type == 'clip':
|
|
376
|
+
novel_view = glob.glob(osp(pred_path,'*'+examples[i]+'*', result_folder, f'*{rgb_name}*'))
|
|
377
|
+
print(f'[INOF] {score_type} loss for example {examples[i]} between 1 GT and {len(novel_view)} predictions')
|
|
378
|
+
# compare first image for other metrics
|
|
379
|
+
else:
|
|
380
|
+
novel_view = glob.glob(osp(pred_path, '*'+examples[i]+'*/', result_folder, f'{first_str}{rgb_name}*'))
|
|
381
|
+
print(f'[INOF] {score_type} loss for example {examples[i]} between {ref_path} and {novel_view}')
|
|
382
|
+
# breakpoint()
|
|
383
|
+
score_i = my_scorer.score_gt([ref_path], novel_view)
|
|
384
|
+
scores[examples[i]] = score_i
|
|
385
|
+
final_res += score_i
|
|
386
|
+
avg_score = final_res / len(examples)
|
|
387
|
+
scores['average'] = avg_score
|
|
388
|
+
return scores
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
if __name__ == "__main__":
|
|
392
|
+
parser = argparse.ArgumentParser(
|
|
393
|
+
description="Script to accept three string arguments")
|
|
394
|
+
parser.add_argument("--input_path",
|
|
395
|
+
default=all_inputs,
|
|
396
|
+
help="Specify the input path")
|
|
397
|
+
parser.add_argument("--pred_pattern",
|
|
398
|
+
default="out/magic123*",
|
|
399
|
+
help="Specify the pattern of predition paths")
|
|
400
|
+
parser.add_argument("--results_folder",
|
|
401
|
+
default="results/images",
|
|
402
|
+
help="where are the results under each pred_path")
|
|
403
|
+
parser.add_argument("--rgb_name",
|
|
404
|
+
default="lambertian",
|
|
405
|
+
help="the postfix of the image")
|
|
406
|
+
parser.add_argument("--first_str",
|
|
407
|
+
default="*0000*",
|
|
408
|
+
help="the str to indicate the first view")
|
|
409
|
+
parser.add_argument("--datasets",
|
|
410
|
+
default=all_datasets,
|
|
411
|
+
nargs='*',
|
|
412
|
+
help="Specify the output path")
|
|
413
|
+
parser.add_argument("--device",
|
|
414
|
+
type=int,
|
|
415
|
+
default=0,
|
|
416
|
+
help="Specify the GPU device to be used")
|
|
417
|
+
parser.add_argument("--save_dir", type=str, default='all_metrics/results')
|
|
418
|
+
args = parser.parse_args()
|
|
419
|
+
|
|
420
|
+
clip_scorer = CLIP(args.device)
|
|
421
|
+
lpips_scorer = LPIPSMeter()
|
|
422
|
+
psnr_scorer = PSNRMeter()
|
|
423
|
+
|
|
424
|
+
os.makedirs(args.save_dir, exist_ok=True)
|
|
425
|
+
|
|
426
|
+
for dataset in args.datasets:
|
|
427
|
+
input_path = osp(args.input_path, dataset)
|
|
428
|
+
|
|
429
|
+
# assume the pred_path is organized as: pred_path/methods/dataset
|
|
430
|
+
pred_pattern = osp(args.pred_pattern, dataset)
|
|
431
|
+
pred_paths = glob.glob(pred_pattern)
|
|
432
|
+
print(f"[INFO] Following the pattern {pred_pattern}, find {len(pred_paths)} pred_paths: \n", pred_paths)
|
|
433
|
+
if len(pred_paths) == 0:
|
|
434
|
+
raise IOError
|
|
435
|
+
for pred_path in pred_paths:
|
|
436
|
+
if not os.path.exists(pred_path):
|
|
437
|
+
print(f'[WARN] prediction does not exit for {pred_path}')
|
|
438
|
+
else:
|
|
439
|
+
print(f'[INFO] evaluate {pred_path}')
|
|
440
|
+
results_dict = {}
|
|
441
|
+
results_dict['clip'] = score_from_method_for_dataset(
|
|
442
|
+
clip_scorer, input_path, pred_path, 'clip',
|
|
443
|
+
result_folder=args.results_folder, rgb_name=args.rgb_name, first_str=args.first_str)
|
|
444
|
+
|
|
445
|
+
results_dict['psnr'] = score_from_method_for_dataset(
|
|
446
|
+
psnr_scorer, input_path, pred_path, 'psnr',
|
|
447
|
+
result_folder=args.results_folder, rgb_name=args.rgb_name, first_str=args.first_str)
|
|
448
|
+
|
|
449
|
+
results_dict['lpips'] = score_from_method_for_dataset(
|
|
450
|
+
lpips_scorer, input_path, pred_path, 'lpips',
|
|
451
|
+
result_folder=args.results_folder, rgb_name=args.rgb_name, first_str=args.first_str)
|
|
452
|
+
|
|
453
|
+
df = pd.DataFrame(results_dict)
|
|
454
|
+
method = pred_path.split('/')[-2]
|
|
455
|
+
print(osp(pred_path, args.results_folder))
|
|
456
|
+
results_str = '_'.join(args.results_folder.split('/'))
|
|
457
|
+
print(method+'-'+results_str)
|
|
458
|
+
print(df)
|
|
459
|
+
df.to_csv(f"{args.save_dir}/{method}-{results_str}-{dataset}.csv")
|
dnnultis/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .log import *
|
dnnultis/log/__init__.py
ADDED
dnnultis/log/logger.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import logging
|
|
3
|
+
import os, sys
|
|
4
|
+
from termcolor import colored
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class _ColorfulFormatter(logging.Formatter):
|
|
8
|
+
def __init__(self, *args, **kwargs):
|
|
9
|
+
self._root_name = kwargs.pop("root_name") + "."
|
|
10
|
+
self._abbrev_name = kwargs.pop("abbrev_name", "")
|
|
11
|
+
if len(self._abbrev_name):
|
|
12
|
+
self._abbrev_name = self._abbrev_name + "."
|
|
13
|
+
super(_ColorfulFormatter, self).__init__(*args, **kwargs)
|
|
14
|
+
|
|
15
|
+
def formatMessage(self, record):
|
|
16
|
+
record.name = record.name.replace(self._root_name, self._abbrev_name)
|
|
17
|
+
log = super(_ColorfulFormatter, self).formatMessage(record)
|
|
18
|
+
if record.levelno == logging.WARNING:
|
|
19
|
+
prefix = colored("WARNING", "red", attrs=["blink"])
|
|
20
|
+
elif record.levelno == logging.ERROR or record.levelno == logging.CRITICAL:
|
|
21
|
+
prefix = colored("ERROR", "red", attrs=["blink", "underline"])
|
|
22
|
+
else:
|
|
23
|
+
return log
|
|
24
|
+
return prefix + " " + log
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# so that calling setup_logging.root multiple times won't add many handlers
|
|
28
|
+
@functools.lru_cache()
|
|
29
|
+
def setup_logging(output=None,
|
|
30
|
+
distributed_rank=0,
|
|
31
|
+
default_level=logging.INFO,
|
|
32
|
+
*,
|
|
33
|
+
color=True,
|
|
34
|
+
name=__name__):
|
|
35
|
+
"""
|
|
36
|
+
Initialize the detectron2 logging.root and set its verbosity level to "INFO".
|
|
37
|
+
Args:
|
|
38
|
+
output (str): a file name or a directory to save log. If None, will not save log file.
|
|
39
|
+
If ends with ".txt" or ".log", assumed to be a file name.
|
|
40
|
+
Otherwise, logs will be saved to `output/log.txt`.
|
|
41
|
+
name (str): the root module name of this logging.root
|
|
42
|
+
Returns:
|
|
43
|
+
logging.logging.root: a logging.root
|
|
44
|
+
"""
|
|
45
|
+
logging.root.setLevel(default_level)
|
|
46
|
+
logging.root.propagate = False
|
|
47
|
+
|
|
48
|
+
plain_formatter = logging.Formatter(
|
|
49
|
+
"[%(asctime)s] %(name)s %(levelname)s: %(message)s",
|
|
50
|
+
datefmt="%y/%m/%d %H:%M:%S")
|
|
51
|
+
# stdout logging: master only
|
|
52
|
+
if distributed_rank == 0:
|
|
53
|
+
ch = logging.StreamHandler(stream=sys.stdout)
|
|
54
|
+
ch.setLevel(default_level)
|
|
55
|
+
if color:
|
|
56
|
+
formatter = _ColorfulFormatter(
|
|
57
|
+
colored("[%(asctime)s %(name)s]: ", "green") + "%(message)s",
|
|
58
|
+
datefmt="%y/%m/%d %H:%M:%S",
|
|
59
|
+
root_name=name,
|
|
60
|
+
)
|
|
61
|
+
else:
|
|
62
|
+
formatter = plain_formatter
|
|
63
|
+
ch.setFormatter(formatter)
|
|
64
|
+
logging.root.addHandler(ch)
|
|
65
|
+
|
|
66
|
+
# file logging: all workers
|
|
67
|
+
if output is not None:
|
|
68
|
+
if output.endswith(".txt") or output.endswith(".log"):
|
|
69
|
+
filename = output
|
|
70
|
+
else:
|
|
71
|
+
filename = os.path.join(output, "log.txt")
|
|
72
|
+
if distributed_rank > 0:
|
|
73
|
+
filename = filename + f".rank{distributed_rank}"
|
|
74
|
+
os.makedirs(os.path.dirname(filename), exist_ok=True)
|
|
75
|
+
|
|
76
|
+
fh = logging.StreamHandler(_cached_log_stream(filename))
|
|
77
|
+
fh.setLevel(default_level)
|
|
78
|
+
fh.setFormatter(plain_formatter)
|
|
79
|
+
logging.root.addHandler(fh)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# cache the opened file object, so that different calls to `setup_logging.root`
|
|
83
|
+
# with the same file name can safely write to the same file.
|
|
84
|
+
@functools.lru_cache(maxsize=None)
|
|
85
|
+
def _cached_log_stream(filename):
|
|
86
|
+
return open(filename, "a")
|
dnnultis/log/wandb.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
import os
|
|
3
|
+
import subprocess
|
|
4
|
+
import wandb
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class WandbUrls:
|
|
8
|
+
def __init__(self, url):
|
|
9
|
+
|
|
10
|
+
hash = url.split("/")[-2]
|
|
11
|
+
project = url.split("/")[-3]
|
|
12
|
+
entity = url.split("/")[-4]
|
|
13
|
+
|
|
14
|
+
self.weight_url = url
|
|
15
|
+
self.log_url = "https://app.wandb.ai/{}/{}/runs/{}/logs".format(entity, project, hash)
|
|
16
|
+
self.chart_url = "https://app.wandb.ai/{}/{}/runs/{}".format(entity, project, hash)
|
|
17
|
+
self.overview_url = "https://app.wandb.ai/{}/{}/runs/{}/overview".format(entity, project, hash)
|
|
18
|
+
self.config_url = "https://app.wandb.ai/{}/{}/runs/{}/files/hydra-config.yaml".format(
|
|
19
|
+
entity, project, hash
|
|
20
|
+
)
|
|
21
|
+
self.overrides_url = "https://app.wandb.ai/{}/{}/runs/{}/files/overrides.yaml".format(entity, project, hash)
|
|
22
|
+
|
|
23
|
+
def __repr__(self):
|
|
24
|
+
msg = "=================================================== WANDB URLS ===================================================================\n"
|
|
25
|
+
for k, v in self.__dict__.items():
|
|
26
|
+
msg += "{}: {}\n".format(k.upper(), v)
|
|
27
|
+
msg += "=================================================================================================================================\n"
|
|
28
|
+
return msg
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class Wandb:
|
|
32
|
+
IS_ACTIVE = False
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def set_urls_to_model(model, url):
|
|
36
|
+
wandb_urls = WandbUrls(url)
|
|
37
|
+
model.wandb = wandb_urls
|
|
38
|
+
|
|
39
|
+
@staticmethod
|
|
40
|
+
def _set_to_wandb_args(wandb_args, cfg, name):
|
|
41
|
+
var = getattr(cfg.wandb, name, None)
|
|
42
|
+
if var:
|
|
43
|
+
wandb_args[name] = var
|
|
44
|
+
|
|
45
|
+
@staticmethod
|
|
46
|
+
def launch(cfg, launch: bool):
|
|
47
|
+
if launch:
|
|
48
|
+
|
|
49
|
+
Wandb.IS_ACTIVE = True
|
|
50
|
+
|
|
51
|
+
wandb_args = {}
|
|
52
|
+
wandb_args["resume"] = "allow"
|
|
53
|
+
Wandb._set_to_wandb_args(wandb_args, cfg, "tags")
|
|
54
|
+
Wandb._set_to_wandb_args(wandb_args, cfg, "project")
|
|
55
|
+
Wandb._set_to_wandb_args(wandb_args, cfg, "name")
|
|
56
|
+
Wandb._set_to_wandb_args(wandb_args, cfg, "entity")
|
|
57
|
+
Wandb._set_to_wandb_args(wandb_args, cfg, "notes")
|
|
58
|
+
Wandb._set_to_wandb_args(wandb_args, cfg, "config")
|
|
59
|
+
Wandb._set_to_wandb_args(wandb_args, cfg, "id")
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
commit_sha = subprocess.check_output(["git", "rev-parse", "HEAD"]).decode("ascii").strip()
|
|
63
|
+
gitdiff = subprocess.check_output(["git", "diff", "--", "':!notebooks'"]).decode()
|
|
64
|
+
except:
|
|
65
|
+
commit_sha = "n/a"
|
|
66
|
+
gitdiff = ""
|
|
67
|
+
|
|
68
|
+
config = wandb_args.get("config", {})
|
|
69
|
+
wandb_args["config"] = {
|
|
70
|
+
**config,
|
|
71
|
+
"run_path": os.getcwd(),
|
|
72
|
+
"commit": commit_sha,
|
|
73
|
+
"gitdiff": gitdiff
|
|
74
|
+
}
|
|
75
|
+
wandb.init(**wandb_args, sync_tensorboard=True)
|
|
76
|
+
wandb.save(os.path.join(os.getcwd(), cfg.cfg_path))
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def add_file(file_path: str):
|
|
80
|
+
if not Wandb.IS_ACTIVE:
|
|
81
|
+
raise RuntimeError("wandb is inactive, please launch first.")
|
|
82
|
+
|
|
83
|
+
filename = os.path.basename(file_path)
|
|
84
|
+
shutil.copyfile(file_path, os.path.join(wandb.run.dir, filename))
|