image.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. from imageio import imread
  2. from PIL import Image
  3. from os.path import isfile
  4. import copy
  5. import numpy as np
  6. from . import utils
  7. def should_have_parts(func):
  8. def inner(self, *args, **kwargs):
  9. assert self.has_parts, "parts are not present!"
  10. return func(self, *args, **kwargs)
  11. return inner
  12. class ImageWrapper(object):
  13. @staticmethod
  14. def read_image(im_path, mode="RGB"):
  15. # im = imread(im_path, pilmode=mode)
  16. im = Image.open(im_path, mode="r")
  17. return im
  18. def __init__(self, im_path, label, parts=None, mode="RGB"):
  19. self.mode = mode
  20. self.im = im_path
  21. self._im_array = None
  22. self.label = label
  23. self.parts = parts
  24. self.parent = None
  25. self._feature = None
  26. def __del__(self):
  27. if isinstance(self._im, Image.Image):
  28. if self._im is not None and self._im.fp is not None:
  29. self._im.close()
  30. @property
  31. def im(self):
  32. return self._im
  33. @property
  34. def im_array(self):
  35. if self._im_array is None:
  36. if isinstance(self._im, Image.Image):
  37. _im = self._im.convert(self.mode)
  38. self._im_array = utils.asarray(_im)
  39. elif isinstance(self._im, np.ndarray):
  40. if self.mode == "RGB" and self._im.ndim == 2:
  41. self._im_array = np.stack((self._im,) * 3, axis=-1)
  42. elif self._im.ndim == 3:
  43. self._im_array = self._im
  44. else:
  45. raise ValueError()
  46. else:
  47. raise ValueError()
  48. return self._im_array
  49. @im.setter
  50. def im(self, value):
  51. if isinstance(value, str):
  52. assert isfile(value), "Image \"{}\" does not exist!".format(value)
  53. self._im = ImageWrapper.read_image(value, mode=self.mode)
  54. else:
  55. self._im = value
  56. def as_tuple(self):
  57. return self.im_array, self.parts, self.label
  58. def copy(self):
  59. new = copy.copy(self)
  60. new.parent = self
  61. deepcopies = [
  62. "_feature",
  63. "parts",
  64. ]
  65. for attr_name in deepcopies:
  66. attr_copy = copy.deepcopy(getattr(self, attr_name))
  67. setattr(new, attr_name, attr_copy)
  68. return new
  69. @property
  70. def feature(self):
  71. return self._feature
  72. @feature.setter
  73. def feature(self, im_feature):
  74. self._feature = im_feature
  75. def crop(self, x, y, w, h):
  76. result = self.copy()
  77. # result.im = self.im[y:y+h, x:x+w]
  78. result.im = self.im.crop(x, y, x+w, y+h)
  79. if self.has_parts:
  80. result.parts[:, 1] -= x
  81. result.parts[:, 2] -= y
  82. return result
  83. @should_have_parts
  84. def hide_parts_outside_bb(self, x, y, w, h):
  85. idxs, (xs,ys) = self.visible_part_locs()
  86. f = np.logical_and
  87. mask = f(f(x <= xs, xs <= x+w), f(y <= ys, ys <= y+h))
  88. result = self.copy()
  89. result.parts[:, -1] = mask.astype(self.parts.dtype)
  90. return result
  91. def uniform_parts(self, ratio):
  92. result = self.copy()
  93. result.parts = utils.uniform_parts(self.im, ratio=ratio)
  94. return result
  95. @should_have_parts
  96. def select_parts(self, idxs):
  97. result = self.copy()
  98. result.parts[:, -1] = 0
  99. result.parts[idxs, -1] = 1
  100. return result
  101. @should_have_parts
  102. def select_random_parts(self, rnd, n_parts):
  103. idxs, xy = self.visible_part_locs()
  104. rnd_idxs = utils.random_idxs(idxs, rnd=rnd, n_parts=n_parts)
  105. return self.select_parts(rnd_idxs)
  106. @should_have_parts
  107. def visible_crops(self, ratio):
  108. return utils.visible_crops(self.im, self.parts, ratio=ratio)
  109. @should_have_parts
  110. def visible_part_locs(self):
  111. return utils.visible_part_locs(self.parts)
  112. @should_have_parts
  113. def reveal_visible(self, ratio):
  114. _, xy = self.visible_part_locs()
  115. result = self.copy()
  116. result.im = utils.reveal_parts(self.im, xy, ratio=ratio)
  117. return result
  118. @should_have_parts
  119. def part_crops(self, ratio):
  120. crops = self.visible_crops(ratio)
  121. idxs, _ = self.visible_part_locs()
  122. result = self.copy()
  123. result.im = crops[idxs]
  124. return result
  125. @property
  126. def has_parts(self):
  127. return self.parts is not None