6
0

file_ops.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import cv2
  2. import os
  3. from PIL import Image
  4. from typing import Tuple
  5. from typing import Optional
  6. from pycs.database.File import File
  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, project_root: str, max_width: int, max_height: int) -> Tuple[str, str]:
  37. """
  38. If file type equals video this function extracts a thumbnail first. It calls resize_image
  39. to resize and returns the resized files directory and name.
  40. :param file: file object
  41. :param max_width: maximum image or thumbnail width
  42. :param max_height: maximum image or thumbnail height
  43. :return: resized file directory, resized file name
  44. """
  45. abs_file_path = file.absolute_path
  46. # extract video thumbnail
  47. if file.type == 'video':
  48. abs_target_path = os.path.join(os.getcwd(), project_root, 'temp', f'{file.uuid}.jpg')
  49. create_thumbnail(abs_file_path, abs_target_path)
  50. abs_file_path = abs_target_path
  51. # resize image file
  52. abs_target_path = os.path.join(os.getcwd(), project_root,
  53. 'temp', f'{file.uuid}_{max_width}_{max_height}.jpg')
  54. result = resize_image(abs_file_path, abs_target_path, max_width, max_height)
  55. # return path
  56. if result is not None:
  57. return os.path.split(abs_target_path)
  58. return os.path.split(abs_file_path)
  59. def resize_image(file_path: str, target_path: str, max_width: int, max_height: int) -> Optional[bool]:
  60. """
  61. resize an image so width < max_width and height < max_height
  62. :param file_path: path to source file
  63. :param target_path: path to target file
  64. :param max_width: maximum image width
  65. :param max_height: maximum image height
  66. :return:
  67. """
  68. # return if file exists
  69. if os.path.exists(target_path):
  70. return True
  71. # load full size image
  72. image = Image.open(file_path)
  73. img_width, img_height = image.size
  74. # abort if file is smaller than desired
  75. if img_width < max_width and img_height < max_height:
  76. return None
  77. # calculate target size
  78. target_width = int(max_width)
  79. target_height = int(max_width * img_height / img_width)
  80. if target_height > max_height:
  81. target_height = int(max_height)
  82. target_width = int(max_height * img_width / img_height)
  83. # resize image
  84. resized_image = image.resize((target_width, target_height))
  85. # save to file
  86. resized_image.save(target_path, quality=80)
  87. return True
  88. def create_thumbnail(file_path: str, target_path: str) -> None:
  89. """
  90. extract a thumbnail from a video
  91. :param file_path: path to source file
  92. :param target_path: path to target file
  93. :return:
  94. """
  95. # return if file exists
  96. if os.path.exists(target_path):
  97. return
  98. # load video
  99. video = cv2.VideoCapture(file_path)
  100. # create thumbnail
  101. _, image = video.read()
  102. cv2.imwrite(target_path, image)
  103. # close video file
  104. video.release()