Created
July 18, 2020 23:36
-
-
Save vardanagarwal/a220001705902dc950d756164ec5614d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from itertools import combinations_with_replacement | |
| from collections import defaultdict | |
| import numpy as np | |
| from numpy.linalg import inv | |
| B, G, R = 0, 1, 2 # index for convenience | |
| def boxfilter(I, r): | |
| """Fast box filter implementation. | |
| Parameters | |
| ---------- | |
| I: a single channel/gray image data normalized to [0.0, 1.0] | |
| r: window radius | |
| Return | |
| ----------- | |
| The filtered image data. | |
| """ | |
| M, N = I.shape | |
| dest = np.zeros((M, N)) | |
| #print(I) | |
| # cumulative sum over Y axis (tate-houkou no wa) | |
| sumY = np.cumsum(I, axis=0) | |
| #print('sumY:{}'.format(sumY)) | |
| # difference over Y axis | |
| dest[:r + 1] = sumY[r:2*r + 1] # top r+1 lines | |
| dest[r + 1:M - r] = sumY[2*r + 1:] - sumY[:M - 2*r - 1] | |
| #print(sumY[2*r + 1:]) # from 2*r+1 to end lines | |
| #print(sumY[:M - 2*r - 1]) # same lines of above, from start | |
| #tile replicate sumY[-1] and line them up to match the shape of (r, 1) | |
| dest[-r:] = np.tile(sumY[-1], (r, 1)) - sumY[M - 2*r - 1:M - r - 1] # bottom r lines | |
| # cumulative sum over X axis | |
| sumX = np.cumsum(dest, axis=1) | |
| #print('sumX:{}'.format(sumX)) | |
| # difference over X axis | |
| dest[:, :r + 1] = sumX[:, r:2*r + 1] # left r+1 columns | |
| dest[:, r + 1:N - r] = sumX[:, 2*r + 1:] - sumX[:, :N - 2*r - 1] | |
| dest[:, -r:] = np.tile(sumX[:, -1][:, None], (1, r)) - sumX[:, N - 2*r - 1:N - r - 1] # right r columns | |
| #print(dest) | |
| return dest | |
| def guided_filter(I, p, r=15, eps=1e-3): | |
| """Refine a filter under the guidance of another (RGB) image. | |
| Parameters | |
| ----------- | |
| I: an M * N * 3 RGB image for guidance. | |
| p: the M * N filter to be guided. transmission is used for this case. | |
| r: the radius of the guidance | |
| eps: epsilon for the guided filter | |
| Return | |
| ----------- | |
| The guided filter. | |
| """ | |
| M, N = p.shape | |
| base = boxfilter(np.ones((M, N)), r) # this is needed for regularization | |
| # each channel of I filtered with the mean filter. this is myu. | |
| means = [boxfilter(I[:, :, i], r) / base for i in range(3)] | |
| # p filtered with the mean filter | |
| mean_p = boxfilter(p, r) / base | |
| # filter I with p then filter it with the mean filter | |
| means_IP = [boxfilter(I[:, :, i]*p, r) / base for i in range(3)] | |
| # covariance of (I, p) in each local patch | |
| covIP = [means_IP[i] - means[i]*mean_p for i in range(3)] | |
| # variance of I in each local patch: the matrix Sigma in ECCV10 eq.14 | |
| var = defaultdict(dict) | |
| for i, j in combinations_with_replacement(range(3), 2): | |
| var[i][j] = boxfilter(I[:, :, i]*I[:, :, j], r) / base - means[i]*means[j] | |
| a = np.zeros((M, N, 3)) | |
| for y, x in np.ndindex(M, N): | |
| # rr, rg, rb | |
| # Sigma = rg, gg, gb | |
| # rb, gb, bb | |
| Sigma = np.array([[var[B][B][y, x], var[B][G][y, x], var[B][R][y, x]], | |
| [var[B][G][y, x], var[G][G][y, x], var[G][R][y, x]], | |
| [var[B][R][y, x], var[G][R][y, x], var[R][R][y, x]]]) | |
| cov = np.array([c[y, x] for c in covIP]) | |
| a[y, x] = np.dot(cov, inv(Sigma + eps*np.eye(3))) # eq 14 | |
| # ECCV10 eq.15 | |
| b = mean_p - a[:, :, R]*means[R] - a[:, :, G]*means[G] - a[:, :, B]*means[B] | |
| # ECCV10 eq.16 | |
| q = (boxfilter(a[:, :, R], r)*I[:, :, R] + boxfilter(a[:, :, G], r)*I[:, :, G] + boxfilter(a[:, :, B], r)*I[:, :, B] + boxfilter(b, r)) / base | |
| return q |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment