noise.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. """
  2. Noise filters to apply on images
  3. """
  4. import numpy as np
  5. import random
  6. from ipfml import processing
  7. def _normalise(x):
  8. if isinstance(x, np.ndarray):
  9. return np.array(list(map(_normalise, x)))
  10. if x > 255:
  11. return 255
  12. if x < 0:
  13. return 0
  14. return x
  15. def _global_noise_filter(image, generator, updator, identical=False):
  16. """White noise filter to apply on image
  17. Args:
  18. image: image used as input (2D or 3D image representation)
  19. generator: lambda function used to generate random numpy array with specific distribution
  20. updator: lambda function used to update pixel value
  21. identical: keep or not identical noise distribution for each canal if RGB Image (default False)
  22. Returns:
  23. 2D Numpy array with specified noise applied
  24. Example:
  25. >>> from ipfml.filters.noise import _global_noise_filter as gf
  26. >>> import numpy as np
  27. >>> image = np.random.uniform(0, 255, 10000).reshape((100, 100))
  28. >>> generator = lambda h, w: np.random.uniform(-0.5, 0.5, (h, w))
  29. >>> n = 10
  30. >>> k = 0.2
  31. >>> updator = lambda x, noise: x + n * k * noise
  32. >>> noisy_image = gf(image, generator, updator)
  33. >>> noisy_image.shape
  34. (100, 100)
  35. """
  36. image_array = np.asarray(image)
  37. nb_chanel = 1
  38. if image_array.ndim != 3:
  39. height, width = image_array.shape
  40. else:
  41. height, width, nb_chanel = image_array.shape
  42. if nb_chanel == 1 or identical:
  43. noise_filter = generator(height, width)
  44. # final output numpy array
  45. output_array = []
  46. # check number of chanel
  47. if nb_chanel == 1:
  48. noisy_image = np.array(list(map(updator, image_array, noise_filter)))
  49. # normalise values
  50. return np.array(list(map(_normalise, noisy_image)), 'uint8')
  51. else:
  52. # final output numpy array
  53. output_array = []
  54. for chanel in range(0, nb_chanel):
  55. # getting flatten information from image and noise
  56. image_array_chanel = image_array[:, :, chanel]
  57. # redefine noise if necessary
  58. if not identical:
  59. noise_filter = generator(height, width)
  60. # compute new pixel value
  61. # x + n * k * white_noise_filter[i] as example
  62. noisy_image = np.array(
  63. list(map(updator, image_array_chanel, noise_filter)))
  64. # normalise values
  65. noisy_image = np.array(list(map(_normalise, noisy_image)), 'uint8')
  66. # in order to concatenate output array
  67. noisy_image = noisy_image[:, :, np.newaxis]
  68. # append new chanel
  69. output_array.append(noisy_image)
  70. # concatenate RGB image
  71. output_array = np.concatenate(output_array, axis=2)
  72. return output_array
  73. def white_noise(image,
  74. n,
  75. identical=False,
  76. distribution_interval=(-0.5, 0.5),
  77. k=0.2):
  78. """White noise filter to apply on image
  79. Args:
  80. image: image used as input (2D or 3D image representation)
  81. n: used to set importance of noise [1, 999]
  82. identical: keep or not identical noise distribution for each canal if RGB Image (default False)
  83. distribution_interval: set the distribution interval of normal law distribution (default (-0.5, 0.5))
  84. k: variable that specifies the amount of noise to be taken into account in the output image (default 0.2)
  85. Returns:
  86. 2D Numpy array with white noise applied
  87. Example:
  88. >>> from ipfml.filters.noise import white_noise
  89. >>> import numpy as np
  90. >>> image = np.random.uniform(0, 255, 10000).reshape((100, 100))
  91. >>> noisy_image = white_noise(image, 10)
  92. >>> noisy_image.shape
  93. (100, 100)
  94. """
  95. a, b = distribution_interval
  96. generator = lambda h, w: np.random.uniform(a, b, (h, w))
  97. updator = lambda x, noise: x + n * k * noise
  98. return _global_noise_filter(image, generator, updator, identical)
  99. def gaussian_noise(image,
  100. n,
  101. identical=False,
  102. distribution_interval=(0, 1),
  103. k=0.1):
  104. """Gaussian noise filter to apply on image
  105. Args:
  106. image: image used as input (2D or 3D image representation)
  107. n: used to set importance of noise [1, 999]
  108. identical: keep or not identical noise distribution for each canal if RGB Image (default False)
  109. distribution_interval: set the distribution interval of normal law distribution (default (0, 1))
  110. k: variable that specifies the amount of noise to be taken into account in the output image (default 0.1)
  111. Returns:
  112. 2D Numpy array with gaussian noise applied
  113. Example:
  114. >>> from ipfml.filters.noise import gaussian_noise
  115. >>> import numpy as np
  116. >>> image = np.random.uniform(0, 255, 10000).reshape((100, 100))
  117. >>> noisy_image = gaussian_noise(image, 10)
  118. >>> noisy_image.shape
  119. (100, 100)
  120. """
  121. a, b = distribution_interval
  122. generator = lambda h, w: np.random.normal(a, b, (h, w))
  123. updator = lambda x, noise: x + n * k * noise
  124. return _global_noise_filter(image, generator, updator, identical)
  125. def laplace_noise(image,
  126. n,
  127. identical=False,
  128. distribution_interval=(0, 1),
  129. k=0.1):
  130. """Laplace noise filter to apply on image
  131. Args:
  132. image: image used as input (2D or 3D image representation)
  133. n: used to set importance of noise [1, 999]
  134. identical: keep or not identical noise distribution for each canal if RGB Image (default False)
  135. distribution_interval: set the distribution interval of normal law distribution (default (0, 1))
  136. k: variable that specifies the amount of noise to be taken into account in the output image (default 0.1)
  137. Returns:
  138. 2D Numpay array with Laplace noise applied
  139. Example:
  140. >>> from ipfml.filters.noise import laplace_noise
  141. >>> import numpy as np
  142. >>> image = np.random.uniform(0, 255, 10000).reshape((100, 100))
  143. >>> noisy_image = laplace_noise(image, 10)
  144. >>> noisy_image.shape
  145. (100, 100)
  146. """
  147. a, b = distribution_interval
  148. generator = lambda h, w: np.random.laplace(a, b, (h, w))
  149. updator = lambda x, noise: x + n * k * noise
  150. return _global_noise_filter(image, generator, updator, identical)
  151. def cauchy_noise(image,
  152. n,
  153. identical=False,
  154. distribution_interval=(0, 1),
  155. k=0.0002):
  156. """Cauchy noise filter to apply on image
  157. Args:
  158. image: image used as input (2D or 3D image representation)
  159. n: used to set importance of noise [1, 999]
  160. identical: keep or not identical noise distribution for each canal if RGB Image (default False)
  161. distribution_interval: set the distribution interval of normal law distribution (default (0, 1))
  162. k: variable that specifies the amount of noise to be taken into account in the output image (default 0.0002)
  163. Returns:
  164. 2D Numpy array with Cauchy noise applied
  165. Example:
  166. >>> from ipfml.filters.noise import cauchy_noise
  167. >>> import numpy as np
  168. >>> image = np.random.uniform(0, 255, 10000).reshape((100, 100))
  169. >>> noisy_image = cauchy_noise(image, 10)
  170. >>> noisy_image.shape
  171. (100, 100)
  172. """
  173. a, b = distribution_interval
  174. generator = lambda h, w: np.random.standard_cauchy((h, w))
  175. updator = lambda x, noise: x + n * k * noise
  176. return _global_noise_filter(image, generator, updator, identical)
  177. def log_normal_noise(image,
  178. n,
  179. identical=False,
  180. distribution_interval=(0, 1),
  181. k=0.05):
  182. """Log-normal noise filter to apply on image
  183. Args:
  184. image: image used as input (2D or 3D image representation)
  185. n: used to set importance of noise [1, 999]
  186. identical: keep or not identical noise distribution for each canal if RGB Image (default False)
  187. distribution_interval: set the distribution interval of normal law distribution (default (0, 1))
  188. k: variable that specifies the amount of noise to be taken into account in the output image (default 0.05)
  189. Returns:
  190. 2D Numpy array with Log-normal noise applied
  191. Example:
  192. >>> from ipfml.filters.noise import log_normal_noise
  193. >>> import numpy as np
  194. >>> image = np.random.uniform(0, 255, 10000).reshape((100, 100))
  195. >>> noisy_image = log_normal_noise(image, 10)
  196. >>> noisy_image.shape
  197. (100, 100)
  198. """
  199. a, b = distribution_interval
  200. generator = lambda h, w: np.random.lognormal(a, b, (h, w))
  201. updator = lambda x, noise: x + n * k * noise
  202. return _global_noise_filter(image, generator, updator, identical)
  203. def mut_white_noise(image,
  204. n,
  205. identical=False,
  206. distribution_interval=(0, 1),
  207. k=0.002):
  208. """Multiplied White noise filter to apply on image
  209. Args:
  210. image: image used as input (2D or 3D image representation)
  211. n: used to set importance of noise [1, 999]
  212. identical: keep or not identical noise distribution for each canal if RGB Image (default False)
  213. distribution_interval: set the distribution interval of normal law distribution (default (0, 1))
  214. k: variable that specifies the amount of noise to be taken into account in the output image (default 0.002)
  215. Returns:
  216. 2D Numpy array with multiplied white noise applied
  217. Example:
  218. >>> from ipfml.filters.noise import mut_white_noise
  219. >>> import numpy as np
  220. >>> image = np.random.uniform(0, 255, 10000).reshape((100, 100))
  221. >>> noisy_image = mut_white_noise(image, 10)
  222. >>> noisy_image.shape
  223. (100, 100)
  224. """
  225. min_value = 1 - (k / 2)
  226. max_value = 1 + (k / 2)
  227. a, b = distribution_interval
  228. generator = lambda h, w: min_value + (np.random.uniform(a, b, (h, w)) * (max_value - min_value))
  229. updator = lambda x, noise: x * pow(noise, n)
  230. return _global_noise_filter(image, generator, updator, identical)
  231. def salt_pepper_noise(image, n, identical=False, p=0.1, k=0.5):
  232. """Pepper salt noise filter to apply on image
  233. Args:
  234. image: image used as input (2D or 3D image representation)
  235. n: used to set importance of noise [1, 999]
  236. identical: keep or not identical noise distribution for each canal if RGB Image (default False)
  237. p: probability to increase pixel value otherwise decrease it
  238. k: variable that specifies the amount of noise to be taken into account in the output image (default 0.5)
  239. Returns:
  240. 2D Numpy array with salt and pepper noise applied
  241. Example:
  242. >>> from ipfml.filters.noise import salt_pepper_noise
  243. >>> import numpy as np
  244. >>> image = np.random.uniform(0, 255, 10000).reshape((100, 100))
  245. >>> noisy_image = salt_pepper_noise(image, 10)
  246. >>> noisy_image.shape
  247. (100, 100)
  248. """
  249. def _generator(h, w):
  250. x = w * h
  251. nb_elem = int(p * x)
  252. elements = np.full(x, 0)
  253. elements[0:nb_elem] = 1
  254. np.random.shuffle(elements)
  255. return elements.reshape(h, w)
  256. image_array = np.array(image)
  257. if image_array.ndim == 3:
  258. height, width, _ = image_array.shape
  259. else:
  260. height, width = image_array.shape
  261. # need same random variable for each pixel value if identical
  262. if identical:
  263. gen = np.random.uniform(0, 1, height * width)
  264. for i in range(2):
  265. gen = np.insert(gen, 0, gen)
  266. gen = iter(gen)
  267. # here noise variable is boolean to update or not pixel value
  268. def _updator(x, noise):
  269. # apply specific changes to each value of 1D array
  270. if isinstance(x, np.ndarray):
  271. return np.array(list(map(_updator, x, noise)))
  272. # probabilty to increase or decrease pixel value
  273. if identical:
  274. rand = next(gen)
  275. else:
  276. rand = random.uniform(0, 1)
  277. if noise:
  278. if rand > 0.5:
  279. return x + n * k
  280. else:
  281. return x - n * k
  282. else:
  283. return x
  284. return _global_noise_filter(image, _generator, _updator, identical)