From 3e78e91ebe85c0598e6365367ff5cad34ecbb322 Mon Sep 17 00:00:00 2001 From: tlpss Date: Wed, 30 Aug 2023 12:05:34 +0200 Subject: [PATCH] remove deprecated labeling workflow --- labeling/Readme.md | 76 ------ labeling/__init__.py | 0 labeling/convert_cvat_to_coco.py | 232 ------------------ labeling/docs/cvat_example_setup.png | Bin 27324 -> 0 bytes labeling/docs/cvat_setup.md | 4 - labeling/example/annotations.json | 109 -------- labeling/example/annotations.xml | 76 ------ labeling/example/coco.json | 106 -------- .../example/coco_category_configuration.json | 19 -- labeling/example/images/1.jpeg | Bin 4297 -> 0 bytes labeling/example/images/2.jpeg | Bin 3034 -> 0 bytes labeling/example/images/3.jpeg | Bin 4498 -> 0 bytes labeling/example/images/4.jpeg | Bin 6624 -> 0 bytes labeling/file_loading.py | 32 --- labeling/parsers/coco_categories_parser.py | 21 -- labeling/parsers/cvat_keypoints_parser.py | 102 -------- labeling/requirements.txt | 3 - labeling/scripts/crop_coco_dataset.py | 113 --------- 18 files changed, 893 deletions(-) delete mode 100644 labeling/Readme.md delete mode 100644 labeling/__init__.py delete mode 100644 labeling/convert_cvat_to_coco.py delete mode 100644 labeling/docs/cvat_example_setup.png delete mode 100644 labeling/docs/cvat_setup.md delete mode 100644 labeling/example/annotations.json delete mode 100644 labeling/example/annotations.xml delete mode 100644 labeling/example/coco.json delete mode 100644 labeling/example/coco_category_configuration.json delete mode 100644 labeling/example/images/1.jpeg delete mode 100644 labeling/example/images/2.jpeg delete mode 100644 labeling/example/images/3.jpeg delete mode 100644 labeling/example/images/4.jpeg delete mode 100644 labeling/file_loading.py delete mode 100644 labeling/parsers/coco_categories_parser.py delete mode 100644 labeling/parsers/cvat_keypoints_parser.py delete mode 100644 labeling/requirements.txt delete mode 100644 labeling/scripts/crop_coco_dataset.py diff --git a/labeling/Readme.md b/labeling/Readme.md deleted file mode 100644 index f17ca67..0000000 --- a/labeling/Readme.md +++ /dev/null @@ -1,76 +0,0 @@ -# CVAT to COCO Keypoints - -This readme defines a workflow to label semantic keypoints on images using [CVAT](https://www.cvat.ai/) and to convert them to the [COCO keypoints format](https://cocodataset.org/#format-data). - This package contains parsers for the different dataset formats and code to convert from the CVAT Image 1.1 format to COCO format. - - - -## Labeling use case analysis -- **we want to label semantic keypoints on images**. -- There can be **multiple categories / classes of objects in the images**. Each category can have 0 - N instances in each image. (think about categories/classes as objects that you could draw a bounding box or segmentation mask for). -- Each category has a number of **semantic types** of keypoints that are of interest. E.g. arms, shoulders, head,.. for the person category. -- Each semantic type can contain multiple keypoints (e.g. a human has 2 shoulders, a cardboard box has 4 corners). Although you could label these separately (and for humans this is very natural as humans have a front/back side, unlike boxes for which there is no semantic difference between the corners), this creates a burden as you have to do this in a geometrically consistent way by e.g. always labeling most topleft corner of a box as 'corner1'. This is easily done afterwards using e.g. the quadrant of each corner and asking the labeler to do so only leads to more work and possible inaccuracies. Therefore each semantic type can have 0 - K keypoints. - -**So each image has N_i instances of each of the K categories and each instance has the M semantic types of that category, where each each type has S_i keypoints.** - -We hence need to be able to -- group the keypoints of a single instance of a category together -- and to label multiple keypoints under one semantic type and later separate them for the COCO format (which does not allow for multiple keypoints for a single type). - - -## CVAT configuration -In CVAT we create a **label** for each **semantic type** of each **category** using the naming convention **{category}.{semantic_type}**. You then label all keypoints of a single type in the image. If there are multiple instances of a single category, you group them together using the Grouping Tool in CVAT, if there is only one instance of a category, there is no need to manually group them together. - -After labeling, the annotations XML can be downloaded. - -## Converting CVAT to COCO -- clone this repo and pip install the requirements of this package. -- [set up CVAT](docs/cvat_setup.md) -- create a task and define your labels. -- label your images. -- export the annotations XML in the CVAT images format. -- create a Category configuration that specifies for each category: - - its name - - its desired ID - - its supercategory - - its semantic types and how much keypoints each type has - - This configuration is then used to create the COCO object categories and define all the keypoints for each categorie. - -- then, from this readme's folder, run `python convert_cvat_to_coco.py --cvat_xml_file example/annotations.xml --coco_categories_config_path example/coco_category_configuration.json` to create a `coco.json` annotation file. You should now have a COCO dataset annotation file, that you can use for example with - -## Example -There is an example included for 4 images containing a number of tshirts. -The desired categories configuration is as follows (see `examples/coco_category_configuration.json`) -``` -{ - "categories": [ - { - "name": "tshirt", - "supercategory": "cloth", - "id": 23, - "semantic_types": [ - { - "name": "neck", - "n_keypoints": 1 - }, - { - "name": "shoulder", - "n_keypoints": 2 - } - ] - } - ] -} -``` - -which implies we have 1 object class that has 2 semantic types: 'neck' with 1 keypoint and 'shoulder' with 2 keypoints (left/right, which is an artificial example as a tshirt has a front and back side and hence there is no ambiguity) - -To label this configuration, we create 2 labels in cvat: -![alt text](docs/cvat_example_setup.png). - - -One image contains 2 instances of the tshirt, which should hence be grouped using CVATs group_id. One image is not labeled to show this can be dealt with. Another image is partially labeled to simulate partial visibility. -You can find the resulting CVAT annotations in `example/annotations.xml`. - -You can now finally convert the CVAT annotations to COCO annotation format, which results in the `example/coco.json` file. diff --git a/labeling/__init__.py b/labeling/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/labeling/convert_cvat_to_coco.py b/labeling/convert_cvat_to_coco.py deleted file mode 100644 index 79da86e..0000000 --- a/labeling/convert_cvat_to_coco.py +++ /dev/null @@ -1,232 +0,0 @@ -from __future__ import annotations - -import json -from typing import List - -import tqdm - -from keypoint_detection.data.coco_parser import CocoImage, CocoKeypointAnnotation, CocoKeypointCategory, CocoKeypoints -from labeling.file_loading import get_dict_from_json, get_dict_from_xml -from labeling.parsers.coco_categories_parser import COCOCategoriesConfig, COCOCategoryConfig -from labeling.parsers.cvat_keypoints_parser import CVATKeypointsParser, ImageItem, Point - - -def cvat_image_to_coco( - cvat_xml_path: str, coco_category_configuration_path: str, image_folder: str = "images" -) -> dict: - """Function that converts an annotation XML in the CVAT 1.1 Image format to the COCO keypoints format. - - This function supports: - - multiple categories (box, tshirt); - - multiple semantic types for each category ("corners", "flap_corners") - - multiple keypoints for a single semantic type (a box has 4 corners) to facilitate fast labeling (no need to label each corner with a separate label, which requires geometric consistency) - - occluded or invisible keypoints for each type - - It requires the CVAT dataset to be created by using labels formatted as ., using the group_id to group multiple instances together. - if only a single instance is present, the group id is set to 1 by default so you don't have to do this yourself. - - To map from the CVAT labels to the COCO categories, you need to specify a configuration. - See the readme for more details and an example. - - This function is rather complex unfortunately, but at a high level it performs the following: - # for all categories in the config: - # for all images: - # create COCO Image - # find number of category instances in that images - # for each instance in the image: - # for all semantic types in the category: - # find all keypoints of that type for that instance in the current image - # create a COCO Annotation for the current instance of the category - - Args: - cvat_xml_path (str): _description_ - coco_category_configuration_path (str): _description_ - - Returns: - (dict): a COCO dict that can be dumped to a JSON. - """ - cvat_dict = get_dict_from_xml(cvat_xml_path) - cvat_parsed = CVATKeypointsParser(**cvat_dict) - - category_dict = get_dict_from_json(coco_category_configuration_path) - parsed_category_config = COCOCategoriesConfig(**category_dict) - - # create a COCO Dataset Model - coco_model = CocoKeypoints(images=[], annotations=[], categories=[]) - - annotation_id_counter = 1 # counter for the annotation ID - - print("starting CVAT Image -> COCO conversion") - for category in parsed_category_config.categories: - print(f"converting category {category.name}") - category_name = category.name - category_keypoint_names = get_coco_keypoint_names_from_category_config(category) - coco_model.categories.append( - CocoKeypointCategory( - id=category.id, - name=category.name, - supercategory=category.supercategory, - keypoints=category_keypoint_names, - ) - ) - - for cvat_image in tqdm.tqdm(cvat_parsed.annotations.image): - coco_image = CocoImage( - file_name=f"{image_folder}/{cvat_image.name}", - height=int(cvat_image.height), - width=int(cvat_image.width), - id=int(cvat_image.id) + 1, - ) - coco_model.images.append(coco_image) - n_image_category_instances = get_n_category_instances_in_image(cvat_image, category_name) - for instance_id in range(1, n_image_category_instances + 1): # IDs start with 1 - instance_category_keypoints = [] - for semantic_type in category.semantic_types: - keypoints = get_semantic_type_keypoints_from_instance_in_cvat_image( - cvat_image, semantic_type.name, instance_id - ) - - # pad for invisible keypoints for the given instance of the semantic type. - keypoints.extend([0.0] * (3 * semantic_type.n_keypoints - len(keypoints))) - instance_category_keypoints.extend(keypoints) - - coco_model.annotations.append( - CocoKeypointAnnotation( - category_id=category.id, - id=annotation_id_counter, - image_id=coco_image.id, - keypoints=instance_category_keypoints, - ) - ) - annotation_id_counter += 1 - return coco_model.dict(exclude_none=True) - - -### helper functions - - -def get_n_category_instances_in_image(cvat_image: ImageItem, category_name: str) -> int: - """returns the number of instances for the specified category in the CVAT ImageItem. - - This is done by finding the maximum group_id for all annotations of the image. - - Edge cases include: no Points in the image or only 1 Point in the image. - """ - if cvat_image.points is None: - return 0 - if not isinstance(cvat_image.points, list): - if get_category_from_cvat_label(cvat_image.points.label) == category_name: - return int(cvat_image.points.group_id) - else: - return 0 - max_group_id = 1 - for cvat_point in cvat_image.points: - if get_category_from_cvat_label(cvat_point.label) == category_name: - max_group_id = max(max_group_id, int(cvat_point.group_id)) - return max_group_id - - -def get_category_from_cvat_label(label: str) -> str: - """cvat labels are formatted as . - this function returns the category - """ - split = label.split(".") - assert len(split) == 2, " label was not formatted as category.semantic_type" - return label.split(".")[0] - - -def get_semantic_type_from_cvat_label(label: str) -> str: - """cvat labels are formatted as . - this function returns the semantic type - """ - split = label.split(".") - assert len(split) == 2, " label was not formatted as category.semantic_type" - return label.split(".")[1] - - -def get_coco_keypoint_names_from_category_config(config: COCOCategoryConfig) -> List[str]: - """Helper function that converts a CategoryConfiguration to a list of coco keypoints. - This function duplicates keypoints for types with n_keypoints > 1 by appending an index: - e.g. "corner", n_keypoints = 2 -> ["corner1" ,"corner2"]. - - Args: - config (dict): _description_ - - Returns: - _type_: _description_ - """ - keypoint_names = [] - for semantic_type in config.semantic_types: - if semantic_type.n_keypoints == 1: - keypoint_names.append(semantic_type.name) - else: - for i in range(semantic_type.n_keypoints): - keypoint_names.append(f"{semantic_type.name}{i+1}") - return keypoint_names - - -def get_semantic_type_keypoints_from_instance_in_cvat_image( - cvat_image: ImageItem, semantic_type: str, instance_id: int -) -> List[float]: - """Gather all keypoints of the given semantic type for this in the image. - - Args: - cvat_image (ImageItem): _description_ - semantic_type (str): _description_ - instance_id (int): _description_ - - Returns: - List: _description_ - """ - instance_id = str(instance_id) - if cvat_image.points is None: - return [0.0, 0.0, 0] - if not isinstance(cvat_image.points, list): - if ( - semantic_type == get_semantic_type_from_cvat_label(cvat_image.points.label) - and instance_id == cvat_image.points.group_id - ): - return extract_coco_keypoint_from_cvat_point(cvat_image.points, cvat_image) - else: - return [0.0, 0.0, 0] - keypoints = [] - for cvat_point in cvat_image.points: - if semantic_type == get_semantic_type_from_cvat_label(cvat_point.label) and instance_id == cvat_point.group_id: - keypoints.extend(extract_coco_keypoint_from_cvat_point(cvat_point, cvat_image)) - return keypoints - - -def extract_coco_keypoint_from_cvat_point(cvat_point: Point, cvat_image: ImageItem) -> List: - """extract keypoint in coco format (u,v,f) from cvat annotation point. - Args: - cvat_point (Point): _description_ - cvat_image (ImageItem): _description_ - - Returns: - List: [u,v,f] where u,v are the coords scaled to the image resolution and f is the coco visibility flag. - see the coco dataset format for more details. - """ - u = float(cvat_point.points.split(",")[0]) - v = float(cvat_point.points.split(",")[1]) - f = ( - 1 if cvat_point.occluded == "1" else 2 - ) # occluded = 1 means not visible, which is 1 in COCO; visible in COCO is 2 - return [u, v, f] - - -if __name__ == "__main__": - """ - example usage: - - python convert_cvat_to_coco.py --cvat_xml_file example/annotations.xml --coco_categories_config_path example/coco_category_configuration.json - """ - import argparse - - parser = argparse.ArgumentParser() - parser.add_argument("--cvat_xml_file", type=str, required=True) - parser.add_argument("--coco_categories_config_path", type=str, required=True) - - args = parser.parse_args() - coco = cvat_image_to_coco(args.cvat_xml_file, args.coco_categories_config_path) - with open("coco.json", "w") as file: - json.dump(coco, file) diff --git a/labeling/docs/cvat_example_setup.png b/labeling/docs/cvat_example_setup.png deleted file mode 100644 index e83889351512eca0ad424bc6f90198736528ca0b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27324 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%0D$NP+R>^)RZC7 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 diff --git a/labeling/docs/cvat_setup.md b/labeling/docs/cvat_setup.md deleted file mode 100644 index 3c680d7..0000000 --- a/labeling/docs/cvat_setup.md +++ /dev/null @@ -1,4 +0,0 @@ -CVAT provides a docker compose file to set up everyting on a private machine, see instructions [here](https://cvat-ai.github.io/cvat/docs/administration/basics/installation/#ubuntu-1804-x86_64amd64). At the time of writing however, you need to change the container tag to `dev`, cf [this issue](https://github.com/opencv/cvat/issues/4816). - - - You can also do this setup on a remote machine, in which case you can either make the client reachable over the web or forward the tcp conncetion to your local machine using ssh: `ssh -L :: @` diff --git a/labeling/example/annotations.json b/labeling/example/annotations.json deleted file mode 100644 index 1c7d36f..0000000 --- a/labeling/example/annotations.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "info": null, - "licenses": null, - "images": [ - { - "license": null, - "file_name": "1.jpeg", - "height": 256, - "width": 256, - "id": 1 - }, - { - "license": null, - "file_name": "2.jpeg", - "height": 256, - "width": 256, - "id": 2 - }, - { - "license": null, - "file_name": "3.jpeg", - "height": 256, - "width": 256, - "id": 3 - }, - { - "license": null, - "file_name": "4.jpeg", - "height": 256, - "width": 256, - "id": 4 - } - ], - "categories": [ - { - "supercategory": "onion", - "id": 0, - "name": "onion", - "keypoints": [ - "head", - "tail" - ], - "skeleton": [ - [ - 1, - 0 - ] - ] - } - ], - "annotations": [ - { - "category_id": 0, - "id": 1, - "image_id": 1, - "num_keypoints": null, - "keypoints": [ - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ] - }, - { - "category_id": 0, - "id": 2, - "image_id": 2, - "num_keypoints": null, - "keypoints": [ - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ] - }, - { - "category_id": 0, - "id": 3, - "image_id": 3, - "num_keypoints": null, - "keypoints": [ - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ] - }, - { - "category_id": 0, - "id": 4, - "image_id": 4, - "num_keypoints": null, - "keypoints": [ - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ] - } - ] -} diff --git a/labeling/example/annotations.xml b/labeling/example/annotations.xml deleted file mode 100644 index 82e17dd..0000000 --- a/labeling/example/annotations.xml +++ /dev/null @@ -1,76 +0,0 @@ - - 1.1 - - - 3 - example-keypoints-task - 4 - annotation - 0 - - 2022-08-24 11:46:30.553731+00:00 - 2022-08-24 12:51:45.689497+00:00 - Train - 0 - 3 - - - - 3 - 0 - 3 - http://localhost:8080/?id=3 - - - - tlips - thomas.lips@ugent.be - - - - - - - - 2022-08-24 12:51:55.830700+00:00 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/labeling/example/coco.json b/labeling/example/coco.json deleted file mode 100644 index a045df1..0000000 --- a/labeling/example/coco.json +++ /dev/null @@ -1,106 +0,0 @@ -{ - "images": [ - { - "file_name": "images/1.jpeg", - "height": 256, - "width": 256, - "id": 1 - }, - { - "file_name": "images/2.jpeg", - "height": 256, - "width": 256, - "id": 2 - }, - { - "file_name": "images/3.jpeg", - "height": 256, - "width": 256, - "id": 3 - }, - { - "file_name": "images/4.jpeg", - "height": 256, - "width": 256, - "id": 4 - } - ], - "categories": [ - { - "supercategory": "cloth", - "id": 23, - "name": "tshirt", - "keypoints": [ - "neck", - "shoulder1", - "shoulder2" - ] - } - ], - "annotations": [ - { - "category_id": 23, - "id": 1, - "image_id": 1, - "keypoints": [ - 126.0, - 26.6, - 2.0, - 64.1, - 31.8, - 2.0, - 181.8, - 28.9, - 2.0 - ] - }, - { - "category_id": 23, - "id": 2, - "image_id": 2, - "keypoints": [ - 127.68, - 61.3, - 2.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ] - }, - { - "category_id": 23, - "id": 3, - "image_id": 3, - "keypoints": [ - 71.96, - 41.64, - 2.0, - 38.52, - 41.31, - 2.0, - 102.44, - 40.0, - 2.0 - ] - }, - { - "category_id": 23, - "id": 4, - "image_id": 3, - "keypoints": [ - 187.34, - 40.33, - 1.0, - 152.27, - 45.9, - 2.0, - 221.76, - 44.59, - 2.0 - ] - } - ] -} diff --git a/labeling/example/coco_category_configuration.json b/labeling/example/coco_category_configuration.json deleted file mode 100644 index e448053..0000000 --- a/labeling/example/coco_category_configuration.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "categories": [ - { - "name": "tshirt", - "supercategory": "cloth", - "id": 23, - "semantic_types": [ - { - "name": "neck", - "n_keypoints": 1 - }, - { - "name": "shoulder", - "n_keypoints": 2 - } - ] - } - ] -} diff --git a/labeling/example/images/1.jpeg b/labeling/example/images/1.jpeg deleted file mode 100644 index f3f2e14b20f52b012033cc32ba1459bf17e5fb69..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4297 zcmY*c2RPf?`~N0Ehqh*@B3gUKYKT=WEn<&qYqw@?5u+mLxLsn@irOkxRcL9ESRHnx zsy0DuUTUjN^LNMp-rxP4=Q;Cv-_LvAbKd7YhcU?b2Cy6Iq4WR{7yv+r1z`LF*o|+6 zxFC>l#Cf=)f&#!80d#?*$B(lfXFd5R*xA_s1t%vb6be18+1WWcxw)ZGUS8hAiNl7E zj}HbD5D*a&m61_qGyx@t>cL>hA;&)efgwj&n2s`oKmY`ESp5qS6Eg(N!VZ8z5D+uu z7=-22Uy>j&2NQ((+$9S|7BuHAodhMzd%|2Fj=XVxao+_KSRvA#_#i27#fnGyD&jl0 zsIK_OuVN}3hZ}={AuLQs4q5)BI2>}EV>(pAiB3?yrS#&S4wt2faNvhGEBAG~of+=| zj-!7#0|F8Tz#IUC17HjTCk|!79EW{vVEo&^hC*FTh2PKB*4~-kHd7JPwxCIcy|Suw zygad_`1pC|sy#c3?IN?6u#)Tv<@OWa^=d80{F6|TqAs-f^WlTD0tqA;p7iqLdG6xs z!!fNa0Xm|;-ThbjUp+zGz-iJd74Gw__2^=9{v34CrQ9GbDc|FP8WaH|Z5-hdU-hhM zoYG!gvv%2kLaJPx@_yA&G9X`46qdy8l=OJZsNywo->AxGew;50>PNSV^Vc7nC!7h= z*b2Q7Am1oj{}kiXN9l6v!)ZyMs$EiQ!LJGL?3rk&$|f$GT4vUJs!Y$$Na-ACWf4Am z*i36d%jr%b3Hg|~l4*kR09RLrY(bJ}W@f>=YTI>sja;ip#lX98wiSP6J;U*g5iYiU5n0P-Id#dZ?k5PA6vRp;vTQ{Mh7eh|w8z!3s|B(y^ z@a9$R5VGN8_|PeOP)hPE|svO_@(NYdj5h9LVR(HVpw0<^~&!v zUhq2Mv37wz6iPhZbA_mhG1Uk+BYKv2smMjO)YW`UO)T8Y9<0{$7=II2)j6BWoS~{Y zRxP?d9q%+hc;-5C)j>b9IbKXt!1K%|(PvK3tni1FK9AGmjE)aUqiwZXZWGZ^l?|zI zqS=*KUL%+k@H^RnCd%EzDE$*);P|5ec;S4EttRXQH#JnOLUZz|wsfSXNZpoOs#Azu zOxYJF*W!(zRp1#T)vj6}t2yOSNP^yA0+2IK5{vW(DqrWt`Fr~z>}bZvDd722Mb5u0!7UpXtl09FH2 zaHjCSx%WY`{-k%Tx9#mrTw4)u%Dg|2X#V=Rw&fTz@y8A>xxm>!TzbXe#DJhx-<_Xr zwMHm?vEC%hROCpxt-ad^L8&2xUvr}>zHFhzEwx0wQ2nX{=~bK&S*~{Sp|-SBc;Cxh zjB7TkOB_WNof%0ksIv4A#~FPN%sdQ=0=4#j%cRnbiLvzp>B`7hNg_vF-F8LE)%2v_ z+vA@!&lz;2a2R`!rFxFi(y(TOy2lomR;Fyjg_!~S2Vhoq15OmvUFjQl&#g)6OabxA zq9MH>M^80D*`e(fOkoHKiQG)Q622 z(MT&tqxED}et+^VX-m$Mq%x-kD?HNn^_`J}?XW6Ok0t&maazZ2QjARe@jTOA0u}d0 z4n}Fc2yjAWy_d=dmV$8X&AxF);z4r(eYfyK4LF`wE@N)OGM;_3#7B~0dd|=6Zk$d!_&%H}Qe^0^(e+HXFzxxr z9fGmgvo|{544CdQaRM*(9FoEKv|;-=a+ZQHE)5Us5hW|bsknZB0v}z$=9Et`zQDG!{b`+%YF?x1;rw zcXBXS`r&V73UXMNbxdRjbBKxBQgUB6xmE2BeL2Yyy7^A8+#Ri6Z_1WcH0IJP7clB# zWlm#8ws<9?mTvEg3z<^RKbV?Nk34DGAF?x%>DIm+lPV?89pTJOuIAz@)$9x*a;}XP z70^AeD}6}w8D6CZeWzGYHlr_`Pna9^*8lKon96fSF9l7rsy~LdQ@aBT>6KNUtLCb% zi4U=u+E0_W)%33SQwXPbnzSkntD)65^tNX& z?rKT%?Xu3rC{`2`tQBObtqG2B&DM7%6mTZgeG4}RNmnxff@8@fS5fY5o8Zii;MfM$z0Oxr^w_Wl*`HdZDj8#iPtnrs_YD>86H+Mj z;EJK=8xK3qV@hi|qN5F^L{m8J66vnOzoiKv`d%~vAa3MlW!{KaKLcQs4I#a5tC#hU z#vzFb?8e3;LB=TL^QKQ!N?B5HzWbfZ*3oiu0+!36Hs{`|Edz-9(X?UmE6YFX{tb+a z)dTzLa_%irZ`P<-E&_I$mLut`InyM% z$vOS@1$zHa>`qH@kAqzgA9q27OKe9iX5zkec{wu!Xz~qJVU|ITf|1`RVJvzq4 zbm3alOR`)msbyZP>P~X;?1n@B+O5jUPi~Kp0Uum`Qxl_(G_PtjJ&>79S!%co+&#<_ zAZ7tBB@o{Ol(jSufR0u-QsPMNax zk23)6unFR3Hd>#E9X|m7s1ov=75&GY{Bj5f;cSEm(pgMyO8Yw`eIIrqd*-b;oQ9>n}iMhF>5q=HO?feJE+MzK1?^ z69UcqoAvKzpdLH-!qpz*?BqGy>)%*xSr`j#nH1{$@?>- z{|VUZYT}_FcdGD|f;#oqkiMf~OxMX`R^`wLwJaa_yT$gk!f(H7R2 zPOVuN^~oE)X6BiwiI1K;OSlNSc;omp1MpEM5K36F{w>_uPV|U3x~d^Vi&8Qv<1rIM zGxT*TI+eBoZ9(Rw7ii5Uh32)4kB#O+jugh)9R5!J2T|%LQ5$>=p#QZ~R>yw#(}FGj z_<7ZBtp6Nb+nps#bu;@)HaRDb&w78z*`Pz`GJy^SKw?i`+&ud-FxUJg`l2FHfJ|7! zqpqGv2-f?$8#EUYSu^oq9d)J<{)o04F6}j-IO#K<9w6;ExhB7(@g>u7{3Zk(^~CG$ z|5yP42)15RTj#w2p-PC^dEe#Y__3aFOyftEe2*`_IJ}nf!E}-xjiAJ;^stDV^U_&E z*-K|H9bSZ^5Pmz9*z@-(or7AC3rn?PKkQr`J+JJ?;xK;EshDEl0aCp5uLn`WRWr(Z z+cS$sM&IWYKyyW%g)GO3!8lrIzW{3#)?s$$p=oGdkfR2FscP6dRmIr!O>}$+v_N_* z`G=pUNs^C4+EOYuNPh8hC(iCN;QaQ#M+q)N%-n!nlYhud6XE}Gq-Np1!X5QfUEJgr z`N6o-pBcv4gcI^r$M)kZj?K-jYYK$evSh(S2wgjfeHMwHbf+B||Cx!v0Bq-avJ1Jn zu@>vJqY*VB998@OOLsM{W0GLcCXI^THg|j;*{R8Te!Cxez>ia0_|2?_i8dZ>jMXKw kYMM_UEo;knzj3x&@NU>ZoWx8H3xcVdSCs7^dl^Ij2O~J&Qvd(} diff --git a/labeling/example/images/2.jpeg b/labeling/example/images/2.jpeg deleted file mode 100644 index ea5807156d5eeb78a638e3f5f39df6e86040dde5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3034 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 diff --git a/labeling/example/images/3.jpeg b/labeling/example/images/3.jpeg deleted file mode 100644 index 4e9e7d56cc3c72ffe453615245cea4575f20d925..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4498 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 x=Ccf|qu|a?6KU1L>*o1vgxh%XaNA4 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 D*t>61 diff --git a/labeling/file_loading.py b/labeling/file_loading.py deleted file mode 100644 index 823084e..0000000 --- a/labeling/file_loading.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/python - -import json - -import xmltodict - - -def get_dict_from_xml(xml_path): - with open(xml_path, "r") as file: - # prefixes @/_ lead to issues with pydantic parsing! so simply use no prefix - xml_dict = xmltodict.parse(file.read(), attr_prefix="") - return xml_dict - - -def get_dict_from_json(path): - with open(path, "r") as file: - return json.load(file) - - -if __name__ == "__main__": - """convert XML to JSON""" - import sys - - assert len(sys.argv) == 2 - xml_path = sys.argv[1] - json_path = xml_path[:-3] + "json" - - print(f"converting {xml_path} to {json_path}") - - xml_dict = get_dict_from_xml(xml_path) - with open(json_path, "w") as outfile: - json.dump(xml_dict, outfile) diff --git a/labeling/parsers/coco_categories_parser.py b/labeling/parsers/coco_categories_parser.py deleted file mode 100644 index c496e77..0000000 --- a/labeling/parsers/coco_categories_parser.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Parser for configuration of COCO categories to convert CVAT XML to COCO Keypoints -""" -from typing import List - -from pydantic import BaseModel - - -class COCOSemanticTypeConfig(BaseModel): - name: str - n_keypoints: int - - -class COCOCategoryConfig(BaseModel): - supercategory: str - id: int - name: str - semantic_types: List[COCOSemanticTypeConfig] - - -class COCOCategoriesConfig(BaseModel): - categories: List[COCOCategoryConfig] diff --git a/labeling/parsers/cvat_keypoints_parser.py b/labeling/parsers/cvat_keypoints_parser.py deleted file mode 100644 index e48a8c1..0000000 --- a/labeling/parsers/cvat_keypoints_parser.py +++ /dev/null @@ -1,102 +0,0 @@ -"""Parser for CVAT Images 1.1 keypoint annotations - -see CVAT Documentation for format information - -This file was created by labeling the example images using the flow that is described in the repo. -Then this xml was converted to JSON using xmltodict -Then an initial version of the parser was created using https://pydantic-docs.helpmanual.io/datamodel_code_generator/: -`datamodel-codegen --input annotations.json --input-file-type json --output cvat_keypoints_parser.py --class-name CVATKeypointsParser` - -And the parser was then further finetuned. - -Note that the attributes cannot have _ as prefix for Pydantic. -""" - -# generated by datamodel-codegen: -# filename: annotations.json -# timestamp: 2022-08-24T12:15:52+00:00 -# then further changed by @tlips - -from __future__ import annotations - -from typing import Any, List, Optional, Union - -from pydantic import BaseModel - - -class Segment(BaseModel): - id: str - start: str - stop: str - url: str - - -class Segments(BaseModel): - segment: Segment - - -class Owner(BaseModel): - username: str - email: str - - -class LabelItem(BaseModel): - name: str - color: str - type: str - attributes: Any - - -class Labels(BaseModel): - label: Union[List[LabelItem], LabelItem] - - -class Task(BaseModel): - id: str - name: str - size: str - mode: str - overlap: str - bugtracker: Any - created: str - updated: str - subset: str - start_frame: str - stop_frame: str - frame_filter: Any - segments: Segments - owner: Owner - assignee: Any - labels: Labels - - -class Meta(BaseModel): - task: Task - dumped: str - - -class Point(BaseModel): - label: str - occluded: str - source: str - points: str - z_order: str - group_id: Optional[str] = "1" # set default group id to 1. - - -class ImageItem(BaseModel): - id: str - name: str - width: str - height: str - points: Optional[Union[List[Point], Point]] = None - - -class Annotations(BaseModel): - version: str - meta: Meta - image: List[ImageItem] - - -class CVATKeypointsParser(BaseModel): - annotations: Annotations diff --git a/labeling/requirements.txt b/labeling/requirements.txt deleted file mode 100644 index efed842..0000000 --- a/labeling/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -xmltodict -pydantic -tqdm diff --git a/labeling/scripts/crop_coco_dataset.py b/labeling/scripts/crop_coco_dataset.py deleted file mode 100644 index 71dc4b9..0000000 --- a/labeling/scripts/crop_coco_dataset.py +++ /dev/null @@ -1,113 +0,0 @@ -import json -import os -from argparse import ArgumentParser -from collections import defaultdict - -import albumentations as A -import cv2 - -from keypoint_detection.data.coco_dataset import COCOKeypointsDataset -from keypoint_detection.data.coco_parser import CocoKeypoints -from keypoint_detection.data.imageloader import ImageLoader, IOSafeImageLoaderDecorator - - -def save_cropped_image_and_edit_annotations( - i, image_info, image_annotations, height_new, width_new, image_loader, input_dataset_path, output_dataset_path -): - input_image_path = os.path.join(input_dataset_path, image_info.file_name) - image = image_loader.get_image(input_image_path, i) - - min_size = min(image.shape[0], image.shape[1]) - transform = A.Compose( - [ - A.CenterCrop(min_size, min_size), - A.Resize(height_new, width_new), - ], - keypoint_params=A.KeypointParams(format="xy", remove_invisible=False), - ) - - # Extract keypoints to the format albumentations wants. - image_keypoints = [] - for annotation in image_annotations: - annotation_keypoints = COCOKeypointsDataset.split_list_in_keypoints(annotation.keypoints) - for keypoint in annotation_keypoints: - image_keypoints.append(keypoint[:2]) - keypoints_xy = [keypoint[:2] for keypoint in image_keypoints] - - # Transform image and keypoints - transformed = transform(image=image, keypoints=keypoints_xy) - transformed_image = transformed["image"] - transformed_keypoints = transformed["keypoints"] - - # Edit the original keypoints. - index = 0 - for annotation in image_annotations: - for i in range(len(annotation.keypoints) // 3): - annotation.keypoints[3 * i : 3 * i + 2] = transformed_keypoints[index] - index += 1 - - # Save transformed image to disk - output_image_path = os.path.join(output_dataset_path, image_info.file_name) - image_directory = os.path.dirname(output_image_path) - os.makedirs(image_directory, exist_ok=True) - image_bgr = cv2.cvtColor(transformed_image, cv2.COLOR_RGB2BGR) - cv2.imwrite(output_image_path, image_bgr) - - -def create_cropped_dataset(input_json_dataset_path, height_new, width_new): - input_dataset_path = os.path.dirname(input_json_dataset_path) - output_dataset_path = input_dataset_path + f"_{height_new}x{width_new}" - - if os.path.exists(output_dataset_path): - print(f"{output_dataset_path} exists, quiting.") - return - - with open(input_json_dataset_path, "r") as file: - data = json.load(file) - parsed_coco = CocoKeypoints(**data) - - image_loader = IOSafeImageLoaderDecorator(ImageLoader()) - annotations = parsed_coco.annotations - - images_annotations = defaultdict(list) - for annotation in annotations: - print(type(annotation)) - images_annotations[annotation.image_id].append(annotation) - - for i, image_info in enumerate(parsed_coco.images): - image_annotations = images_annotations[image_info.id] - save_cropped_image_and_edit_annotations( - i, - image_info, - image_annotations, - height_new, - width_new, - image_loader, - input_dataset_path, - output_dataset_path, - ) - - annotations_json = os.path.join(output_dataset_path, os.path.basename(input_json_dataset_path)) - with open(annotations_json, "w") as file: - json.dump(parsed_coco.dict(exclude_none=True), file) - - return output_dataset_path - - -if __name__ == "__main__": - """ - example usage: - - python crop_coco_dataset.py datasets/towel_testset_0 256 256 - - This will create a new dataset called towel_testset_0_256x256 in the same directory as the old one. - The old dataset will be unaltered. - Currently only square outputs are supported. - """ - - parser = ArgumentParser() - parser.add_argument("input_json_dataset_path") - parser.add_argument("height_new", type=int) - parser.add_argument("width_new", type=int) - args = parser.parse_args() - create_cropped_dataset(**vars(args))