transform.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. """
  2. Functions which can be used to extract information from image or reduce it
  3. """
  4. # main imports
  5. import os
  6. import random
  7. import numpy as np
  8. # image processing imports
  9. from numpy.linalg import svd
  10. from scipy import misc
  11. from sklearn import preprocessing
  12. from skimage import io, color
  13. import cv2
  14. from PIL import Image
  15. # ipfml imports
  16. from ipfml.processing import compression
  17. def get_LAB(image):
  18. """Transforms RGB Image into Lab
  19. Args:
  20. image: image to convert
  21. Returns:
  22. Lab information
  23. Usage:
  24. >>> from PIL import Image
  25. >>> from ipfml.processing import transform
  26. >>> img = Image.open('./images/test_img.png')
  27. >>> Lab = transform.get_LAB(img)
  28. >>> Lab.shape
  29. (200, 200, 3)
  30. """
  31. return color.rgb2lab(image)
  32. def get_LAB_L(image):
  33. """Transforms RGB Image into Lab and returns L
  34. Args:
  35. image: image to convert
  36. Returns:
  37. The L chanel from Lab information
  38. >>> from PIL import Image
  39. >>> from ipfml.processing import transform
  40. >>> img = Image.open('./images/test_img.png')
  41. >>> L = transform.get_LAB_L(img)
  42. >>> L.shape
  43. (200, 200)
  44. """
  45. lab = get_LAB(image)
  46. return lab[:, :, 0]
  47. def get_LAB_a(image):
  48. """Transforms RGB Image into LAB and returns a
  49. Args:
  50. image: image to convert
  51. Returns:
  52. The a chanel from Lab information
  53. Usage:
  54. >>> from PIL import Image
  55. >>> from ipfml.processing import transform
  56. >>> img = Image.open('./images/test_img.png')
  57. >>> a = transform.get_LAB_a(img)
  58. >>> a.shape
  59. (200, 200)
  60. """
  61. lab = get_LAB(image)
  62. return lab[:, :, 1]
  63. def get_LAB_b(image):
  64. """Transforms RGB Image into LAB and returns b
  65. Args:
  66. image: image to convert
  67. Returns:
  68. The b chanel from Lab information
  69. Usage :
  70. >>> from PIL import Image
  71. >>> from ipfml.processing import transform
  72. >>> img = Image.open('./images/test_img.png')
  73. >>> b = transform.get_LAB_b(img)
  74. >>> b.shape
  75. (200, 200)
  76. """
  77. lab = get_LAB(image)
  78. return lab[:, :, 2]
  79. def get_XYZ(image):
  80. """Transforms RGB Image into XYZ
  81. Args:
  82. image: image to convert
  83. Returns:
  84. XYZ information obtained from transformation
  85. Usage:
  86. >>> from PIL import Image
  87. >>> from ipfml.processing import transform
  88. >>> img = Image.open('./images/test_img.png')
  89. >>> transform.get_XYZ(img).shape
  90. (200, 200, 3)
  91. """
  92. return color.rgb2xyz(image)
  93. def get_XYZ_X(image):
  94. """Transforms RGB Image into XYZ and returns X
  95. Args:
  96. image: image to convert
  97. Returns:
  98. The X chanel from XYZ information
  99. Usage:
  100. >>> from PIL import Image
  101. >>> from ipfml.processing import transform
  102. >>> img = Image.open('./images/test_img.png')
  103. >>> x = transform.get_XYZ_X(img)
  104. >>> x.shape
  105. (200, 200)
  106. """
  107. xyz = color.rgb2xyz(image)
  108. return xyz[:, :, 0]
  109. def get_XYZ_Y(image):
  110. """Transforms RGB Image into XYZ and returns Y
  111. Args:
  112. image: image to convert
  113. Returns:
  114. The Y chanel from XYZ information
  115. Usage:
  116. >>> from PIL import Image
  117. >>> from ipfml.processing import transform
  118. >>> img = Image.open('./images/test_img.png')
  119. >>> y = transform.get_XYZ_Y(img)
  120. >>> y.shape
  121. (200, 200)
  122. """
  123. xyz = color.rgb2xyz(image)
  124. return xyz[:, :, 1]
  125. def get_XYZ_Z(image):
  126. """Transforms RGB Image into XYZ and returns Z
  127. Args:
  128. image: image to convert
  129. Returns:
  130. The Z chanel from XYZ information
  131. Raises:
  132. ValueError: If `nb_bits` has unexpected value. `nb_bits` needs to be in interval [1, 8].
  133. Usage:
  134. >>> from PIL import Image
  135. >>> from ipfml.processing import transform
  136. >>> img = Image.open('./images/test_img.png')
  137. >>> z = transform.get_XYZ_Z(img)
  138. >>> z.shape
  139. (200, 200)
  140. """
  141. xyz = color.rgb2xyz(image)
  142. return xyz[:, :, 2]
  143. def get_low_bits_img(image, nb_bits=4):
  144. """Returns Image or Numpy array with data information reduced using only low bits
  145. Args:
  146. image: image to convert
  147. nb_bits: optional parameter which indicates the number of bits to keep
  148. Returns:
  149. Numpy array with reduced values
  150. Usage:
  151. >>> from PIL import Image
  152. >>> from ipfml.processing import transform
  153. >>> img = Image.open('./images/test_img.png')
  154. >>> low_bits_img = transform.get_low_bits_img(img, 5)
  155. >>> low_bits_img.shape
  156. (200, 200, 3)
  157. """
  158. if nb_bits <= 0:
  159. raise ValueError(
  160. "unexpected value of number of bits to keep. @nb_bits needs to be positive and greater than 0."
  161. )
  162. if nb_bits > 8:
  163. raise ValueError(
  164. "Unexpected value of number of bits to keep. @nb_bits needs to be in interval [1, 8]."
  165. )
  166. img_arr = np.array(image)
  167. bits_values = sum([pow(2, i - 1) for i in range(1, nb_bits + 1)])
  168. return img_arr & bits_values
  169. def get_bits_img(image, interval):
  170. """Returns only bits specified into the interval
  171. Args:
  172. image: image to convert using this interval of bits value to keep
  173. interval: (begin, end) of bits values
  174. Returns:
  175. Numpy array with reduced values
  176. Raises:
  177. ValueError: If min value from interval is not >= 1.
  178. ValueError: If max value from interval is not <= 8.
  179. ValueError: If min value from interval >= max value.
  180. Usage:
  181. >>> from PIL import Image
  182. >>> from ipfml.processing import transform
  183. >>> img = Image.open('./images/test_img.png')
  184. >>> bits_img = transform.get_bits_img(img, (2, 5))
  185. >>> bits_img.shape
  186. (200, 200, 3)
  187. """
  188. img_arr = np.array(image)
  189. begin, end = interval
  190. if begin < 1:
  191. raise ValueError(
  192. "Unexpected value of interval. Interval min value needs to be >= 1."
  193. )
  194. if end > 8:
  195. raise ValueError(
  196. "Unexpected value of interval. Interval min value needs to be <= 8."
  197. )
  198. if begin >= end:
  199. raise ValueError("Unexpected interval values order.")
  200. bits_values = sum([pow(2, i - 1) for i in range(begin, end + 1)])
  201. return img_arr & bits_values
  202. def gray_to_mscn(image):
  203. """Convert Grayscale Image into Mean Subtracted Contrast Normalized (MSCN)
  204. Args:
  205. image: grayscale image
  206. Returns:
  207. MSCN matrix obtained from transformation
  208. Usage:
  209. >>> from PIL import Image
  210. >>> from ipfml.processing import transform
  211. >>> img = Image.open('./images/test_img.png')
  212. >>> img = transform.get_LAB_L(img)
  213. >>> img_mscn = transform.gray_to_mscn(img)
  214. >>> img_mscn.shape
  215. (200, 200)
  216. """
  217. s = 7 / 6
  218. blurred = cv2.GaussianBlur(image, (7, 7),
  219. s) # apply gaussian blur to the image
  220. blurred_sq = blurred * blurred
  221. sigma = cv2.GaussianBlur(image * image, (7, 7), s)
  222. sigma = abs(sigma - blurred_sq)**0.5
  223. sigma = sigma + 1.0 / 255 # avoid DivideByZero Exception
  224. mscn = (image - blurred) / sigma # MSCN(i, j) image
  225. return mscn
  226. def rgb_to_mscn(image):
  227. """Convert RGB Image into Mean Subtracted Contrast Normalized (MSCN)
  228. Args:
  229. image: 3D RGB image Numpy array or PIL RGB image
  230. Returns:
  231. 2D Numpy array with MSCN information
  232. Example:
  233. >>> from PIL import Image
  234. >>> from ipfml.processing import transform
  235. >>> img = Image.open('./images/test_img.png')
  236. >>> img_mscn = transform.rgb_to_mscn(img)
  237. >>> img_mscn.shape
  238. (200, 200)
  239. """
  240. # check if PIL image or not
  241. img_arr = np.array(image)
  242. # convert rgb image to gray
  243. im = np.array(color.rgb2gray(img_arr) * 255, 'uint8')
  244. return gray_to_mscn(im)
  245. def get_mscn_coefficients(image):
  246. """Compute the Mean Substracted Constrast Normalized coefficients of an image
  247. Args:
  248. image: PIL Image, Numpy array or path of image
  249. Returns:
  250. MSCN coefficients
  251. Raises:
  252. FileNotFoundError: If `image` is set as str path and image was not found
  253. ValueError: If `image` numpy shape are not correct
  254. Example:
  255. >>> from PIL import Image
  256. >>> import numpy as np
  257. >>> from ipfml.processing import transform
  258. >>> image_values = Image.open('./images/test_img.png')
  259. >>> mscn_coefficients = transform.get_mscn_coefficients(image_values)
  260. >>> mscn_coefficients.shape
  261. (200, 200)
  262. """
  263. if isinstance(image, str):
  264. if os.path.exists(image):
  265. # open image directly as grey level image
  266. imdist = cv2.imread(image, 0)
  267. else:
  268. raise FileNotFoundError('Image not found in your system')
  269. elif isinstance(image, np.ndarray):
  270. # convert if necessary to grey level numpy array
  271. if image.ndim == 2:
  272. imdist = image
  273. if image.ndim == 3:
  274. imdist = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  275. else:
  276. raise ValueError('Incorrect image shape')
  277. else:
  278. # if PIL Image
  279. image = np.asarray(image)
  280. if image.ndim == 2:
  281. imdist = image
  282. if image.ndim == 3:
  283. imdist = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  284. else:
  285. raise ValueError('Incorrect image shape')
  286. imdist = imdist.astype(np.float64)
  287. imdist = imdist / 255.0
  288. # calculating MSCN coefficients
  289. mu = cv2.GaussianBlur(
  290. imdist, (7, 7), 7 / 6, borderType=cv2.BORDER_CONSTANT)
  291. mu_sq = mu * mu
  292. sigma = cv2.GaussianBlur(
  293. imdist * imdist, (7, 7), 7 / 6, borderType=cv2.BORDER_CONSTANT)
  294. sigma = np.sqrt(abs((sigma - mu_sq)))
  295. structdis = (imdist - mu) / (sigma + 1)
  296. return structdis
  297. def get_LAB_L_SVD(image):
  298. """Returns Singular values from LAB L Image information
  299. Args:
  300. image: PIL Image or Numpy array
  301. Returns:
  302. U, s, V information obtained from SVD compression using Lab
  303. Example:
  304. >>> from PIL import Image
  305. >>> from ipfml.processing import transform
  306. >>> img = Image.open('./images/test_img.png')
  307. >>> U, s, V = transform.get_LAB_L_SVD(img)
  308. >>> U.shape
  309. (200, 200)
  310. >>> len(s)
  311. 200
  312. >>> V.shape
  313. (200, 200)
  314. """
  315. L = get_LAB_L(image)
  316. return compression.get_SVD(L)
  317. def get_LAB_L_SVD_s(image):
  318. """Returns s (Singular values) SVD from L of LAB Image information
  319. Args:
  320. image: PIL Image or Numpy array
  321. Returns:
  322. vector of singular values
  323. Example:
  324. >>> from PIL import Image
  325. >>> from ipfml.processing import transform
  326. >>> img = Image.open('./images/test_img.png')
  327. >>> s = transform.get_LAB_L_SVD_s(img)
  328. >>> len(s)
  329. 200
  330. """
  331. L = get_LAB_L(image)
  332. return compression.get_SVD_s(L)
  333. def get_LAB_L_SVD_U(image):
  334. """Returns U SVD from L of LAB Image information
  335. Args:
  336. image: PIL Image or Numpy array
  337. Returns:
  338. U matrix of SVD compression
  339. Example:
  340. >>> from PIL import Image
  341. >>> from ipfml.processing import transform
  342. >>> img = Image.open('./images/test_img.png')
  343. >>> U = transform.get_LAB_L_SVD_U(img)
  344. >>> U.shape
  345. (200, 200)
  346. """
  347. L = get_LAB_L(image)
  348. return compression.get_SVD_U(L)
  349. def get_LAB_L_SVD_V(image):
  350. """Returns V SVD from L of LAB Image information
  351. Args:
  352. image: PIL Image or Numpy array
  353. Returns:
  354. V matrix of SVD compression
  355. Example:
  356. >>> from PIL import Image
  357. >>> from ipfml.processing import transform
  358. >>> img = Image.open('./images/test_img.png')
  359. >>> V = transform.get_LAB_L_SVD_V(img)
  360. >>> V.shape
  361. (200, 200)
  362. """
  363. L = get_LAB_L(image)
  364. return compression.get_SVD_V(L)
  365. def rgb_to_grey_low_bits(image, nb_bits=4):
  366. """Convert RGB Image into grey image using only 4 low bits values
  367. Args:
  368. image: 3D RGB image Numpy array or PIL RGB image
  369. nb_bits: optional parameter which indicates the number of bits to keep (default 4)
  370. Returns:
  371. 2D Numpy array with low bits information kept
  372. Example:
  373. >>> from PIL import Image
  374. >>> from ipfml.processing import transform
  375. >>> img = Image.open('./images/test_img.png')
  376. >>> low_bits_grey_img = transform.rgb_to_grey_low_bits(img, 5)
  377. >>> low_bits_grey_img.shape
  378. (200, 200)
  379. """
  380. img_arr = np.array(image)
  381. grey_block = np.array(color.rgb2gray(img_arr) * 255, 'uint8')
  382. return get_low_bits_img(grey_block, nb_bits)
  383. def rgb_to_LAB_L_low_bits(image, nb_bits=4):
  384. """Convert RGB Image into Lab L channel image using only 4 low bits values
  385. Args:
  386. image: 3D RGB image Numpy array or PIL RGB image
  387. nb_bits: optional parameter which indicates the number of bits to keep (default 4)
  388. Returns:
  389. 2D Numpy array with low bits information kept
  390. Example:
  391. >>> from PIL import Image
  392. >>> from ipfml.processing import transform
  393. >>> img = Image.open('./images/test_img.png')
  394. >>> low_bits_Lab_l_img = transform.rgb_to_LAB_L_low_bits(img, 5)
  395. >>> low_bits_Lab_l_img.shape
  396. (200, 200)
  397. """
  398. L_block = np.asarray(get_LAB_L(image), 'uint8')
  399. return get_low_bits_img(L_block, nb_bits)
  400. def rgb_to_LAB_L_bits(image, interval):
  401. """Returns only bits from LAB L canal specified into the interval
  402. Args:
  403. image: image to convert using this interval of bits value to keep
  404. interval: (begin, end) of bits values
  405. Returns:
  406. 2D Numpy array with reduced values
  407. >>> from PIL import Image
  408. >>> from ipfml.processing import transform
  409. >>> img = Image.open('./images/test_img.png')
  410. >>> bits_Lab_l_img = transform.rgb_to_LAB_L_bits(img, (2, 6))
  411. >>> bits_Lab_l_img.shape
  412. (200, 200)
  413. """
  414. L_block = np.asarray(get_LAB_L(image), 'uint8')
  415. return get_bits_img(L_block, interval)