-
Notifications
You must be signed in to change notification settings - Fork 10
/
utils.py
115 lines (93 loc) · 3.68 KB
/
utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import torch
import numpy as np
eps = np.finfo(np.float32).eps
PI = 3.141592
chrom0 = torch.tensor([[1.0], [1.0], [1.0]])
chrom0 /= torch.norm(chrom0, p=2)
temp = torch.tensor([[0.0], [0.0], [1.0]])
chrom1 = torch.cross(chrom0, temp)
chrom1 /= torch.norm(chrom1, p=2)
chrom2 = torch.cross(chrom0, chrom1)
chrom2 /= torch.norm(chrom2, p=2)
theta = torch.FloatTensor([PI / 180 * (idx + 1) for idx in range(180)])
X, Y = torch.cos(theta), torch.sin(theta)
XY = torch.cat((X.reshape(1, -1), Y.reshape(1, -1)), dim=0)
def entropy_intrinsic(image, calculate_intrinsic_img=False):
img_flat = image.reshape(-1, 3)
log_geomean = torch.log(
torch.pow(
torch.mul(torch.mul(img_flat[:, 0], img_flat[:, 1]), img_flat[:, 2]),
(1 / 3.0),
)
).float()
allrgbslog = torch.log(img_flat).float()
allrgbslog[:, 0] -= log_geomean
allrgbslog[:, 1] -= log_geomean
allrgbslog[:, 2] -= log_geomean
chi = torch.cat(
(torch.matmul(allrgbslog, chrom1), torch.matmul(allrgbslog, chrom2)), dim=1
)
entropy = torch.zeros_like(theta)
projGrey = torch.matmul(chi, XY)
projGrey_np = projGrey.cpu().numpy()
P05 = np.percentile(projGrey_np, 5, 0)
P95 = np.percentile(projGrey_np, 95, 0)
for idx, col in enumerate(projGrey_np.T):
p05, p95 = P05[idx], P95[idx]
im = col[np.where(np.logical_and(col > p05, col < p95))[0]]
n = im.shape[0]
bin_wid = 3.5 * np.power(n, (-1.0 / 3)) * np.std(im)
his_up, his_low = np.max(im), np.min(im)
nbin = np.int(np.ceil((his_up - his_low) / bin_wid))
bins = np.arange(his_low, (nbin + 1) * bin_wid + his_low, bin_wid)
hist, _ = np.histogram(im, bins)
n_hist = hist / n
tmp_entropy = 0
for bin_idx in range(nbin):
if n_hist[bin_idx] != 0:
tmp_entropy -= n_hist[bin_idx] * np.log2(n_hist[bin_idx])
entropy[idx] = tmp_entropy
if calculate_intrinsic_img:
projected = torch.matmul(chi, XY[:, int(np.argmin(tmp_entropy))]).reshape(
128, 128
)
return (np.argmin(entropy), projected)
else:
return np.argmin(entropy)
def hist_match(source, template):
"""
Source: https://stackoverflow.com/a/33047048
Adjust the pixel values of a grayscale image such that its histogram
matches that of a target image
Arguments:
-----------
source: np.ndarray
Image to transform; the histogram is computed over the flattened
array
template: np.ndarray
Template image; can have different dimensions to source
Returns:
-----------
matched: np.ndarray
The transformed output image
"""
oldshape = source.shape
source = source.ravel()
template = template.ravel()
# get the set of unique pixel values and their corresponding indices and
# counts
s_values, bin_idx, s_counts = np.unique(
source, return_inverse=True, return_counts=True
)
t_values, t_counts = np.unique(template, return_counts=True)
# take the cumsum of the counts and normalize by the number of pixels to
# get the empirical cumulative distribution functions for the source and
# template images (maps pixel value --> quantile)
s_quantiles = np.cumsum(s_counts).astype(np.float64)
s_quantiles /= s_quantiles[-1]
t_quantiles = np.cumsum(t_counts).astype(np.float64)
t_quantiles /= t_quantiles[-1]
# interpolate linearly to find the pixel values in the template image
# that correspond most closely to the quantiles in the source image
interp_t_values = np.interp(s_quantiles, t_quantiles, t_values)
return interp_t_values[bin_idx].reshape(oldshape)