processing.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. from PIL import Image
  2. from matplotlib import cm
  3. import random
  4. from skimage import color
  5. import numpy as np
  6. import ipfml.metrics as metrics
  7. import cv2
  8. from scipy import signal
  9. def get_LAB_L_SVD(image):
  10. """
  11. @brief Returns Singular values from LAB L Image information
  12. @param image - PIL Image or Numpy array
  13. @return U, s, V information obtained from SVD compression using Lab
  14. Usage :
  15. >>> from PIL import Image
  16. >>> from ipfml import processing
  17. >>> img = Image.open('./images/test_img.png')
  18. >>> U, s, V = processing.get_LAB_L_SVD(img)
  19. >>> U.shape
  20. (200, 200)
  21. >>> len(s)
  22. 200
  23. >>> V.shape
  24. (200, 200)
  25. """
  26. L = metrics.get_LAB_L(image)
  27. return metrics.get_SVD(L)
  28. def get_LAB_L_SVD_s(image):
  29. """
  30. @brief Returns s (Singular values) SVD from L of LAB Image information
  31. @param image - PIL Image or numpy array
  32. @return vector of singular values
  33. Usage :
  34. >>> from PIL import Image
  35. >>> from ipfml import processing
  36. >>> img = Image.open('./images/test_img.png')
  37. >>> s = processing.get_LAB_L_SVD_s(img)
  38. >>> len(s)
  39. 200
  40. """
  41. L = metrics.get_LAB_L(image)
  42. return metrics.get_SVD_s(L)
  43. def get_LAB_L_SVD_U(image):
  44. """
  45. @brief Returns U SVD from L of LAB Image information
  46. @param image - PIL Image
  47. @return U matrix of SVD compression
  48. Usage :
  49. >>> from PIL import Image
  50. >>> from ipfml import processing
  51. >>> img = Image.open('./images/test_img.png')
  52. >>> U = processing.get_LAB_L_SVD_U(img)
  53. >>> U.shape
  54. (200, 200)
  55. """
  56. L = metrics.get_LAB_L(image)
  57. return metrics.get_SVD_U(L)
  58. def get_LAB_L_SVD_V(image):
  59. """
  60. @brief Returns V SVD from L of LAB Image information
  61. @param image - PIL Image or numpy array
  62. @return V matrix of SVD compression
  63. Usage :
  64. >>> from PIL import Image
  65. >>> from ipfml import processing
  66. >>> img = Image.open('./images/test_img.png')
  67. >>> V = processing.get_LAB_L_SVD_V(img)
  68. >>> V.shape
  69. (200, 200)
  70. """
  71. L = metrics.get_LAB_L(image)
  72. return metrics.get_SVD_V(L)
  73. def divide_in_blocks(image, block_size, pil=True):
  74. '''
  75. @brief Divide image into equal size blocks
  76. @param image - PIL Image or numpy array
  77. @param block - tuple (width, height) representing the size of each dimension of the block
  78. @param pil - kind block type (PIL by default or Numpy array)
  79. @return list containing all 2D numpy blocks (in RGB or not)
  80. Usage :
  81. >>> import numpy as np
  82. >>> from PIL import Image
  83. >>> from ipfml import processing
  84. >>> from ipfml import metrics
  85. >>> image_values = np.random.randint(255, size=(800, 800, 3))
  86. >>> blocks = divide_in_blocks(image_values, (20, 20))
  87. >>> len(blocks)
  88. 1600
  89. >>> blocks[0].width
  90. 20
  91. >>> blocks[0].height
  92. 20
  93. >>> img_l = Image.open('./images/test_img.png')
  94. >>> L = metrics.get_LAB_L(img_l)
  95. >>> blocks_L = divide_in_blocks(L, (100, 100))
  96. >>> len(blocks_L)
  97. 4
  98. >>> blocks_L[0].width
  99. 100
  100. '''
  101. blocks = []
  102. mode = 'RGB'
  103. # convert in numpy array
  104. image_array = np.array(image)
  105. # check dimension of input image
  106. if image_array.ndim != 3:
  107. mode = 'L'
  108. image_width, image_height = image_array.shape
  109. else:
  110. image_width, image_height, _ = image_array.shape
  111. # check size compatibility
  112. width, height = block_size
  113. if(image_width % width != 0):
  114. raise "Width size issue, block size not compatible"
  115. if(image_height % height != 0):
  116. raise "Height size issue, block size not compatible"
  117. nb_block_width = image_width / width
  118. nb_block_height = image_height / height
  119. for i in range(int(nb_block_width)):
  120. begin_x = i * width
  121. for j in range(int(nb_block_height)):
  122. begin_y = j * height
  123. # getting sub block information
  124. current_block = image_array[begin_x:(begin_x + width), begin_y:(begin_y + height)]
  125. if pil:
  126. blocks.append(Image.fromarray(current_block.astype('uint8'), mode))
  127. else:
  128. blocks.append(current_block)
  129. return blocks
  130. def normalize_arr(arr):
  131. '''
  132. @brief Normalize data of 1D array shape
  133. @param arr - array data of 1D shape
  134. @return Normalized 1D array
  135. Usage :
  136. >>> from ipfml import processing
  137. >>> import numpy as np
  138. >>> arr = np.arange(11)
  139. >>> arr_normalized = processing.normalize_arr(arr)
  140. >>> arr_normalized[1]
  141. 0.1
  142. '''
  143. output_arr = []
  144. max_value = max(arr)
  145. min_value = min(arr)
  146. for v in arr:
  147. output_arr.append((v - min_value) / (max_value - min_value))
  148. return output_arr
  149. def normalize_arr_with_range(arr, min, max):
  150. '''
  151. @brief Normalize data of 1D array shape
  152. @param arr - array data of 1D shape
  153. Usage :
  154. >>> from ipfml import processing
  155. >>> import numpy as np
  156. >>> arr = np.arange(11)
  157. >>> arr_normalized = processing.normalize_arr_with_range(arr, 0, 20)
  158. >>> arr_normalized[1]
  159. 0.05
  160. '''
  161. output_arr = []
  162. for v in arr:
  163. output_arr.append((v - min) / (max - min))
  164. return output_arr
  165. def normalize_2D_arr(arr):
  166. """
  167. @brief Return array normalize from its min and max values
  168. @param arr - 2D numpy array
  169. @return normalized 2D array
  170. Usage :
  171. >>> from PIL import Image
  172. >>> from ipfml import processing
  173. >>> img = Image.open('./images/test_img.png')
  174. >>> img_mscn = processing.rgb_to_mscn(img)
  175. >>> img_normalized = processing.normalize_2D_arr(img_mscn)
  176. >>> img_normalized.shape
  177. (200, 200)
  178. """
  179. # getting min and max value from 2D array
  180. max_value = arr.max(axis=1).max()
  181. min_value = arr.min(axis=1).min()
  182. # normalize each row
  183. output_array = []
  184. width, height = arr.shape
  185. for row_index in range(0, height):
  186. values = arr[row_index, :]
  187. output_array.append(normalize_arr_with_range(values, min_value, max_value))
  188. return np.asarray(output_array)
  189. def rgb_to_mscn(image):
  190. """
  191. @brief Convert RGB Image into Mean Subtracted Contrast Normalized (MSCN)
  192. @param 3D RGB image numpy array or PIL RGB image
  193. Usage :
  194. >>> from PIL import Image
  195. >>> from ipfml import processing
  196. >>> img = Image.open('./images/test_img.png')
  197. >>> img_mscn = processing.rgb_to_mscn(img)
  198. >>> img_mscn.shape
  199. (200, 200)
  200. """
  201. # check if PIL image or not
  202. img_arr = np.array(image)
  203. # convert rgb image to gray
  204. im = np.array(color.rgb2gray(img_arr)*255, 'uint8')
  205. return metrics.gray_to_mscn(im)
  206. def rgb_to_grey_low_bits(image, nb_bits=4):
  207. """
  208. @brief Convert RGB Image into grey image using only 4 low bits values
  209. @param 3D RGB image numpy array or PIL RGB image
  210. @param nb_bits, optional parameter which indicates the number of bits to keep
  211. Usage :
  212. >>> from PIL import Image
  213. >>> from ipfml import processing
  214. >>> img = Image.open('./images/test_img.png')
  215. >>> low_bits_grey_img = processing.rgb_to_grey_low_bits(img, 5)
  216. >>> low_bits_grey_img.shape
  217. (200, 200)
  218. """
  219. img_arr = np.array(image)
  220. grey_block = np.array(color.rgb2gray(img_arr)*255, 'uint8')
  221. return metrics.get_low_bits_img(grey_block, nb_bits)
  222. def rgb_to_LAB_L_low_bits(image, nb_bits=4):
  223. """
  224. @brief Convert RGB Image into Lab L channel image using only 4 low bits values
  225. @param 3D RGB image numpy array or PIL RGB image
  226. @param nb_bits, optional parameter which indicates the number of bits to keep
  227. Usage :
  228. >>> from PIL import Image
  229. >>> from ipfml import processing
  230. >>> img = Image.open('./images/test_img.png')
  231. >>> low_bits_Lab_l_img = processing.rgb_to_LAB_L_low_bits(img, 5)
  232. >>> low_bits_Lab_l_img.shape
  233. (200, 200)
  234. """
  235. L_block = np.asarray(metrics.get_LAB_L(image), 'uint8')
  236. return metrics.get_low_bits_img(L_block, nb_bits)
  237. def rgb_to_LAB_L_bits(image, interval):
  238. """
  239. @brief Returns only bits from LAB L canal specified into the interval
  240. @param image to convert using this interval of bits value to keep
  241. @param interval (begin, end) of bits values
  242. @return Numpy array with reduced values
  243. >>> from PIL import Image
  244. >>> from ipfml import processing
  245. >>> img = Image.open('./images/test_img.png')
  246. >>> bits_Lab_l_img = processing.rgb_to_LAB_L_bits(img, (2, 6))
  247. >>> bits_Lab_l_img.shape
  248. (200, 200)
  249. """
  250. L_block = np.asarray(metrics.get_LAB_L(image), 'uint8')
  251. return metrics.get_bits_img(L_block, interval)