|
@@ -1,7 +1,10 @@
|
|
|
import os
|
|
|
-from typing import Tuple
|
|
|
+import typing as T
|
|
|
+
|
|
|
+from collections import namedtuple
|
|
|
|
|
|
import cv2
|
|
|
+
|
|
|
from PIL import Image
|
|
|
|
|
|
from pycs.database.File import File
|
|
@@ -9,6 +12,8 @@ from pycs.database.File import File
|
|
|
DEFAULT_JPEG_QUALITY = 80
|
|
|
|
|
|
|
|
|
+BoundingBox = namedtuple("BoundingBox", "x y w h")
|
|
|
+
|
|
|
def file_info(data_folder: str, file_name: str, file_ext: str):
|
|
|
"""
|
|
|
Receive file type, frame count and frames per second.
|
|
@@ -46,7 +51,10 @@ def file_info(data_folder: str, file_name: str, file_ext: str):
|
|
|
return file_type, frames, fps
|
|
|
|
|
|
|
|
|
-def resize_file(file: File, project_root: str, max_width: int, max_height: int) -> Tuple[str, str]:
|
|
|
+def resize_file(file: File,
|
|
|
+ project_root: str,
|
|
|
+ max_width: int,
|
|
|
+ max_height: int) -> T.Tuple[str, str]:
|
|
|
"""
|
|
|
If file type equals video this function extracts a thumbnail first. It calls resize_image
|
|
|
to resize and returns the resized files directory and name.
|
|
@@ -80,9 +88,8 @@ def resize_file(file: File, project_root: str, max_width: int, max_height: int)
|
|
|
return os.path.split(abs_file_path)
|
|
|
|
|
|
|
|
|
-def crop_file(file: File, project_root: str,
|
|
|
- x: float, y: float, w: float, h: float,
|
|
|
- max_width: int, max_height: int) -> Tuple[str, str]:
|
|
|
+def crop_file(file: File, project_root: str, box: BoundingBox,
|
|
|
+ max_width: int, max_height: int) -> T.Tuple[str, str]:
|
|
|
"""
|
|
|
gets a file for the given file_id, crops the according image to the
|
|
|
bounding box and saves the crops in the temp folder of the project.
|
|
@@ -91,10 +98,8 @@ def crop_file(file: File, project_root: str,
|
|
|
:param project_root: project root folder path
|
|
|
:param max_width: maximum image or thumbnail width
|
|
|
:param max_height: maximum image or thumbnail height
|
|
|
- :param x: relative x-coordinate of the top left corner
|
|
|
- :param y: relative y-coordinate of the top left corner
|
|
|
- :param w: relative width of the bounding box
|
|
|
- :param h: relative height of the bounding box
|
|
|
+ :param box: BoundingBox with relative x, y coordinates and
|
|
|
+ the relative height and width of the bounding box
|
|
|
|
|
|
:return: directory and file name of the cropped patch
|
|
|
"""
|
|
@@ -107,21 +112,23 @@ def crop_file(file: File, project_root: str,
|
|
|
|
|
|
abs_file_path = abs_target_path
|
|
|
|
|
|
+ bounding_box_suffix = f"{box.x}_{box.y}_{box.w}_{box.h}"
|
|
|
# crop image file
|
|
|
abs_target_path = os.path.join(os.getcwd(),
|
|
|
project_root,
|
|
|
'temp',
|
|
|
- f'{file.uuid}_{x}_{y}_{w}_{h}.jpg')
|
|
|
- result = crop_image(abs_file_path, abs_target_path, x, y, w, h)
|
|
|
+ f'{file.uuid}_{bounding_box_suffix}.jpg')
|
|
|
+ result = crop_image(abs_file_path, abs_target_path, box)
|
|
|
|
|
|
if result:
|
|
|
abs_file_path = abs_target_path
|
|
|
|
|
|
# resize image
|
|
|
+ target_file_name = f'{file.uuid}_{max_width}_{max_height}_{bounding_box_suffix}.jpg'
|
|
|
abs_target_path = os.path.join(os.getcwd(),
|
|
|
project_root,
|
|
|
'temp',
|
|
|
- f'{file.uuid}_{max_width}_{max_height}_{x}_{y}_{w}_{h}.jpg')
|
|
|
+ target_file_name)
|
|
|
result = resize_image(abs_file_path, abs_target_path, max_width, max_height)
|
|
|
|
|
|
if result:
|
|
@@ -193,17 +200,15 @@ def resize_image(file_path: str, target_path: str, max_width: int, max_height: i
|
|
|
return True
|
|
|
|
|
|
|
|
|
-def crop_image(file_path: str, target_path: str, x: float, y: float, w: float, h: float) -> bool:
|
|
|
+def crop_image(file_path: str, target_path: str, box: BoundingBox) -> bool:
|
|
|
"""
|
|
|
Crop an image with the given coordinates, width and height.
|
|
|
If however no crop is applied no new file is stored.
|
|
|
|
|
|
:param file_path: path to source file
|
|
|
:param target_path: path to target file
|
|
|
- :param x: crop x position (normalized)
|
|
|
- :param y: crop y position (normalized)
|
|
|
- :param w: crop width (normalized)
|
|
|
- :param h: crop height (normalized)
|
|
|
+ :param box: BoundingBox with relative x, y coordinates and
|
|
|
+ the relative height and width of the bounding box
|
|
|
:return: `True` if a crop operation was performed or the target file already exists
|
|
|
"""
|
|
|
# return if file exists
|
|
@@ -211,7 +216,7 @@ def crop_image(file_path: str, target_path: str, x: float, y: float, w: float, h
|
|
|
return True
|
|
|
|
|
|
# abort if no crop would be applied
|
|
|
- if x <= 0 and y <= 0 and w >= 1 and h >= 1:
|
|
|
+ if box.x <= 0 and box.y <= 0 and box.w >= 1 and box.h >= 1:
|
|
|
return False
|
|
|
|
|
|
# load full size image
|
|
@@ -219,10 +224,10 @@ def crop_image(file_path: str, target_path: str, x: float, y: float, w: float, h
|
|
|
img_width, img_height = image.size
|
|
|
|
|
|
# calculate absolute crop position
|
|
|
- crop_x1 = int(img_width * x)
|
|
|
- crop_y1 = int(img_height * y)
|
|
|
- crop_x2 = min(int(img_width * w) + crop_x1, img_width)
|
|
|
- crop_y2 = min(int(img_height * h) + crop_y1, img_height)
|
|
|
+ crop_x1 = int(img_width * box.x)
|
|
|
+ crop_y1 = int(img_height * box.y)
|
|
|
+ crop_x2 = min(int(img_width * box.w) + crop_x1, img_width)
|
|
|
+ crop_y2 = min(int(img_height * box.h) + crop_y1, img_height)
|
|
|
|
|
|
# crop image
|
|
|
print(crop_x1, crop_y1, crop_x2, crop_y2)
|