transformations.py 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. # main imports
  2. import os
  3. import numpy as np
  4. # image processing imports
  5. from ipfml.processing import transform, compression
  6. from ipfml.processing import reconstruction
  7. from ipfml.filters import convolution, kernels
  8. from ipfml import utils
  9. import cv2
  10. from skimage.restoration import denoise_nl_means, estimate_sigma
  11. from PIL import Image
  12. def remove_pixel(img, limit):
  13. width, height = img.shape
  14. output = np.zeros((width, height))
  15. for i in range(width):
  16. for j in range(height):
  17. if img[i,j] <= limit:
  18. output[i,j] = img[i,j]
  19. return output
  20. def get_random_value(distribution):
  21. rand = random.uniform(0, 1)
  22. prob_sum = 0.
  23. for id, prob in enumerate(distribution):
  24. prob_sum += prob
  25. if prob_sum >= rand:
  26. return id
  27. return len(distribution) - 1
  28. def distribution_from_data(data):
  29. occurences = np.array([data.count(x) for x in set(data)])
  30. max_occurences = sum(occurences)
  31. return occurences / max_occurences
  32. def fill_image_with_rand_value(img, func, value_to_replace):
  33. width, height = img.shape
  34. output = np.zeros((width, height))
  35. for i in range(width):
  36. for j in range(height):
  37. if img[i,j] == value_to_replace:
  38. output[i, j] = func()
  39. else:
  40. output[i, j] = img[i, j]
  41. return output
  42. def _compute_relative_error(ref_sv, k_sv):
  43. ref = np.sqrt(np.sum(np.square(ref_sv)))
  44. k = np.sqrt(np.sum(np.square(k_sv)))
  45. return k / ref
  46. def _find_n_components(block, e=0.1):
  47. s = transform.get_LAB_L_SVD_s(block)
  48. errors = []
  49. found = False
  50. k_components = None
  51. for i in range(len(s)):
  52. #Ak = reconstruction.svd(img, [0, i])
  53. #error = compute_relative_error_matrix(A, Ak)
  54. error = _compute_relative_error(s, s[i:])
  55. errors.append(error)
  56. if error < e and not found:
  57. k_components = (i + 1)
  58. found = True
  59. return (k_components, errors)
  60. # Transformation class to store transformation method of image and get usefull information
  61. class Transformation():
  62. def __init__(self, _transformation, _param, _size):
  63. self.transformation = _transformation
  64. self.param = _param
  65. self.size = _size
  66. def getTransformedImage(self, img):
  67. if self.transformation == 'svd_reconstruction':
  68. begin, end = list(map(int, self.param.split(',')))
  69. h, w = list(map(int, self.size.split(',')))
  70. img_reconstructed = reconstruction.svd(img, [begin, end])
  71. data_array = np.array(img_reconstructed, 'uint8')
  72. img_array = Image.fromarray(data_array)
  73. img_array.thumbnail((h, w))
  74. data = np.array(img_array)
  75. if self.transformation == 'svd_reconstruction':
  76. begin, end = list(map(int, self.param.split(',')))
  77. h, w = list(map(int, self.size.split(',')))
  78. img_reconstructed = reconstruction.svd(img, [begin, end])
  79. data_array = np.array(img_reconstructed, 'uint8')
  80. img_array = Image.fromarray(data_array)
  81. img_array.thumbnail((h, w))
  82. data = np.array(img_array)
  83. if self.transformation == 'ipca_reconstruction':
  84. n_components, batch_size = list(map(int, self.param.split(',')))
  85. h, w = list(map(int, self.size.split(',')))
  86. img_reconstructed = reconstruction.ipca(img, n_components, batch_size)
  87. data_array = np.array(img_reconstructed, 'uint8')
  88. img_array = Image.fromarray(data_array)
  89. img_array.thumbnail((h, w))
  90. data = np.array(img_array)
  91. if self.transformation == 'fast_ica_reconstruction':
  92. n_components = self.param
  93. h, w = list(map(int, self.size.split(',')))
  94. img_reconstructed = reconstruction.fast_ica(img, n_components)
  95. data_array = np.array(img_reconstructed, 'uint8')
  96. img_array = Image.fromarray(data_array)
  97. img_array.thumbnail((h, w))
  98. data = np.array(img_array)
  99. if self.transformation == 'gini_map':
  100. # kernel size
  101. k_w, k_h = list(map(int, self.param.split(',')))
  102. h, w = list(map(int, self.size.split(',')))
  103. lab_img = transform.get_LAB_L(img)
  104. img_mask = convolution.convolution2D(lab_img, kernels.gini, (k_w, k_h))
  105. # renormalize data
  106. data_array = np.array(img_mask * 255, 'uint8')
  107. img_array = Image.fromarray(data_array)
  108. img_array.thumbnail((h, w))
  109. data = np.array(img_array)
  110. if self.transformation == 'sobel_based_filter':
  111. k_size, p_limit = list(map(int, self.param.split(',')))
  112. h, w = list(map(int, self.size.split(',')))
  113. lab_img = transform.get_LAB_L(img)
  114. weight, height = lab_img.shape
  115. sobelx = cv2.Sobel(lab_img, cv2.CV_64F, 1, 0, ksize=k_size)
  116. sobely = cv2.Sobel(lab_img, cv2.CV_64F, 0, 1,ksize=k_size)
  117. sobel_mag = np.array(np.hypot(sobelx, sobely), 'uint8') # magnitude
  118. sobel_mag_limit = remove_pixel(sobel_mag, p_limit)
  119. # use distribution value of pixel to fill `0` values
  120. sobel_mag_limit_without_0 = [x for x in sobel_mag_limit.reshape((weight*height)) if x != 0]
  121. distribution = distribution_from_data(sobel_mag_limit_without_0)
  122. min_value = int(min(sobel_mag_limit_without_0))
  123. l = lambda: get_random_value(distribution) + min_value
  124. img_reconstructed = fill_image_with_rand_value(sobel_mag_limit, l, 0)
  125. img_reconstructed_norm = utils.normalize_2D_arr(img_reconstructed)
  126. img_reconstructed_norm = np.array(img_reconstructed_norm*255, 'uint8')
  127. sobel_reconstructed = Image.fromarray(img_reconstructed_norm)
  128. sobel_reconstructed.thumbnail((h, w))
  129. data = np.array(sobel_reconstructed)
  130. if self.transformation == 'nl_mean_noise_mask':
  131. patch_size, patch_distance = list(map(int, self.param.split(',')))
  132. h, w = list(map(int, self.size.split(',')))
  133. img = np.array(img)
  134. sigma_est = np.mean(estimate_sigma(img, multichannel=True))
  135. patch_kw = dict(patch_size=patch_size, # 5x5 patches
  136. patch_distance=patch_distance, # 13x13 search area
  137. multichannel=True)
  138. # slow algorithm
  139. denoise = denoise_nl_means(img, h=0.8 * sigma_est, sigma=sigma_est,
  140. fast_mode=False,
  141. **patch_kw)
  142. denoise = np.array(denoise, 'uint8')
  143. noise_mask = np.abs(denoise - img)
  144. data_array = np.array(noise_mask, 'uint8')
  145. img_array = Image.fromarray(data_array)
  146. img_array.thumbnail((h, w))
  147. data = np.array(img_array)
  148. if self.transformation == 'static':
  149. # static content, we keep input as it is
  150. data = img
  151. return data
  152. def getTransformationPath(self):
  153. path = self.transformation
  154. if self.transformation == 'svd_reconstruction':
  155. begin, end = list(map(int, self.param.split(',')))
  156. w, h = list(map(int, self.size.split(',')))
  157. path = os.path.join(path, str(begin) + '_' + str(end) + '_S_' + str(w) + '_' + str(h))
  158. if self.transformation == 'gini_map':
  159. k_w, k_h = list(map(int, self.param.split(',')))
  160. w, h = list(map(int, self.size.split(',')))
  161. path = os.path.join(path, str(k_w) + '_' + str(k_h) + '_S_' + str(w) + '_' + str(h))
  162. if self.transformation == 'ipca_reconstruction':
  163. n_components, batch_size = list(map(int, self.param.split(',')))
  164. w, h = list(map(int, self.size.split(',')))
  165. path = os.path.join(path, 'N' + str(n_components) + '_' + str(batch_size) + '_S_' + str(w) + '_' + str(h))
  166. if self.transformation == 'fast_ica_reconstruction':
  167. n_components = self.param
  168. w, h = list(map(int, self.size.split(',')))
  169. path = os.path.join(path, 'N' + str(n_components) + '_S_' + str(w) + '_' + str(h))
  170. if self.transformation == 'min_diff_filter':
  171. w_size, h_size, stride = list(map(int, self.param.split(',')))
  172. w, h = list(map(int, self.size.split(',')))
  173. path = os.path.join(path, 'W_' + str(w_size) + '_' + str(h_size) + '_Stride_' + str(stride) + '_S_' + str(w) + '_' + str(h))
  174. if self.transformation == 'sobel_based_filter':
  175. k_size, p_limit = list(map(int, self.param.split(',')))
  176. h, w = list(map(int, self.size.split(',')))
  177. path = os.path.join(path, 'K_' + str(k_size) + '_L' + str(p_limit) + '_S_' + str(w) + '_' + str(h))
  178. if self.transformation == 'nl_mean_noise_mask':
  179. patch_size, patch_distance = list(map(int, self.param.split(',')))
  180. h, w = list(map(int, self.size.split(',')))
  181. path = os.path.join(path, 'S' + str(patch_size) + '_D' + str(patch_distance) + '_S_' + str(w) + '_' + str(h))
  182. if self.transformation == 'static':
  183. # param contains image name to find for each scene
  184. path = self.param
  185. return path
  186. def getName(self):
  187. return self.transformation
  188. def getParam(self):
  189. return self.param
  190. def __str__( self ):
  191. return self.transformation + ' transformation with parameter : ' + self.param