Skip to content

Commit

Permalink
feat: add to convert the circle to rect of lableme(#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
SWHL committed Dec 10, 2024
1 parent cda84de commit 10ef3b3
Show file tree
Hide file tree
Showing 6 changed files with 312 additions and 135 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ A tool for object detection and image segmentation dataset format conversion.
Supports conversion between labelme tool annotated data, labelImg tool annotated data, YOLO, PubLayNet and COCO data set formats.

## Supported conversions

```mermaid
flowchart LR
Expand All @@ -40,19 +41,22 @@ H --> J
```

## Installation

```bash
pip install label_convert
```

## Documentation

Full documentation can be found on [docs](https://rapidai.github.io/LabelConvert/docs) in Chinese.

## Contributing

Pull requests are welcome. For major changes, please open an issue first
to discuss what you would like to change.

Please make sure to update tests as appropriate.


## License

[Apache 2.0](https://choosealicense.com/licenses/apache-2.0/)
56 changes: 40 additions & 16 deletions label_convert/labelme_to_coco.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@
# @Contact: [email protected]
import argparse
import json
import math
import random
import shutil
import time
from pathlib import Path
from typing import List, Union
from typing import List, Tuple, Union

import cv2
import numpy as np
from tqdm import tqdm

ValueType = Union[str, Path, None]
RECTANGLE = "rectangle"
POLYGON = "polygon"
RECTANGLE: str = "rectangle"
POLYGON: str = "polygon"
CIRCLE: str = "circle"


class LabelmeToCOCO:
Expand Down Expand Up @@ -64,9 +66,7 @@ def __init__(

self.categories = self._get_category()

def __call__(
self,
):
def __call__(self):
img_list = self.get_img_list()
if not img_list:
raise ValueError(f"{self.data_dir} is empty!")
Expand Down Expand Up @@ -146,9 +146,7 @@ def _init_json(self):
}
return annotation_info

def _get_category(
self,
):
def _get_category(self):
json_list = Path(self.data_dir).glob("*.json")
all_categories = []
for json_path in json_list:
Expand Down Expand Up @@ -198,9 +196,9 @@ def generate_json(self, img_list, save_dir):
anno_list = []
for shape in shapes:
shape_type = shape.get("shape_type")
if shape_type not in [RECTANGLE, POLYGON]:
if shape_type not in [RECTANGLE, POLYGON, CIRCLE]:
print(
f"Current shape type is {shape_type}, not between {RECTANGLE} and {POLYGON}, skip"
f"Current shape type is {shape_type}, not between {RECTANGLE}, {CIRCLE} and {POLYGON}, skip"
)
continue

Expand All @@ -209,17 +207,25 @@ def generate_json(self, img_list, save_dir):
points = np.array(shape.get("points"))

if shape_type == RECTANGLE:
seg_points = [np.ravel(points, order="C").tolist()]

x0, y0 = np.min(points, axis=0)
x1, y1 = np.max(points, axis=0)
w, h = x1 - x1, y1 - y0
seg_points = [[x0, y0, x1, y0, x1, y1, x0, y1]]

w, h = x1 - x0, y1 - y0
bbox_points = [x0, y0, w, h]
area = w * h

elif shape_type == POLYGON:
seg_points = points.tolist()
bbox_points, area = self.cvt_poly_to_rect(img_h, img_w, points)
elif shape_type == CIRCLE:
circle_center, radius_point = points.tolist()
x0, y0, x1, y1 = self.cvt_circle_to_rect(
circle_center, radius_point
)
seg_points = [[x0, y0, x1, y0, x1, y1, x0, y1]]
w, h = x1 - x0, y1 - y0
bbox_points = [x0, y0, w, h]
area = w * h
else:
print(f"Current {shape_type} is not supported!")
continue
Expand Down Expand Up @@ -300,13 +306,31 @@ def get_mini_boxes(contour) -> List[int]:
box_h = right_bottom[1] - left_top[1]
return left_top + [box_w, box_h]

@staticmethod
def cvt_circle_to_rect(circle_center: float, radius_point: float) -> Tuple[float]:
"""
根据圆心和圆上一点计算正方形边界框的左上角和右下角坐标。
modified from https://blog.csdn.net/jacke121/article/details/137387901
"""
# 计算半径
radius = math.sqrt(
(circle_center[0] - radius_point[0]) ** 2
+ (circle_center[1] - radius_point[1]) ** 2
)

# 计算正方形边界框的左上角和右下角坐标
x0, y0 = circle_center[0] - radius, circle_center[1] - radius
x1, y1 = circle_center[0] + radius, circle_center[1] + radius

return x0, y0, x1, y1


def main():
parser = argparse.ArgumentParser("Datasets converter from labelme to COCO")
parser.add_argument(
"--data_dir",
type=str,
default="/Users/joshuawang/projects/_self/LabelConvert/data",
default="/Users/jiahuawang/projects/LabelConvert/tests/test_files/labelme_dataset",
)
parser.add_argument("--save_dir", type=str, default=None)
parser.add_argument("--val_ratio", type=float, default=0.2)
Expand Down
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def get_readme() -> str:
except ValueError:
latest_version = "0.0.1"

VERSION_NUM = obtainer.version_add_one(latest_version)
VERSION_NUM = obtainer.version_add_one(latest_version, add_patch=True)

# 优先提取commit message中的语义化版本号,如无,则自动加1
if len(sys.argv) > 2:
Expand Down Expand Up @@ -70,8 +70,9 @@ def get_readme() -> str:
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
],
python_requires=">=3.6,<3.12",
python_requires=">=3.6,<3.13",
entry_points={
"console_scripts": [
f"coco_to_labelImg={MODULE_NAME}.coco_to_labelImg:main",
Expand Down
40 changes: 38 additions & 2 deletions tests/test_files/labelme_dataset/4645_8.json

Large diffs are not rendered by default.

146 changes: 99 additions & 47 deletions tests/test_files/labelme_dataset/val_0001.json

Large diffs are not rendered by default.

Loading

0 comments on commit 10ef3b3

Please sign in to comment.