InPeerReview commited on
Commit
f4834aa
·
verified ·
1 Parent(s): 252cb56

Upload 2 files

Browse files
Files changed (2) hide show
  1. core/logger.py +118 -0
  2. core/metrics.py +107 -0
core/logger.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ from collections import OrderedDict
4
+ import json
5
+ from datetime import datetime
6
+ import argparse
7
+
8
+
9
+ def mkdirs(paths):
10
+ if isinstance(paths, str):
11
+ os.makedirs(paths, exist_ok=True)
12
+ else:
13
+ for path in paths:
14
+ os.makedirs(path, exist_ok=True)
15
+
16
+ def get_timestamp():
17
+ return datetime.now().strftime('%y%m%d_%H%M%S')
18
+
19
+
20
+ def parse(args):
21
+ phase = args.phase
22
+ opt_path =args.config
23
+ gpu_ids = args.gpu_ids
24
+
25
+ json_str = ''
26
+ with open(opt_path, 'r') as f:
27
+ for line in f:
28
+ line = line.split('//')[0] + '\n'
29
+ json_str += line
30
+ #print(json_str)
31
+ opt =json.loads(json_str, object_pairs_hook=OrderedDict)
32
+ #print(opt)
33
+
34
+ #create experiments folder
35
+ experiments_root = os.path.join(
36
+ 'experiments', '{}_{}'.format(opt['name'], get_timestamp()))
37
+ opt['path_cd']['experiments_root'] = experiments_root
38
+ for key, path in opt['path_cd'].items():
39
+ if 'resume' not in key and 'experiments' not in key:
40
+ opt['path_cd'][key] = os.path.join(experiments_root, path)
41
+ mkdirs(opt['path_cd'][key])
42
+
43
+ #chaneg dataset len
44
+ opt['phase'] = phase
45
+
46
+ # export CUDA_VISIBLE_DEVICES
47
+ if gpu_ids is not None:
48
+ opt['gpu_ids'] = [int(id) for id in gpu_ids.split(',')]
49
+ gpu_list = gpu_ids
50
+ else:
51
+ gpu_list = ','.join(str(x) for x in opt['gpu_ids'])
52
+ #print(gpu_list)
53
+ os.environ['CUDA_VISIBLE_DEVICES'] = gpu_list
54
+ print('expert CUDA_VISIBLE_DEVICES=' + gpu_list)
55
+ if len(gpu_list) > 1:
56
+ opt['distributed'] = True
57
+ else:
58
+ opt['distributed'] = False
59
+
60
+ return opt
61
+
62
+ class NoneDict(dict):
63
+ def __missing__(self, key):
64
+ return None
65
+
66
+ # convert to NoneDict, which return None for missing key.
67
+ def dict_to_nonedict(opt):
68
+ if isinstance(opt, dict):
69
+ new_opt = dict()
70
+ for key, sub_opt in opt.items():
71
+ new_opt[key] = dict_to_nonedict(sub_opt)
72
+ return NoneDict(**new_opt)
73
+ elif isinstance(opt, list):
74
+ return [dict_to_nonedict(sub_opt) for sub_opt in opt]
75
+ else:
76
+ return opt
77
+
78
+ def dict2str(opt, indent_l=1):
79
+ '''dict to string for logger'''
80
+ msg = ''
81
+ for k, v in opt.items():
82
+ if isinstance(v, dict):
83
+ msg += ' ' * (indent_l * 2) + k + ':[\n'
84
+ msg += dict2str(v, indent_l + 1)
85
+ msg += ' ' * (indent_l * 2) + ']\n'
86
+ else:
87
+ msg += ' ' * (indent_l * 2) + k + ': ' + str(v) + '\n'
88
+ return msg
89
+
90
+ def setup_logger(logger_name, root, phase, level=logging.INFO, screen=False):
91
+ '''set up logger'''
92
+ l = logging.getLogger(logger_name)
93
+ formatter = logging.Formatter(
94
+ '%(asctime)s.%(msecs)03d - %(levelname)s: %(message)s', datefmt='%y-%m-%d %H:%M:%S')
95
+ print(formatter)
96
+ log_file = os.path.join(root, '{}.log'.format(phase))
97
+ print(log_file)
98
+ fh = logging.FileHandler(log_file, mode='w')
99
+ fh.setFormatter(formatter)
100
+ l.setLevel(level)
101
+ l.addHandler(fh)
102
+ if screen:
103
+ sh = logging.StreamHandler()
104
+ sh.setFormatter(formatter)
105
+ l.addHandler(sh)
106
+
107
+
108
+ if __name__ == "__main__":
109
+ parser = argparse.ArgumentParser()
110
+ parser.add_argument('-c', '--config', type=str, default='../config/levir.json')
111
+ parser.add_argument('-p', '--phase', type=str, choices=['train', 'test'], default='train')
112
+ parser.add_argument('-gpu', '--gpu_ids', type=str, default=None)
113
+
114
+ args = parser.parse_args()
115
+ opt = parse(args)
116
+ print(opt)
117
+ opt = dict_to_nonedict(opt)
118
+ print(opt)
core/metrics.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import math
3
+ import numpy as np
4
+ import cv2
5
+ from torchvision.utils import make_grid
6
+ from data.colormap import second_colormap
7
+
8
+
9
+ def tensor2img(tensor, out_type=np.uint8, min_max=(-1, 1)):
10
+ '''
11
+ Converts a torch Tensor into an image Numpy array
12
+ Input: 4D(B,(3/1),H,W), 3D(C,H,W), or 2D(H,W), any range, RGB channel order
13
+ Output: 3D(H,W,C) or 2D(H,W), [0,255], np.uint8 (default)
14
+ '''
15
+ tensor = tensor.squeeze().float().cpu().clamp_(*min_max) # clamp
16
+ tensor = (tensor - min_max[0]) / \
17
+ (min_max[1] - min_max[0]) # to range [0,1]
18
+ n_dim = tensor.dim()
19
+ if n_dim == 4:
20
+ n_img = len(tensor)
21
+ img_np = make_grid(tensor, nrow=int(
22
+ math.sqrt(n_img)), normalize=False).numpy()
23
+ img_np = np.transpose(img_np, (1, 2, 0)) # HWC, RGB
24
+ elif n_dim == 3:
25
+ img_np = tensor.numpy()
26
+ img_np = np.transpose(img_np, (1, 2, 0)) # HWC, RGB
27
+ elif n_dim == 2:
28
+ img_np = tensor.numpy()
29
+ else:
30
+ raise TypeError(
31
+ 'Only support 4D, 3D and 2D tensor. But received with dimension: {:d}'.format(n_dim))
32
+ if out_type == np.uint8:
33
+ img_np = (img_np * 255.0).round()
34
+ # Important. Unlike matlab, numpy.unit8() WILL NOT round by default.
35
+ return img_np.astype(out_type)
36
+
37
+
38
+ def Index2Color(pred, cmap=second_colormap):
39
+ colormap = np.asarray(cmap, dtype='uint8')
40
+ x = np.asarray(pred, dtype='int32')
41
+ return colormap[x, :]
42
+
43
+ def save_img(img, img_path, mode='RGB'):
44
+ cv2.imwrite(img_path, cv2.cvtColor(img, cv2.COLOR_RGB2BGR))
45
+ # cv2.imwrite(img_path, img)
46
+
47
+ def save_scdimg(img, img_path, mode='RGB'):
48
+ cv2.imwrite(img_path, cv2.cvtColor(np.squeeze(img, axis=0), cv2.COLOR_RGB2BGR))
49
+
50
+ def save_feat(img, img_path, mode='RGB'):
51
+ cv2.imwrite(img_path, cv2.applyColorMap(cv2.resize(img, (256,256), interpolation=cv2.INTER_CUBIC), cv2.COLORMAP_JET))
52
+ # cv2.imwrite(img_path, cv2.resize(img, (256,256), interpolation=cv2.INTER_))
53
+ # cv2.imwrite(img_path, img)
54
+
55
+
56
+ def calculate_psnr(img1, img2):
57
+ # img1 and img2 have range [0, 255]
58
+ img1 = img1.astype(np.float64)
59
+ img2 = img2.astype(np.float64)
60
+ mse = np.mean((img1 - img2)**2)
61
+ if mse == 0:
62
+ return float('inf')
63
+ return 20 * math.log10(255.0 / math.sqrt(mse))
64
+
65
+
66
+ def ssim(img1, img2):
67
+ C1 = (0.01 * 255)**2
68
+ C2 = (0.03 * 255)**2
69
+
70
+ img1 = img1.astype(np.float64)
71
+ img2 = img2.astype(np.float64)
72
+ kernel = cv2.getGaussianKernel(11, 1.5)
73
+ window = np.outer(kernel, kernel.transpose())
74
+
75
+ mu1 = cv2.filter2D(img1, -1, window)[5:-5, 5:-5] # valid
76
+ mu2 = cv2.filter2D(img2, -1, window)[5:-5, 5:-5]
77
+ mu1_sq = mu1**2
78
+ mu2_sq = mu2**2
79
+ mu1_mu2 = mu1 * mu2
80
+ sigma1_sq = cv2.filter2D(img1**2, -1, window)[5:-5, 5:-5] - mu1_sq
81
+ sigma2_sq = cv2.filter2D(img2**2, -1, window)[5:-5, 5:-5] - mu2_sq
82
+ sigma12 = cv2.filter2D(img1 * img2, -1, window)[5:-5, 5:-5] - mu1_mu2
83
+
84
+ ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / ((mu1_sq + mu2_sq + C1) *
85
+ (sigma1_sq + sigma2_sq + C2))
86
+ return ssim_map.mean()
87
+
88
+
89
+ def calculate_ssim(img1, img2):
90
+ '''calculate SSIM
91
+ the same outputs as MATLAB's
92
+ img1, img2: [0, 255]
93
+ '''
94
+ if not img1.shape == img2.shape:
95
+ raise ValueError('Input images must have the same dimensions.')
96
+ if img1.ndim == 2:
97
+ return ssim(img1, img2)
98
+ elif img1.ndim == 3:
99
+ if img1.shape[2] == 3:
100
+ ssims = []
101
+ for i in range(3):
102
+ ssims.append(ssim(img1, img2))
103
+ return np.array(ssims).mean()
104
+ elif img1.shape[2] == 1:
105
+ return ssim(np.squeeze(img1), np.squeeze(img2))
106
+ else:
107
+ raise ValueError('Wrong input image dimensions.')