processing.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. """
  2. Functions to quickly extract reduced information from image
  3. """
  4. from PIL import Image
  5. import random
  6. import cv2
  7. from skimage import transform, color
  8. import numpy as np
  9. import ipfml.metrics as metrics
  10. from ipfml import exceptions
  11. from scipy import signal
  12. def get_LAB_L_SVD(image):
  13. """Returns Singular values from LAB L Image information
  14. Args:
  15. image: PIL Image or Numpy array
  16. Returns:
  17. U, s, V information obtained from SVD compression using Lab
  18. Example:
  19. >>> from PIL import Image
  20. >>> from ipfml import processing
  21. >>> img = Image.open('./images/test_img.png')
  22. >>> U, s, V = processing.get_LAB_L_SVD(img)
  23. >>> U.shape
  24. (200, 200)
  25. >>> len(s)
  26. 200
  27. >>> V.shape
  28. (200, 200)
  29. """
  30. L = metrics.get_LAB_L(image)
  31. return metrics.get_SVD(L)
  32. def get_LAB_L_SVD_s(image):
  33. """Returns s (Singular values) SVD from L of LAB Image information
  34. Args:
  35. image: PIL Image or Numpy array
  36. Returns:
  37. vector of singular values
  38. Example:
  39. >>> from PIL import Image
  40. >>> from ipfml import processing
  41. >>> img = Image.open('./images/test_img.png')
  42. >>> s = processing.get_LAB_L_SVD_s(img)
  43. >>> len(s)
  44. 200
  45. """
  46. L = metrics.get_LAB_L(image)
  47. return metrics.get_SVD_s(L)
  48. def get_LAB_L_SVD_U(image):
  49. """Returns U SVD from L of LAB Image information
  50. Args:
  51. image: PIL Image or Numpy array
  52. Returns:
  53. U matrix of SVD compression
  54. Example:
  55. >>> from PIL import Image
  56. >>> from ipfml import processing
  57. >>> img = Image.open('./images/test_img.png')
  58. >>> U = processing.get_LAB_L_SVD_U(img)
  59. >>> U.shape
  60. (200, 200)
  61. """
  62. L = metrics.get_LAB_L(image)
  63. return metrics.get_SVD_U(L)
  64. def get_LAB_L_SVD_V(image):
  65. """Returns V SVD from L of LAB Image information
  66. Args:
  67. image: PIL Image or Numpy array
  68. Returns:
  69. V matrix of SVD compression
  70. Example:
  71. >>> from PIL import Image
  72. >>> from ipfml import processing
  73. >>> img = Image.open('./images/test_img.png')
  74. >>> V = processing.get_LAB_L_SVD_V(img)
  75. >>> V.shape
  76. (200, 200)
  77. """
  78. L = metrics.get_LAB_L(image)
  79. return metrics.get_SVD_V(L)
  80. def rgb_to_mscn(image):
  81. """Convert RGB Image into Mean Subtracted Contrast Normalized (MSCN)
  82. Args:
  83. image: 3D RGB image Numpy array or PIL RGB image
  84. Returns:
  85. 2D Numpy array with MSCN information
  86. Example:
  87. >>> from PIL import Image
  88. >>> from ipfml import processing
  89. >>> img = Image.open('./images/test_img.png')
  90. >>> img_mscn = processing.rgb_to_mscn(img)
  91. >>> img_mscn.shape
  92. (200, 200)
  93. """
  94. # check if PIL image or not
  95. img_arr = np.array(image)
  96. # convert rgb image to gray
  97. im = np.array(color.rgb2gray(img_arr) * 255, 'uint8')
  98. return metrics.gray_to_mscn(im)
  99. def rgb_to_grey_low_bits(image, nb_bits=4):
  100. """Convert RGB Image into grey image using only 4 low bits values
  101. Args:
  102. image: 3D RGB image Numpy array or PIL RGB image
  103. nb_bits: optional parameter which indicates the number of bits to keep (default 4)
  104. Returns:
  105. 2D Numpy array with low bits information kept
  106. Example:
  107. >>> from PIL import Image
  108. >>> from ipfml import processing
  109. >>> img = Image.open('./images/test_img.png')
  110. >>> low_bits_grey_img = processing.rgb_to_grey_low_bits(img, 5)
  111. >>> low_bits_grey_img.shape
  112. (200, 200)
  113. """
  114. img_arr = np.array(image)
  115. grey_block = np.array(color.rgb2gray(img_arr) * 255, 'uint8')
  116. return metrics.get_low_bits_img(grey_block, nb_bits)
  117. def rgb_to_LAB_L_low_bits(image, nb_bits=4):
  118. """Convert RGB Image into Lab L channel image using only 4 low bits values
  119. Args:
  120. image: 3D RGB image Numpy array or PIL RGB image
  121. nb_bits: optional parameter which indicates the number of bits to keep (default 4)
  122. Returns:
  123. 2D Numpy array with low bits information kept
  124. Example:
  125. >>> from PIL import Image
  126. >>> from ipfml import processing
  127. >>> img = Image.open('./images/test_img.png')
  128. >>> low_bits_Lab_l_img = processing.rgb_to_LAB_L_low_bits(img, 5)
  129. >>> low_bits_Lab_l_img.shape
  130. (200, 200)
  131. """
  132. L_block = np.asarray(metrics.get_LAB_L(image), 'uint8')
  133. return metrics.get_low_bits_img(L_block, nb_bits)
  134. def rgb_to_LAB_L_bits(image, interval):
  135. """Returns only bits from LAB L canal specified into the interval
  136. Args:
  137. image: image to convert using this interval of bits value to keep
  138. interval: (begin, end) of bits values
  139. Returns:
  140. 2D Numpy array with reduced values
  141. >>> from PIL import Image
  142. >>> from ipfml import processing
  143. >>> img = Image.open('./images/test_img.png')
  144. >>> bits_Lab_l_img = processing.rgb_to_LAB_L_bits(img, (2, 6))
  145. >>> bits_Lab_l_img.shape
  146. (200, 200)
  147. """
  148. L_block = np.asarray(metrics.get_LAB_L(image), 'uint8')
  149. return metrics.get_bits_img(L_block, interval)
  150. def divide_in_blocks(image, block_size, pil=True):
  151. '''Divide image into equal size blocks
  152. Args:
  153. image: PIL Image or Numpy array
  154. block: tuple (width, height) representing the size of each dimension of the block
  155. pil: block type returned as PIL Image (default True)
  156. Returns:
  157. list containing all 2D Numpy blocks (in RGB or not)
  158. Raises:
  159. ValueError: If `image_width` or `image_height` are not compatible to produce correct block sizes
  160. Example:
  161. >>> import numpy as np
  162. >>> from PIL import Image
  163. >>> from ipfml import processing
  164. >>> from ipfml import metrics
  165. >>> image_values = np.random.randint(255, size=(800, 800, 3))
  166. >>> blocks = divide_in_blocks(image_values, (20, 20))
  167. >>> len(blocks)
  168. 1600
  169. >>> blocks[0].width
  170. 20
  171. >>> blocks[0].height
  172. 20
  173. >>> img_l = Image.open('./images/test_img.png')
  174. >>> L = metrics.get_LAB_L(img_l)
  175. >>> blocks_L = divide_in_blocks(L, (100, 100))
  176. >>> len(blocks_L)
  177. 4
  178. >>> blocks_L[0].width
  179. 100
  180. '''
  181. blocks = []
  182. mode = 'RGB'
  183. # convert in Numpy array
  184. image_array = np.array(image)
  185. # check dimension of input image
  186. if image_array.ndim != 3:
  187. mode = 'L'
  188. image_width, image_height = image_array.shape
  189. else:
  190. image_width, image_height, _ = image_array.shape
  191. # check size compatibility
  192. width, height = block_size
  193. if (image_width % width != 0):
  194. raise ValueError("Width size issue, block size not compatible")
  195. if (image_height % height != 0):
  196. raise ValueError("Height size issue, block size not compatible")
  197. nb_block_width = image_width / width
  198. nb_block_height = image_height / height
  199. for i in range(int(nb_block_width)):
  200. begin_x = i * width
  201. for j in range(int(nb_block_height)):
  202. begin_y = j * height
  203. # getting sub block information
  204. current_block = image_array[begin_x:(begin_x + width), begin_y:(
  205. begin_y + height)]
  206. if pil:
  207. blocks.append(
  208. Image.fromarray(current_block.astype('uint8'), mode))
  209. else:
  210. blocks.append(current_block)
  211. return blocks
  212. def fusion_images(images, pil=True):
  213. '''Fusion array of images into single image
  214. Args:
  215. images: array of images (PIL Image or Numpy array)
  216. pil: block type returned as PIL Image (default True)
  217. Returns:
  218. merged image from array of images
  219. Raises:
  220. ValueError: if `images` is not an array or is empty
  221. NumpyShapeComparisonException: if `images` array contains images with different shapes
  222. Example:
  223. >>> import numpy as np
  224. >>> from ipfml import processing
  225. >>> image_values_1 = np.random.randint(255, size=(800, 800, 3))
  226. >>> image_values_2 = np.random.randint(255, size=(800, 800, 3))
  227. >>> merged_image = processing.fusion_images([image_values_1, image_values_2], pil=False)
  228. >>> merged_image.shape
  229. (800, 800, 3)
  230. '''
  231. mode = 'RGB'
  232. dim = 1
  233. if len(images) == 0:
  234. raise ValueError('Empty array of images provided...')
  235. # convert image in numpy array (perhaps not necessary)
  236. images = [np.asarray(img) for img in images]
  237. image_array = images[0]
  238. if image_array.ndim != 3:
  239. mode = 'L'
  240. width, height = image_array.shape
  241. else:
  242. width, height, dim = image_array.shape
  243. # raise exception if all images do not have same shape
  244. if not np.array([image_array.shape == a.shape for a in images]).all():
  245. raise NumpyShapeComparisonException()
  246. if dim == 1:
  247. image_mean = np.empty([width, height])
  248. else:
  249. image_mean = np.empty([width, height, dim])
  250. nb_images = len(images)
  251. # construction of mean image from rotation
  252. for i in range(width):
  253. for j in range(height):
  254. if dim == 1:
  255. grey_value = 0
  256. # for each image we merge pixel values
  257. for img in images:
  258. grey_value += img[i][j]
  259. image_mean[i][j] = grey_value / nb_images
  260. else:
  261. for k in range(dim):
  262. canal_value = 0
  263. # for each image we merge pixel values
  264. for img in images:
  265. canal_value += img[i][j][k]
  266. image_mean[i][j][k] = canal_value / nb_images
  267. image_mean = np.array(image_mean, 'uint8')
  268. if pil:
  269. return Image.fromarray(image_mean, mode)
  270. else:
  271. return image_mean
  272. def rotate_image(image, angle=90, pil=True):
  273. """Rotate image using specific angle
  274. Args:
  275. image: PIL Image or Numpy array
  276. angle: Angle value of the rotation
  277. pil: block type returned as PIL Image (default True)
  278. Returns:
  279. Image with rotation applied
  280. Example:
  281. >>> from PIL import Image
  282. >>> import numpy as np
  283. >>> from ipfml import processing
  284. >>> image_values = Image.open('./images/test_img.png')
  285. >>> rotated_image = processing.rotate_image(image_values, 90, pil=False)
  286. >>> rotated_image.shape
  287. (200, 200, 3)
  288. """
  289. mode = 'RGB'
  290. image_array = np.asarray(image)
  291. if image_array.ndim != 3:
  292. mode = 'L'
  293. rotated_image = np.array(
  294. transform.rotate(image_array, angle) * 255, 'uint8')
  295. if pil:
  296. return Image.fromarray(rotated_image, mode)
  297. else:
  298. return rotated_image