parent
-
+
帧率
-
+
请输入抽帧间隔(FPS: {fps}):
-
+
正在解析中,请稍等。。。
-
+
取消
diff --git a/anylabeling/services/auto_labeling/depth_anything.py b/anylabeling/services/auto_labeling/depth_anything.py
index d185d036..a69d7918 100644
--- a/anylabeling/services/auto_labeling/depth_anything.py
+++ b/anylabeling/services/auto_labeling/depth_anything.py
@@ -322,7 +322,7 @@ def predict_shapes(self, image, image_path=None):
depth = self.postprocess(output, orig_shape)
image_dir_path = os.path.dirname(image_path)
- save_path = os.path.join(image_dir_path, "..", "depth")
+ save_path = os.path.join(image_dir_path, "..", "x-anylabeling-depth")
save_path = os.path.realpath(save_path)
os.makedirs(save_path, exist_ok=True)
image_file_name = os.path.basename(image_path)
diff --git a/anylabeling/services/auto_labeling/depth_anything_v2.py b/anylabeling/services/auto_labeling/depth_anything_v2.py
index 4b5178b8..d2872890 100644
--- a/anylabeling/services/auto_labeling/depth_anything_v2.py
+++ b/anylabeling/services/auto_labeling/depth_anything_v2.py
@@ -107,7 +107,7 @@ def predict_shapes(self, image, image_path=None):
depth = self.postprocess(outputs, orig_shape)
image_dir_path = os.path.dirname(image_path)
- save_path = os.path.join(image_dir_path, "..", "depth")
+ save_path = os.path.join(image_dir_path, "..", "x-anylabeling-depth")
save_path = os.path.realpath(save_path)
os.makedirs(save_path, exist_ok=True)
image_file_name = os.path.basename(image_path)
diff --git a/anylabeling/services/auto_labeling/model_manager.py b/anylabeling/services/auto_labeling/model_manager.py
index 031ca488..36057663 100644
--- a/anylabeling/services/auto_labeling/model_manager.py
+++ b/anylabeling/services/auto_labeling/model_manager.py
@@ -60,10 +60,11 @@ class ModelManager(QObject):
"yolov8_obb",
"yolov5_car_plate",
"rtmdet_pose",
- "depth_anything",
"yolov9",
"yolow",
"yolov10",
+ "rmbg",
+ "depth_anything",
"depth_anything_v2",
"yolow_ram",
"rtdetrv2",
@@ -1440,6 +1441,28 @@ def _load_model(self, model_id):
)
)
return
+ elif model_config["type"] == "rmbg":
+ from .rmbg import RMBG
+
+ try:
+ model_config["model"] = RMBG(
+ model_config, on_message=self.new_model_status.emit
+ )
+ self.auto_segmentation_model_unselected.emit()
+ except Exception as e: # noqa
+ self.new_model_status.emit(
+ self.tr(
+ "Error in loading model: {error_message}".format(
+ error_message=str(e)
+ )
+ )
+ )
+ print(
+ "Error in loading model: {error_message}".format(
+ error_message=str(e)
+ )
+ )
+ return
elif model_config["type"] == "depth_anything":
from .depth_anything import DepthAnything
diff --git a/anylabeling/services/auto_labeling/rmbg.py b/anylabeling/services/auto_labeling/rmbg.py
new file mode 100644
index 00000000..8095d2a6
--- /dev/null
+++ b/anylabeling/services/auto_labeling/rmbg.py
@@ -0,0 +1,139 @@
+import logging
+import os
+
+import cv2
+import numpy as np
+from PIL import Image
+from PyQt5.QtCore import QCoreApplication
+
+from anylabeling.app_info import __preferred_device__
+from anylabeling.views.labeling.utils.opencv import qt_img_to_rgb_cv_img
+from .model import Model
+from .types import AutoLabelingResult
+from .engines.build_onnx_engine import OnnxBaseModel
+
+
+class RMBG(Model):
+ """A class for removing backgrounds from images using BRIA RMBG 1.4 model."""
+
+ class Meta:
+ required_config_names = [
+ "type",
+ "name",
+ "display_name",
+ "model_path",
+ ]
+ widgets = ["button_run"]
+ output_modes = {
+ "rectangle": QCoreApplication.translate("Model", "Rectangle"),
+ }
+ default_output_mode = "rectangle"
+
+ def __init__(self, model_config, on_message) -> None:
+ # Run the parent class's init method
+ super().__init__(model_config, on_message)
+ model_name = self.config["type"]
+ model_abs_path = self.get_model_abs_path(self.config, "model_path")
+ if not model_abs_path or not os.path.isfile(model_abs_path):
+ raise FileNotFoundError(
+ QCoreApplication.translate(
+ "Model",
+ f"Could not download or initialize {model_name} model.",
+ )
+ )
+ self.model_path = model_abs_path
+ self.net = OnnxBaseModel(model_abs_path, __preferred_device__)
+ self.input_shape = self.net.get_input_shape()[-2:]
+ self.device = "cuda" if __preferred_device__ == "GPU" else "cpu"
+
+ def preprocess(self, image: np.ndarray) -> np.ndarray:
+ """
+ Preprocess the input image for the model.
+
+ Args:
+ image (np.ndarray): Input image as a numpy array.
+
+ Returns:
+ np.ndarray: Preprocessed image.
+ """
+ if len(image.shape) < 3:
+ image = np.expand_dims(image, axis=2)
+ image = cv2.resize(
+ image, self.input_shape, interpolation=cv2.INTER_LINEAR
+ )
+ image = image.astype(np.float32) / 255.0
+ image = (image - 0.5) / 1.0
+ image = np.transpose(image, (2, 0, 1))
+ return np.expand_dims(image, axis=0)
+
+ def forward(self, blob):
+ return self.net.get_ort_inference(blob, extract=True, squeeze=True)
+
+ def postprocess(
+ self, result: np.ndarray, original_size: tuple
+ ) -> np.ndarray:
+ """
+ Postprocess the model output.
+
+ Args:
+ result (np.ndarray): Model output.
+ original_size (tuple): Original image size (height, width).
+
+ Returns:
+ np.ndarray: Postprocessed image as a numpy array.
+ """
+ result = cv2.resize(
+ np.squeeze(result),
+ original_size[::-1],
+ interpolation=cv2.INTER_LINEAR,
+ )
+ max_val, min_val = np.max(result), np.min(result)
+ result = (result - min_val) / (max_val - min_val)
+ return (result * 255).astype(np.uint8)
+
+ def predict_shapes(self, image, image_path=None):
+ """
+ Remove the background from an image and save the result.
+
+ Args:
+ image (np.ndarray): Input image as a numpy array.
+ image_path (str): Path to the input image.
+ """
+ if image is None:
+ return []
+
+ try:
+ image = qt_img_to_rgb_cv_img(image, image_path)
+ except Exception as e: # noqa
+ logging.warning("Could not inference model")
+ logging.warning(e)
+ return []
+
+ blob = self.preprocess(image)
+ output = self.forward(blob)
+ result_image = self.postprocess(output, image.shape[:2])
+
+ # Create the final image with transparent background
+ pil_mask = Image.fromarray(result_image)
+ pil_image = Image.open(image_path)
+ pil_image = pil_image.convert("RGBA")
+ pil_mask = pil_mask.convert("L")
+
+ # Create a new image with an alpha channel
+ output_image = Image.new("RGBA", pil_image.size, (0, 0, 0, 0))
+ output_image.paste(pil_image, (0, 0), pil_mask)
+
+ # Save the result
+ image_dir_path = os.path.dirname(image_path)
+ save_path = os.path.join(image_dir_path, "..", "x-anylabeling-matting")
+ save_path = os.path.realpath(save_path)
+ os.makedirs(save_path, exist_ok=True)
+ image_file_name = os.path.basename(image_path)
+ save_name = os.path.splitext(image_file_name)[0] + ".png"
+ save_file = os.path.join(save_path, save_name)
+ output_image.save(save_file)
+
+ return AutoLabelingResult([], replace=False)
+
+ def unload(self):
+ del self.net
diff --git a/anylabeling/services/auto_labeling/segment_anything_2_video.py b/anylabeling/services/auto_labeling/segment_anything_2_video.py
index 94952b08..b1fd884a 100644
--- a/anylabeling/services/auto_labeling/segment_anything_2_video.py
+++ b/anylabeling/services/auto_labeling/segment_anything_2_video.py
@@ -322,23 +322,27 @@ def video_process(self, cv_image, filename):
) # give a unique id to each object we interact with (it can be any integers)
if prompt["type"] == "rectangle":
bbox = prompt["data"]
- _, out_obj_ids, out_mask_logits = (
- self.video_predictor.add_new_prompt(
- frame_idx=ann_frame_idx,
- obj_id=ann_obj_id,
- bbox=bbox,
- )
+ (
+ _,
+ out_obj_ids,
+ out_mask_logits,
+ ) = self.video_predictor.add_new_prompt(
+ frame_idx=ann_frame_idx,
+ obj_id=ann_obj_id,
+ bbox=bbox,
)
elif prompt["type"] == "point":
points = prompt["data"]["point_coords"]
labels = prompt["data"]["point_labels"]
- _, out_obj_ids, out_mask_logits = (
- self.video_predictor.add_new_prompt(
- frame_idx=ann_frame_idx,
- obj_id=ann_obj_id,
- points=points,
- labels=labels,
- )
+ (
+ _,
+ out_obj_ids,
+ out_mask_logits,
+ ) = self.video_predictor.add_new_prompt(
+ frame_idx=ann_frame_idx,
+ obj_id=ann_obj_id,
+ points=points,
+ labels=labels,
)
self.is_first_init = False
return [], False
diff --git a/anylabeling/services/auto_labeling/utils/sahi/postprocess/combine.py b/anylabeling/services/auto_labeling/utils/sahi/postprocess/combine.py
index 0ca79424..77022207 100644
--- a/anylabeling/services/auto_labeling/utils/sahi/postprocess/combine.py
+++ b/anylabeling/services/auto_labeling/utils/sahi/postprocess/combine.py
@@ -409,11 +409,11 @@ def __call__(
self.match_metric,
self.match_threshold,
):
- object_prediction_list[keep_ind] = (
- merge_object_prediction_pair(
- object_prediction_list[keep_ind].tolist(),
- object_prediction_list[merge_ind].tolist(),
- )
+ object_prediction_list[
+ keep_ind
+ ] = merge_object_prediction_pair(
+ object_prediction_list[keep_ind].tolist(),
+ object_prediction_list[merge_ind].tolist(),
)
selected_object_predictions.append(
object_prediction_list[keep_ind].tolist()
@@ -451,11 +451,11 @@ def __call__(
self.match_metric,
self.match_threshold,
):
- object_prediction_list[keep_ind] = (
- merge_object_prediction_pair(
- object_prediction_list[keep_ind].tolist(),
- object_prediction_list[merge_ind].tolist(),
- )
+ object_prediction_list[
+ keep_ind
+ ] = merge_object_prediction_pair(
+ object_prediction_list[keep_ind].tolist(),
+ object_prediction_list[merge_ind].tolist(),
)
selected_object_predictions.append(
object_prediction_list[keep_ind].tolist()
diff --git a/anylabeling/services/auto_labeling/utils/sahi/predict.py b/anylabeling/services/auto_labeling/utils/sahi/predict.py
index 013ba547..a730cfbd 100644
--- a/anylabeling/services/auto_labeling/utils/sahi/predict.py
+++ b/anylabeling/services/auto_labeling/utils/sahi/predict.py
@@ -113,9 +113,9 @@ def get_prediction(
shift_amount=shift_amount,
full_shape=full_shape,
)
- object_prediction_list: List[ObjectPrediction] = (
- detection_model.object_prediction_list
- )
+ object_prediction_list: List[
+ ObjectPrediction
+ ] = detection_model.object_prediction_list
# postprocess matching predictions
if postprocess is not None:
diff --git a/anylabeling/services/auto_labeling/utils/sahi/prediction.py b/anylabeling/services/auto_labeling/utils/sahi/prediction.py
index 86144a18..527d38fa 100644
--- a/anylabeling/services/auto_labeling/utils/sahi/prediction.py
+++ b/anylabeling/services/auto_labeling/utils/sahi/prediction.py
@@ -180,9 +180,9 @@ def __init__(
):
self.image: Image.Image = read_image_as_pil(image)
self.image_width, self.image_height = self.image.size
- self.object_prediction_list: List[ObjectPrediction] = (
- object_prediction_list
- )
+ self.object_prediction_list: List[
+ ObjectPrediction
+ ] = object_prediction_list
self.durations_in_seconds = durations_in_seconds
def export_visuals(
diff --git a/anylabeling/services/auto_labeling/utils/sahi/utils/coco.py b/anylabeling/services/auto_labeling/utils/sahi/utils/coco.py
index 2decc902..70e9ed5c 100644
--- a/anylabeling/services/auto_labeling/utils/sahi/utils/coco.py
+++ b/anylabeling/services/auto_labeling/utils/sahi/utils/coco.py
@@ -954,9 +954,9 @@ def update_categories(self, desired_name2id, update_image_filenames=False):
current_category_id = coco_category.id
current_category_name = coco_category.name
if current_category_name in desired_name2id.keys():
- currentid2desiredid_mapping[current_category_id] = (
- desired_name2id[current_category_name]
- )
+ currentid2desiredid_mapping[
+ current_category_id
+ ] = desired_name2id[current_category_name]
else:
# ignore categories that are not included in desired_name2id
currentid2desiredid_mapping[current_category_id] = None
diff --git a/anylabeling/services/auto_labeling/utils/sahi/utils/torch.py b/anylabeling/services/auto_labeling/utils/sahi/utils/torch.py
index 08f9319c..9198b813 100644
--- a/anylabeling/services/auto_labeling/utils/sahi/utils/torch.py
+++ b/anylabeling/services/auto_labeling/utils/sahi/utils/torch.py
@@ -74,13 +74,13 @@ def select_device(device: str):
cpu = device == "cpu"
mps = device == "mps" # Apple Metal Performance Shaders (MPS)
if cpu or mps:
- os.environ["CUDA_VISIBLE_DEVICES"] = (
- "-1" # force torch.cuda.is_available() = False
- )
+ os.environ[
+ "CUDA_VISIBLE_DEVICES"
+ ] = "-1" # force torch.cuda.is_available() = False
elif device: # non-cpu device requested
- os.environ["CUDA_VISIBLE_DEVICES"] = (
- device # set environment variable - must be before assert is_available()
- )
+ os.environ[
+ "CUDA_VISIBLE_DEVICES"
+ ] = device # set environment variable - must be before assert is_available()
if (
not cpu and not mps and is_torch_cuda_available()
diff --git a/anylabeling/services/auto_labeling/yolox_dwpose.py b/anylabeling/services/auto_labeling/yolox_dwpose.py
index 50e556d6..2e5a8732 100644
--- a/anylabeling/services/auto_labeling/yolox_dwpose.py
+++ b/anylabeling/services/auto_labeling/yolox_dwpose.py
@@ -127,9 +127,9 @@ def det_pre_process(self, img, net, swap=(2, 0, 1)):
(int(img.shape[1] * r), int(img.shape[0] * r)),
interpolation=cv2.INTER_LINEAR,
).astype(np.uint8)
- padded_img[: int(img.shape[0] * r), : int(img.shape[1] * r)] = (
- resized_img
- )
+ padded_img[
+ : int(img.shape[0] * r), : int(img.shape[1] * r)
+ ] = resized_img
padded_img = padded_img.transpose(swap)
padded_img = np.ascontiguousarray(padded_img, dtype=np.float32)
diff --git a/anylabeling/views/labeling/label_converter.py b/anylabeling/views/labeling/label_converter.py
index cadf8967..ece46a4d 100644
--- a/anylabeling/views/labeling/label_converter.py
+++ b/anylabeling/views/labeling/label_converter.py
@@ -999,9 +999,9 @@ def custom_to_voc(
ET.SubElement(size, "height").text = str(image_height)
ET.SubElement(size, "depth").text = str(image_depth)
source = ET.SubElement(root, "source")
- ET.SubElement(source, "database").text = (
- "https://github.com/CVHub520/X-AnyLabeling"
- )
+ ET.SubElement(
+ source, "database"
+ ).text = "https://github.com/CVHub520/X-AnyLabeling"
for shape in shapes:
label = shape["label"]
points = shape["points"]
diff --git a/anylabeling/views/labeling/label_file.py b/anylabeling/views/labeling/label_file.py
index b78a8fa9..d1ea93c9 100644
--- a/anylabeling/views/labeling/label_file.py
+++ b/anylabeling/views/labeling/label_file.py
@@ -101,9 +101,9 @@ def load(self, filename):
"UserWarning: Diagonal vertex mode is deprecated in X-AnyLabeling release v2.2.0 or later.\n"
"Please update your code to accommodate the new four-point mode."
)
- data["shapes"][i]["points"] = (
- utils.rectangle_from_diagonal(shape_points)
- )
+ data["shapes"][i][
+ "points"
+ ] = utils.rectangle_from_diagonal(shape_points)
data["imagePath"] = osp.basename(data["imagePath"])
if data["imageData"] is not None:
diff --git a/docs/en/model_zoo.md b/docs/en/model_zoo.md
index 5cb1ad10..0d8fb96a 100644
--- a/docs/en/model_zoo.md
+++ b/docs/en/model_zoo.md
@@ -204,6 +204,13 @@
| yolov8n-seg.onnx | [YOLOv8](https://github.com/ultralytics/ultralytics)-COCO | [yolov8n_seg.yaml](../../anylabeling/configs/auto_labeling/yolov8n_seg.yaml) | 13.18MB | [baidu](https://pan.baidu.com/s/1WQmN0yKBnm3PKgXTBFyQ-A?pwd=194i) \| [github](https://github.com/CVHub520/X-AnyLabeling/releases/download/v0.1.0/yolov8n-seg.onnx) |
+### Image Matting
+
+|Name|Description|Configuration|Size|Link|
+| --- | --- | --- | --- | --- |
+| bria-rmbg-1.4.onnx | [RMBG v1.4 (BRIA AI)](https://huggingface.co/briaai/RMBG-1.4) | [rmbg_v14.yaml](../../anylabeling/configs/auto_labeling/rmbg_v14.yaml) | 167.99MB | [baidu](https://pan.baidu.com/s/1tVuHF7NsZ7CXeqdQbsOhJg?pwd=9yny) \| [github](https://github.com/CVHub520/X-AnyLabeling/releases/download/v2.4.3/bria-rmbg-1.4.onnx) |
+
+
### Union Task
|Name|Description|Configuration|Size|Link|
diff --git a/docs/en/user_guide.md b/docs/en/user_guide.md
index 31de28f3..054b40cb 100644
--- a/docs/en/user_guide.md
+++ b/docs/en/user_guide.md
@@ -50,6 +50,7 @@
* [8.6 Depth Estimation](#86-depth-estimation)
* [8.7 Optical Character Recognition](#87-optical-character-recognition)
* [8.8 Interactive Video Object Segmentation](#88-interactive-video-object-segmentation)
+ * [8.9 Matting](#89-matting)
* [9. Models](#9-models)
@@ -708,6 +709,9 @@ Note: In `multi-label classification tasks`, if the user manually uploads a prop
- Interactive Video Object Segmentation: [Link](../../examples/interactive_video_object_segmentation/README.md)
+### 8.9 Matting
+
+- Image Matting: [Link](../../examples/matting/image_matting/README.md)
## 9. Models
diff --git a/docs/zh_cn/model_zoo.md b/docs/zh_cn/model_zoo.md
index c88233b3..d11da1e4 100644
--- a/docs/zh_cn/model_zoo.md
+++ b/docs/zh_cn/model_zoo.md
@@ -11,6 +11,7 @@
| yolov5s-cls.onnx | [YOLOv5-Cls](https://github.com/ultralytics/yolov5)-ImageNet | [yolov5s_cls.yaml](../../anylabeling/configs/auto_labeling/yolov5s_cls.yaml) | 20.81MB | [百度网盘](https://pan.baidu.com/s/1ftQ-CpbfsBOU1iaRgGsl0A?pwd=k2sm) \| [GitHub](https://github.com/CVHub520/X-AnyLabeling/releases/download/v2.2.0/yolov5s-cls.onnx) |
| yolov8s-cls.onnx | [YOLOv8-Cls](https://github.com/ultralytics/ultralytics)-ImageNet | [yolov8s_cls.yaml](../../anylabeling/configs/auto_labeling/yolov8s_cls.yaml) | 24.28MB | [百度网盘](https://pan.baidu.com/s/1-V_h-LJWbmuooMy9yRKq4g?pwd=klrg) \| [GitHub](https://github.com/CVHub520/X-AnyLabeling/releases/download/v2.2.0/yolov8s-cls.onnx) |
+
### 关键点检测
- 脸部关键点检测
@@ -202,6 +203,13 @@
| yolov8n-seg.onnx | [YOLOv8](https://github.com/ultralytics/ultralytics)-COCO | [yolov8n_seg.yaml](../../anylabeling/configs/auto_labeling/yolov8n_seg.yaml) | 13.18MB | [百度网盘](https://pan.baidu.com/s/1WQmN0yKBnm3PKgXTBFyQ-A?pwd=194i) \| [github](https://github.com/CVHub520/X-AnyLabeling/releases/download/v0.1.0/yolov8n-seg.onnx) |
+### 图像抠图
+
+|名称|描述|配置|大小|链接|
+| --- | --- | --- | --- | --- |
+| bria-rmbg-1.4.onnx | [RMBG v1.4 (BRIA AI)](https://huggingface.co/briaai/RMBG-1.4) | [rmbg_v14.yaml](../../anylabeling/configs/auto_labeling/rmbg_v14.yaml) | 167.99MB | [百度网盘](https://pan.baidu.com/s/1tVuHF7NsZ7CXeqdQbsOhJg?pwd=9yny) \| [github](https://github.com/CVHub520/X-AnyLabeling/releases/download/v2.4.3/bria-rmbg-1.4.onnx) |
+
+
### 多任务
|名称|描述|配置|大小|链接|
diff --git a/docs/zh_cn/user_guide.md b/docs/zh_cn/user_guide.md
index a0dceee8..030c9b7e 100644
--- a/docs/zh_cn/user_guide.md
+++ b/docs/zh_cn/user_guide.md
@@ -50,6 +50,7 @@
* [8.6 深度估计](#86-深度估计)
* [8.7 光学字符识别](#87-光学字符识别)
* [8.8 交互式视频目标分割](#88-交互式视频目标分割)
+ * [8.9 抠图](#89-抠图)
* [9. 模型](#9-模型)
## 1. 文件
@@ -712,6 +713,9 @@ labels:
- 交互式视频目标分割: [链接](../../examples/interactive_video_object_segmentation/README.md)
+### 8.9 抠图
+
+- 图像抠图:[链接](../../examples/matting/image_matting/README.md)
## 9. 模型
diff --git a/examples/estimation/depth_estimation/README.md b/examples/estimation/depth_estimation/README.md
index 42969dc6..b8afaaee 100644
--- a/examples/estimation/depth_estimation/README.md
+++ b/examples/estimation/depth_estimation/README.md
@@ -22,7 +22,7 @@ X-AnyLabeling offers a range of depth models for using, including [Depth Anythin
2. Select and load the Depth-Anything related model, or choose from other available depth estimation models.
3. Initiate the process by clicking `Run (i)`. Once you've verified that everything is set up correctly, use the keyboard shortcut `Ctrl+M` to process all images in one go.
-The output, once completed, will be automatically stored in a `depth` subdirectory within the same folder as your original image.
+The output, once completed, will be automatically stored in a `x-anylabeling-depth` subdirectory within the same folder as your original image.
diff --git a/examples/matting/image_matting/.data/British_Shorthair.jpg b/examples/matting/image_matting/.data/British_Shorthair.jpg
new file mode 100644
index 00000000..16e8e051
Binary files /dev/null and b/examples/matting/image_matting/.data/British_Shorthair.jpg differ
diff --git a/examples/matting/image_matting/.data/British_Shorthair.png b/examples/matting/image_matting/.data/British_Shorthair.png
new file mode 100644
index 00000000..fe998cc7
Binary files /dev/null and b/examples/matting/image_matting/.data/British_Shorthair.png differ
diff --git a/examples/matting/image_matting/README.md b/examples/matting/image_matting/README.md
new file mode 100644
index 00000000..9c9caff2
--- /dev/null
+++ b/examples/matting/image_matting/README.md
@@ -0,0 +1,17 @@
+# Image Matting Example
+
+## Introduction
+
+| Image | Result |
+|:---:|:---:|
+| ![](.data/British_Shorthair.jpg) | ![](.data/British_Shorthair.png) |
+
+**Image Matting** is the process of accurately estimating the foreground object in images and videos. It is a very important technique in image and video editing applications, particularly in film production for creating visual effects.
+
+## Usage
+
+1. Import your image (`Ctrl+I`) or video (`Ctrl+O`) file into the X-AnyLabeling.
+2. Select and load the `RMBG v1.4 (BRIA AI)` model, or choose from other available matting models.
+3. Initiate the process by clicking `Run (i)`. Once you've verified that everything is set up correctly, use the keyboard shortcut `Ctrl+M` to process all images in one go.
+
+The output, once completed, will be automatically stored in a `x-anylabeling-matting` subdirectory within the same folder as your original image.
diff --git a/tools/label_drawer.py b/tools/label_drawer.py
index 1049006c..2366c601 100644
--- a/tools/label_drawer.py
+++ b/tools/label_drawer.py
@@ -15,7 +15,9 @@
except ImportError:
print("Supervision library is not installed. Attempting to install...")
try:
- subprocess.check_call([sys.executable, "-m", "pip", "install", "supervision"])
+ subprocess.check_call(
+ [sys.executable, "-m", "pip", "install", "supervision"]
+ )
print("Supervision library installed successfully.")
import supervision as sv
except Exception as e:
@@ -440,8 +442,10 @@ def draw_rotation_from_custom(
xyxyxyxy = np.stack(xyxyxyxy_list, axis=0)
object_ids = np.array(cind_list, dtype=np.int32)
detections = sv.Detections(
- xyxy=xyxy, mask=None, class_id=object_ids,
- data={'xyxyxyxy': xyxyxyxy}
+ xyxy=xyxy,
+ mask=None,
+ class_id=object_ids,
+ data={"xyxyxyxy": xyxyxyxy},
)
# Annotate the image with boxes and optionally labels
@@ -463,37 +467,84 @@ def draw_rotation_from_custom(
def main():
parser = argparse.ArgumentParser(description="Label drawing tool")
- parser.add_argument("task", choices=["video", "polygon", "rectangle", "rotation"], help="Task to execute")
- parser.add_argument("--save_dir", required=True, help="Path to save directory")
- parser.add_argument("--image_path", required=True, help="Path to image directory")
+ parser.add_argument(
+ "task",
+ choices=["video", "polygon", "rectangle", "rotation"],
+ help="Task to execute",
+ )
+ parser.add_argument(
+ "--save_dir", required=True, help="Path to save directory"
+ )
+ parser.add_argument(
+ "--image_path", required=True, help="Path to image directory"
+ )
parser.add_argument("--label_path", help="Path to label directory")
- parser.add_argument("--classes", nargs="+", default=[], help="List of classes or path to classes.txt file")
- parser.add_argument("--frame_rate", type=int, default=25, help="Video frame rate")
- parser.add_argument("--save_box", action="store_true", help="Whether to save bounding box")
- parser.add_argument("--save_label", action="store_true", help="Whether to save label")
- parser.add_argument("--keep_ori_fn", action="store_true", help="Whether to keep original filename")
+ parser.add_argument(
+ "--classes",
+ nargs="+",
+ default=[],
+ help="List of classes or path to classes.txt file",
+ )
+ parser.add_argument(
+ "--frame_rate", type=int, default=25, help="Video frame rate"
+ )
+ parser.add_argument(
+ "--save_box", action="store_true", help="Whether to save bounding box"
+ )
+ parser.add_argument(
+ "--save_label", action="store_true", help="Whether to save label"
+ )
+ parser.add_argument(
+ "--keep_ori_fn",
+ action="store_true",
+ help="Whether to keep original filename",
+ )
args = parser.parse_args()
# Process classes argument
- if len(args.classes) == 1 and args.classes[0].endswith('.txt'):
+ if len(args.classes) == 1 and args.classes[0].endswith(".txt"):
# If a file path is provided, read classes from the file
- with open(args.classes[0], 'r') as f:
+ with open(args.classes[0], "r") as f:
args.classes = [line.strip() for line in f if line.strip()]
elif not args.classes:
print("Warning: No classes specified. All classes will be considered.")
if args.task == "video":
- create_video_from_images(args.image_path, args.save_dir, args.frame_rate)
+ create_video_from_images(
+ args.image_path, args.save_dir, args.frame_rate
+ )
elif args.task == "polygon":
- draw_polygon_from_custom(args.save_dir, args.image_path, args.label_path, args.classes, args.save_box, args.save_label, args.keep_ori_fn)
+ draw_polygon_from_custom(
+ args.save_dir,
+ args.image_path,
+ args.label_path,
+ args.classes,
+ args.save_box,
+ args.save_label,
+ args.keep_ori_fn,
+ )
elif args.task == "rectangle":
- draw_rectangle_from_custom(args.save_dir, args.image_path, args.label_path, args.classes, args.save_label, args.keep_ori_fn)
+ draw_rectangle_from_custom(
+ args.save_dir,
+ args.image_path,
+ args.label_path,
+ args.classes,
+ args.save_label,
+ args.keep_ori_fn,
+ )
elif args.task == "rotation":
- draw_rotation_from_custom(args.save_dir, args.image_path, args.label_path, args.classes, args.save_label, args.keep_ori_fn)
+ draw_rotation_from_custom(
+ args.save_dir,
+ args.image_path,
+ args.label_path,
+ args.classes,
+ args.save_label,
+ args.keep_ori_fn,
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
"""
Usage examples:
@@ -510,4 +561,3 @@ def main():
python tools/label_drawer.py rotation --save_dir --image_path --label_path --classes classes.txt --save_label
"""
main()
-
\ No newline at end of file