file_ops.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import os
  2. import typing as T
  3. import cv2
  4. from PIL import Image
  5. from pycs.database.File import File
  6. # pylint: disable=too-many-arguments, too-many-locals
  7. def crop_file(file: File, project_root: str, x: float, y: float, w: float, h: float) -> str:
  8. """
  9. gets a file for the given file_id, crops the according image to the
  10. bounding box and saves the crops in the temp folder of the project.
  11. :param file: file object
  12. :param x: relative x-coordinate of the top left corner
  13. :param y: relative y-coordinate of the top left corner
  14. :param w: relative width of the bounding box
  15. :param h: relative height of the bounding box
  16. :return: directory and file name of the cropped patch
  17. """
  18. image = Image.open(file.absolute_path)
  19. width, height = image.size
  20. crop_width = int(width * w)
  21. crop_height = int(height * h)
  22. x0 = int(width * x)
  23. y0 = int(height * y)
  24. x1 = x0 + crop_width
  25. y1 = y0 + crop_height
  26. target_path = os.path.join(
  27. os.getcwd(),
  28. project_root,
  29. 'temp',
  30. f'{file.uuid}_{x0}-{y0}_{x1}-{y1}.jpg',
  31. )
  32. if not os.path.exists(target_path):
  33. crop = image.crop((x0, y0, x0+crop_width, y0+crop_height))
  34. crop.save(target_path, quality=80)
  35. return os.path.split(target_path)
  36. def resize_file(file: File,
  37. project_root: str,
  38. max_width: int,
  39. max_height: int) -> T.Tuple[str, str]:
  40. """
  41. If file type equals video this function extracts a thumbnail first. It calls resize_image
  42. to resize and returns the resized files directory and name.
  43. :param file: file object
  44. :param max_width: maximum image or thumbnail width
  45. :param max_height: maximum image or thumbnail height
  46. :return: resized file directory, resized file name
  47. """
  48. abs_file_path = file.absolute_path
  49. # extract video thumbnail
  50. if file.type == 'video':
  51. abs_target_path = os.path.join(os.getcwd(), project_root, 'temp', f'{file.uuid}.jpg')
  52. create_thumbnail(abs_file_path, abs_target_path)
  53. abs_file_path = abs_target_path
  54. # resize image file
  55. abs_target_path = os.path.join(os.getcwd(), project_root,
  56. 'temp', f'{file.uuid}_{max_width}_{max_height}.jpg')
  57. result = resize_image(abs_file_path, abs_target_path, max_width, max_height)
  58. # return path
  59. if result is not None:
  60. return os.path.split(abs_target_path)
  61. return os.path.split(abs_file_path)
  62. def resize_image(file_path: str,
  63. target_path: str,
  64. max_width: int,
  65. max_height: int) -> T.Optional[bool]:
  66. """
  67. resize an image so width < max_width and height < max_height
  68. :param file_path: path to source file
  69. :param target_path: path to target file
  70. :param max_width: maximum image width
  71. :param max_height: maximum image height
  72. :return:
  73. """
  74. # return if file exists
  75. if os.path.exists(target_path):
  76. return True
  77. # load full size image
  78. image = Image.open(file_path)
  79. img_width, img_height = image.size
  80. # abort if file is smaller than desired
  81. if img_width < max_width and img_height < max_height:
  82. return None
  83. # calculate target size
  84. target_width = int(max_width)
  85. target_height = int(max_width * img_height / img_width)
  86. if target_height > max_height:
  87. target_height = int(max_height)
  88. target_width = int(max_height * img_width / img_height)
  89. # resize image
  90. resized_image = image.resize((target_width, target_height))
  91. # save to file
  92. resized_image.save(target_path, quality=80)
  93. return True
  94. def create_thumbnail(file_path: str, target_path: str) -> None:
  95. """
  96. extract a thumbnail from a video
  97. :param file_path: path to source file
  98. :param target_path: path to target file
  99. :return:
  100. """
  101. # return if file exists
  102. if os.path.exists(target_path):
  103. return
  104. # load video
  105. video = cv2.VideoCapture(file_path)
  106. # create thumbnail
  107. _, image = video.read()
  108. cv2.imwrite(target_path, image)
  109. # close video file
  110. video.release()