| import cv2 |
| import uuid |
| import shutil |
| import numpy as np |
| from pathlib import Path |
| from typing import Protocol, Type |
|
|
| from tools.contour_detector import getting_coordinates |
| from tools.mask_display import mask_map |
|
|
|
|
| SAVE_FOLDER = Path.cwd() / 'video-test' |
|
|
|
|
| class ExportObject: |
| def __init__(self, mask, name_class) -> None: |
| self.mask = mask |
| self.name_class = name_class |
|
|
|
|
| class ExportImage: |
| def __init__(self, image, objects: list[ExportObject]) -> None: |
| self.image = image |
| self.exports_objects = objects |
|
|
|
|
| class TypeSave(Protocol): |
| def start_creation(self) -> None: |
| pass |
|
|
| def create_archive(self) -> str: |
| pass |
|
|
|
|
| def get_type_save_annotation( |
| images: list[np.ndarray], |
| masks: list[np.ndarray], |
| names_class: list[str], |
| type_save: str = 'yolo', |
| ) -> TypeSave: |
| '''Factory''' |
| types_saves: dict[str, Type[TypeSave]] = { |
| 'yolo': YoloSave, |
| } |
|
|
| return types_saves[type_save](images, masks, names_class) |
|
|
|
|
| class YoloSave: |
| def __init__( |
| self, images: list[np.ndarray], masks: list[np.ndarray], names_class: list[str] |
| ) -> None: |
| self.images = images |
| self.masks = masks |
| self.names_class = {} |
|
|
| for i, name in enumerate(names_class): |
| self.names_class[name] = i |
| folder_name = ( |
| ''.join(names_class)[:10] |
| if len(''.join(names_class)) > 15 |
| else ''.join(names_class) |
| ) |
| folder_name = f'dt-{folder_name}-{uuid.uuid1()}' |
| p = Path(SAVE_FOLDER / folder_name) |
| p.mkdir() |
| self.path_folder = SAVE_FOLDER / folder_name |
| self.images_folder = self.path_folder / 'images' |
| p = Path(self.images_folder) |
| p.mkdir() |
| self.lables_folder = self.path_folder / 'lables' |
| p = Path(self.lables_folder) |
| p.mkdir() |
|
|
| def start_creation(self): |
| path_image = self.images_folder / 'image_filename' |
| path_txt = self.lables_folder / 'image_filename' |
|
|
| for i, (image, mask) in enumerate(zip(self.images, self.masks)): |
| cv2.imwrite(f'{path_image}{i+1}.jpg', image) |
| txt_frame_save(image, mask, f'{path_txt}{i+1}', 0) |
|
|
| txt_class_save(self.path_folder / 'classes', self.names_class) |
|
|
| def create_archive(self) -> str: |
| shutil.make_archive(self.path_folder, 'zip', self.path_folder) |
| shutil.rmtree(self.path_folder) |
| return f'{self.path_folder}.zip' |
|
|
|
|
| def txt_class_save(path: str, names_class: dict): |
| with open(f'{path}.txt', 'w') as file: |
| for key, value in names_class.items(): |
| name_class_str = [f'{value} {key} \n'] |
|
|
| file.writelines(name_class_str) |
|
|
|
|
| def txt_frame_save( |
| images: np.ndarray, mask_unique: np.ndarray, path: str, name_class_idx: int |
| ): |
|
|
| img_height = images.shape[0] |
| img_width = images.shape[1] |
| with open(f'{path}.txt', 'w') as file: |
| coordinates = [] |
| for mask in mask_map(mask_unique): |
| coordinate = getting_coordinates(mask) |
| coordinates += coordinate |
|
|
| for box in coordinates: |
| x, y = box[0], box[1] |
| w, h = box[2], box[3] |
|
|
| x_center = x + int(w / 2) |
| y_center = y + int(h / 2) |
|
|
| norm_xc = x_center / img_width |
| norm_yc = y_center / img_height |
| norm_width = w / img_width |
| norm_height = h / img_height |
|
|
| yolo_annotation = [ |
| f'{name_class_idx} {norm_xc} {norm_yc} {norm_width} {norm_height} \n' |
| ] |
|
|
| file.writelines(yolo_annotation) |
|
|