image.py 3.9 KB

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