Skip to content

Commit

Permalink
[Docs] Add shape-level classification examples (#539)
Browse files Browse the repository at this point in the history
  • Loading branch information
CVHub520 committed Jul 27, 2024
1 parent 6c87f50 commit cf7ff2c
Show file tree
Hide file tree
Showing 14 changed files with 431 additions and 9 deletions.
61 changes: 52 additions & 9 deletions anylabeling/views/labeling/label_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import pathlib
import cv2
import re
import yaml
import webbrowser
from difflib import SequenceMatcher

Expand Down Expand Up @@ -111,6 +112,7 @@ def __init__(
if config is None:
config = get_config()
self._config = config
self.label_flags = self._config["label_flags"]

# set default shape colors
Shape.line_color = QtGui.QColor(*self._config["shape"]["line_color"])
Expand Down Expand Up @@ -150,7 +152,7 @@ def __init__(
show_text_field=self._config["show_label_text_field"],
completion=self._config["label_completion"],
fit_to_content=self._config["fit_to_content"],
flags=self._config["label_flags"],
flags=self.label_flags,
)

self.label_list = LabelListWidget()
Expand Down Expand Up @@ -864,9 +866,16 @@ def __init__(
icon="format_classify",
tip=self.tr("Upload Custom Image Flags File"),
)
upload_attr_file = action(
upload_label_flags_file = action(
self.tr("&Upload Label Flags File"),
self.upload_label_flags_file,
None,
icon="format_classify",
tip=self.tr("Upload Custom Label Flags File"),
)
upload_shape_attrs_file = action(
self.tr("&Upload Attributes File"),
self.upload_attr_file,
self.upload_shape_attrs_file,
None,
icon="format_classify",
tip=self.tr("Upload Custom Attributes File"),
Expand Down Expand Up @@ -1148,7 +1157,8 @@ def __init__(
create_point_mode=create_point_mode,
create_line_strip_mode=create_line_strip_mode,
upload_image_flags_file=upload_image_flags_file,
upload_attr_file=upload_attr_file,
upload_label_flags_file=upload_label_flags_file,
upload_shape_attrs_file=upload_shape_attrs_file,
upload_yolo_hbb_annotation=upload_yolo_hbb_annotation,
upload_yolo_obb_annotation=upload_yolo_obb_annotation,
upload_yolo_seg_annotation=upload_yolo_seg_annotation,
Expand Down Expand Up @@ -1330,7 +1340,8 @@ def __init__(
self.menus.upload,
(
upload_image_flags_file,
upload_attr_file,
upload_label_flags_file,
upload_shape_attrs_file,
None,
upload_yolo_hbb_annotation,
upload_yolo_obb_annotation,
Expand Down Expand Up @@ -2792,8 +2803,8 @@ def load_labels(self, shapes):
shape.close()

default_flags = {}
if self._config["label_flags"]:
for pattern, keys in self._config["label_flags"].items():
if self.label_flags:
for pattern, keys in self.label_flags.items():
if re.match(pattern, label):
for key in keys:
default_flags[key] = False
Expand Down Expand Up @@ -3588,7 +3599,38 @@ def upload_image_flags_file(self):
msg_box.setWindowTitle(self.tr("Information"))
msg_box.exec_()

def upload_attr_file(self):
def upload_label_flags_file(self):
filter = "Label Flags Files (*.yaml);;All Files (*)"
file_path, _ = QtWidgets.QFileDialog.getOpenFileName(
self,
self.tr("Select a specific flags file"),
"",
filter,
)
if not file_path:
return

with open(file_path, "r", encoding="utf-8") as f:
# Each line in the file is an flag-level flag
self.label_flags = yaml.safe_load(f)
for label in list(self.label_flags.keys()):
if not self.unique_label_list.find_items_by_label(label):
item = self.unique_label_list.create_item_from_label(label)
self.unique_label_list.addItem(item)
rgb = self._get_rgb_by_label(label)
self.unique_label_list.set_item_label(
item, label, rgb, LABEL_OPACITY
)
self.label_dialog.upload_flags(self.label_flags)

msg_box = QMessageBox()
msg_box.setIcon(QMessageBox.Information)
msg_box.setText(self.tr("Success!"))
msg_box.setInformativeText(self.tr("Uploading successfully!"))
msg_box.setWindowTitle(self.tr("Information"))
msg_box.exec_()

def upload_shape_attrs_file(self):
filter = "Attribute Files (*.json);;All Files (*)"
file_path, _ = QtWidgets.QFileDialog.getOpenFileName(
self,
Expand Down Expand Up @@ -3617,7 +3659,8 @@ def upload_attr_file(self):

msg_box = QMessageBox()
msg_box.setIcon(QMessageBox.Information)
msg_box.setInformativeText(self.tr(f"Attribute file loaded successfully!"))
msg_box.setText(self.tr("Success!"))
msg_box.setInformativeText(self.tr("Uploading successfully!"))
msg_box.setWindowTitle(self.tr("Information"))
msg_box.exec_()

Expand Down
3 changes: 3 additions & 0 deletions anylabeling/views/labeling/widgets/label_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,9 @@ def postprocess(self):
text = text.trimmed()
self.edit.setText(text)

def upload_flags(self, flags):
self._flags = flags

def update_flags(self, label_new):
# keep state of shared flags
flags_old = self.get_flags()
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
115 changes: 115 additions & 0 deletions examples/classification/shape-level/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Shape-level Classification Example

## Multi-task Classification

### Introduction

**Multi-task Classification** involves training a model to perform multiple classification tasks simultaneously. For example, a model could be trained to classify both the type of person and vehicle attributes in a single image.

<img src=".data/annotated_person_attributes.png" width="100%" />
<img src=".data/annotated_vehicle_attributes.png" width="100%" />

### Usage

**Step 0: Preparation**

Prepare a attributes file like [attributes.json](./attributes.json). An example is shown below:

```json
{
"vehicle": {
"bodyColor": [
"red",
"white",
"blue"
],
"vehicleType": [
"SUV",
"sedan",
"bus",
"truck"
]
},
"person": {
"wearsGlasses": ["yes", "no"],
"wearsMask": ["yes", "no"],
"clothingColor": [
"red",
"green",
"blue"
]
}
}

```

**Step 1: Run the Application**

```bash
python anylabeling/app.py
```

**Step 2: Upload the Configuration File**

Click on `Upload -> Upload Attributes File` in the top menu bar and select the prepared configuration file to upload.

For detailed output examples, refer to [this file](./sources/multi-task/elon-musk-tesla.json).


## Multiclass & Multilabel Classification

Similar to [Image-Level Classification](../image-level/README.md), you can also conduct multiclass and multilabel classification for Shape-Level Annotation.

<img src=".data/annotated_person_flags.png" width="100%" />
<img src=".data/annotated_helmet_flags.png" width="100%" />

## Usage

### GUI Import (Recommended)

**Step 0: Preparation**

Prepare a flags file like [label_flags.yaml](./label_flags.yaml). An example is shown below:

```YAML
person:
- male
- female
helmet:
- white
- red
- blue
- yellow
- green
```
**Step 1: Run the Application**
```bash
python anylabeling/app.py
```

**Step 2: Upload the Configuration File**

Click on `Upload -> Upload Label Flags File` in the top menu bar and select the prepared configuration file to upload.

### Command Line Loading

**Option 1: Quick Start**

```bash
python anylabeling/app.py --labels person,helmet --labelflags "{'person': ['male', 'female'], 'helmet': ['white', 'red', 'blue', 'yellow', 'green']}" --validatelabel exact
```

> [!TIP]
> The `labelflags` key field supports regular expressions. For instance, you can use patterns like `{person-\d+: [male, tall], "dog-\d+": [black, brown, white], .*: [occluded]}`.
**Option 2: Using a Configuration File**

```bash
python anylabeling/app.py --labels labels.txt --labelflags label_flags.yaml --validatelabel exact
```

For detailed output examples, refer to [this file](./sources/multi-label/worker.json).


24 changes: 24 additions & 0 deletions examples/classification/shape-level/attributes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"vehicle": {
"bodyColor": [
"red",
"white",
"blue"
],
"vehicleType": [
"SUV",
"sedan",
"bus",
"truck"
]
},
"person": {
"wearsGlasses": ["yes", "no"],
"wearsMask": ["yes", "no"],
"clothingColor": [
"red",
"green",
"blue"
]
}
}
9 changes: 9 additions & 0 deletions examples/classification/shape-level/label_flags.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
person:
- male
- female
helmet:
- white
- red
- blue
- yellow
- green
2 changes: 2 additions & 0 deletions examples/classification/shape-level/labels.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
person
helmet
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit cf7ff2c

Please sign in to comment.