Upload folder using huggingface_hub
Browse files- README.md +2 -18
- app.py +33 -5
- src/backend/gradio_image_annotation/image_annotator.py +3 -0
- src/demo/app.py +33 -5
- src/frontend/Index.svelte +2 -0
- src/frontend/shared/Canvas.svelte +65 -38
- src/frontend/shared/ImageAnnotator.svelte +4 -2
- src/frontend/shared/ImageCanvas.svelte +5 -3
- src/pyproject.toml +1 -1
README.md
CHANGED
|
@@ -1,20 +1,3 @@
|
|
| 1 |
-
---
|
| 2 |
-
tags:
|
| 3 |
-
- gradio-custom-component
|
| 4 |
-
- gradio-template-Image
|
| 5 |
-
- bounding box
|
| 6 |
-
- annotator
|
| 7 |
-
- annotate
|
| 8 |
-
- boxes
|
| 9 |
-
title: gradio_image_annotation V0.0.8
|
| 10 |
-
colorFrom: yellow
|
| 11 |
-
colorTo: green
|
| 12 |
-
sdk: docker
|
| 13 |
-
pinned: false
|
| 14 |
-
license: apache-2.0
|
| 15 |
-
short_description: A Gradio component for image annotation
|
| 16 |
-
---
|
| 17 |
-
|
| 18 |
|
| 19 |
# `gradio_image_annotation`
|
| 20 |
<a href="https://pypi.org/project/gradio_image_annotation/" target="_blank"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/gradio_image_annotation"></a>
|
|
@@ -475,4 +458,5 @@ The code snippet below is accurate in cases where the component is used as both
|
|
| 475 |
value: dict | None
|
| 476 |
) -> dict | None:
|
| 477 |
return value
|
| 478 |
-
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
|
| 2 |
# `gradio_image_annotation`
|
| 3 |
<a href="https://pypi.org/project/gradio_image_annotation/" target="_blank"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/gradio_image_annotation"></a>
|
|
|
|
| 458 |
value: dict | None
|
| 459 |
) -> dict | None:
|
| 460 |
return value
|
| 461 |
+
```
|
| 462 |
+
|
app.py
CHANGED
|
@@ -1,7 +1,30 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
from gradio_image_annotation import image_annotator
|
| 3 |
|
| 4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
"image": "https://raw.githubusercontent.com/gradio-app/gradio/main/guides/assets/logo.png",
|
| 6 |
"boxes": [
|
| 7 |
{
|
|
@@ -9,8 +32,7 @@ example = {
|
|
| 9 |
"ymin": 70,
|
| 10 |
"xmax": 530,
|
| 11 |
"ymax": 500,
|
| 12 |
-
"
|
| 13 |
-
"color": (250, 185, 0),
|
| 14 |
}
|
| 15 |
]
|
| 16 |
}
|
|
@@ -29,19 +51,25 @@ def crop(annotations):
|
|
| 29 |
def get_boxes_json(annotations):
|
| 30 |
return annotations["boxes"]
|
| 31 |
|
|
|
|
| 32 |
with gr.Blocks() as demo:
|
| 33 |
with gr.Tab("Object annotation"):
|
| 34 |
annotator = image_annotator(
|
| 35 |
-
|
| 36 |
label_list=["Person", "Vehicle"],
|
| 37 |
label_colors=[(0, 255, 0), (255, 0, 0)],
|
| 38 |
)
|
| 39 |
button_get = gr.Button("Get bounding boxes")
|
| 40 |
json_boxes = gr.JSON()
|
| 41 |
button_get.click(get_boxes_json, annotator, json_boxes)
|
|
|
|
| 42 |
with gr.Tab("Crop"):
|
| 43 |
with gr.Row():
|
| 44 |
-
annotator_crop = image_annotator(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
image_crop = gr.Image()
|
| 46 |
button_crop = gr.Button("Crop")
|
| 47 |
button_crop.click(crop, annotator_crop, image_crop)
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
from gradio_image_annotation import image_annotator
|
| 3 |
|
| 4 |
+
|
| 5 |
+
example_annotation = {
|
| 6 |
+
"image": "https://gradio-builds.s3.amazonaws.com/demo-files/base.png",
|
| 7 |
+
"boxes": [
|
| 8 |
+
{
|
| 9 |
+
"xmin": 636,
|
| 10 |
+
"ymin": 575,
|
| 11 |
+
"xmax": 801,
|
| 12 |
+
"ymax": 697,
|
| 13 |
+
"label": "Vehicle",
|
| 14 |
+
"color": (255, 0, 0)
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"xmin": 360,
|
| 18 |
+
"ymin": 615,
|
| 19 |
+
"xmax": 386,
|
| 20 |
+
"ymax": 702,
|
| 21 |
+
"label": "Person",
|
| 22 |
+
"color": (0, 255, 0)
|
| 23 |
+
}
|
| 24 |
+
]
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
example_crop = {
|
| 28 |
"image": "https://raw.githubusercontent.com/gradio-app/gradio/main/guides/assets/logo.png",
|
| 29 |
"boxes": [
|
| 30 |
{
|
|
|
|
| 32 |
"ymin": 70,
|
| 33 |
"xmax": 530,
|
| 34 |
"ymax": 500,
|
| 35 |
+
"color": (100, 200, 255)
|
|
|
|
| 36 |
}
|
| 37 |
]
|
| 38 |
}
|
|
|
|
| 51 |
def get_boxes_json(annotations):
|
| 52 |
return annotations["boxes"]
|
| 53 |
|
| 54 |
+
|
| 55 |
with gr.Blocks() as demo:
|
| 56 |
with gr.Tab("Object annotation"):
|
| 57 |
annotator = image_annotator(
|
| 58 |
+
example_annotation,
|
| 59 |
label_list=["Person", "Vehicle"],
|
| 60 |
label_colors=[(0, 255, 0), (255, 0, 0)],
|
| 61 |
)
|
| 62 |
button_get = gr.Button("Get bounding boxes")
|
| 63 |
json_boxes = gr.JSON()
|
| 64 |
button_get.click(get_boxes_json, annotator, json_boxes)
|
| 65 |
+
|
| 66 |
with gr.Tab("Crop"):
|
| 67 |
with gr.Row():
|
| 68 |
+
annotator_crop = image_annotator(
|
| 69 |
+
example_crop,
|
| 70 |
+
image_type="numpy",
|
| 71 |
+
disable_edit_boxes=True
|
| 72 |
+
)
|
| 73 |
image_crop = gr.Image()
|
| 74 |
button_crop = gr.Button("Crop")
|
| 75 |
button_crop.click(crop, annotator_crop, image_crop)
|
src/backend/gradio_image_annotation/image_annotator.py
CHANGED
|
@@ -53,6 +53,7 @@ class image_annotator(Component):
|
|
| 53 |
handle_size: int | None = None,
|
| 54 |
box_thickness: int | None = None,
|
| 55 |
box_selected_thickness: int | None = None,
|
|
|
|
| 56 |
height: int | str | None = None,
|
| 57 |
width: int | str | None = None,
|
| 58 |
image_mode: Literal[
|
|
@@ -84,6 +85,7 @@ class image_annotator(Component):
|
|
| 84 |
handle_size: Size of the bounding box resize handles.
|
| 85 |
box_thickness: Thickness of the bounding box outline.
|
| 86 |
box_selected_thickness: Thickness of the bounding box outline when it is selected.
|
|
|
|
| 87 |
height: The height of the displayed image, specified in pixels if a number is passed, or in CSS units if a string is passed.
|
| 88 |
width: The width of the displayed image, specified in pixels if a number is passed, or in CSS units if a string is passed.
|
| 89 |
image_mode: "RGB" if color, or "L" if black and white. See https://pillow.readthedocs.io/en/stable/handbook/concepts.html for other supported image modes and their meaning.
|
|
@@ -140,6 +142,7 @@ class image_annotator(Component):
|
|
| 140 |
self.handle_size = handle_size
|
| 141 |
self.box_thickness = box_thickness
|
| 142 |
self.box_selected_thickness = box_selected_thickness
|
|
|
|
| 143 |
if label_list:
|
| 144 |
self.label_list = [(l, i) for i, l in enumerate(label_list)]
|
| 145 |
else:
|
|
|
|
| 53 |
handle_size: int | None = None,
|
| 54 |
box_thickness: int | None = None,
|
| 55 |
box_selected_thickness: int | None = None,
|
| 56 |
+
disable_edit_boxes: bool | None = None,
|
| 57 |
height: int | str | None = None,
|
| 58 |
width: int | str | None = None,
|
| 59 |
image_mode: Literal[
|
|
|
|
| 85 |
handle_size: Size of the bounding box resize handles.
|
| 86 |
box_thickness: Thickness of the bounding box outline.
|
| 87 |
box_selected_thickness: Thickness of the bounding box outline when it is selected.
|
| 88 |
+
disable_edit_boxes: Disables the ability to set and edit the label and color of the boxes.
|
| 89 |
height: The height of the displayed image, specified in pixels if a number is passed, or in CSS units if a string is passed.
|
| 90 |
width: The width of the displayed image, specified in pixels if a number is passed, or in CSS units if a string is passed.
|
| 91 |
image_mode: "RGB" if color, or "L" if black and white. See https://pillow.readthedocs.io/en/stable/handbook/concepts.html for other supported image modes and their meaning.
|
|
|
|
| 142 |
self.handle_size = handle_size
|
| 143 |
self.box_thickness = box_thickness
|
| 144 |
self.box_selected_thickness = box_selected_thickness
|
| 145 |
+
self.disable_edit_boxes = disable_edit_boxes
|
| 146 |
if label_list:
|
| 147 |
self.label_list = [(l, i) for i, l in enumerate(label_list)]
|
| 148 |
else:
|
src/demo/app.py
CHANGED
|
@@ -1,7 +1,30 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
from gradio_image_annotation import image_annotator
|
| 3 |
|
| 4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
"image": "https://raw.githubusercontent.com/gradio-app/gradio/main/guides/assets/logo.png",
|
| 6 |
"boxes": [
|
| 7 |
{
|
|
@@ -9,8 +32,7 @@ example = {
|
|
| 9 |
"ymin": 70,
|
| 10 |
"xmax": 530,
|
| 11 |
"ymax": 500,
|
| 12 |
-
"
|
| 13 |
-
"color": (250, 185, 0),
|
| 14 |
}
|
| 15 |
]
|
| 16 |
}
|
|
@@ -29,19 +51,25 @@ def crop(annotations):
|
|
| 29 |
def get_boxes_json(annotations):
|
| 30 |
return annotations["boxes"]
|
| 31 |
|
|
|
|
| 32 |
with gr.Blocks() as demo:
|
| 33 |
with gr.Tab("Object annotation"):
|
| 34 |
annotator = image_annotator(
|
| 35 |
-
|
| 36 |
label_list=["Person", "Vehicle"],
|
| 37 |
label_colors=[(0, 255, 0), (255, 0, 0)],
|
| 38 |
)
|
| 39 |
button_get = gr.Button("Get bounding boxes")
|
| 40 |
json_boxes = gr.JSON()
|
| 41 |
button_get.click(get_boxes_json, annotator, json_boxes)
|
|
|
|
| 42 |
with gr.Tab("Crop"):
|
| 43 |
with gr.Row():
|
| 44 |
-
annotator_crop = image_annotator(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
image_crop = gr.Image()
|
| 46 |
button_crop = gr.Button("Crop")
|
| 47 |
button_crop.click(crop, annotator_crop, image_crop)
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
from gradio_image_annotation import image_annotator
|
| 3 |
|
| 4 |
+
|
| 5 |
+
example_annotation = {
|
| 6 |
+
"image": "https://gradio-builds.s3.amazonaws.com/demo-files/base.png",
|
| 7 |
+
"boxes": [
|
| 8 |
+
{
|
| 9 |
+
"xmin": 636,
|
| 10 |
+
"ymin": 575,
|
| 11 |
+
"xmax": 801,
|
| 12 |
+
"ymax": 697,
|
| 13 |
+
"label": "Vehicle",
|
| 14 |
+
"color": (255, 0, 0)
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"xmin": 360,
|
| 18 |
+
"ymin": 615,
|
| 19 |
+
"xmax": 386,
|
| 20 |
+
"ymax": 702,
|
| 21 |
+
"label": "Person",
|
| 22 |
+
"color": (0, 255, 0)
|
| 23 |
+
}
|
| 24 |
+
]
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
example_crop = {
|
| 28 |
"image": "https://raw.githubusercontent.com/gradio-app/gradio/main/guides/assets/logo.png",
|
| 29 |
"boxes": [
|
| 30 |
{
|
|
|
|
| 32 |
"ymin": 70,
|
| 33 |
"xmax": 530,
|
| 34 |
"ymax": 500,
|
| 35 |
+
"color": (100, 200, 255)
|
|
|
|
| 36 |
}
|
| 37 |
]
|
| 38 |
}
|
|
|
|
| 51 |
def get_boxes_json(annotations):
|
| 52 |
return annotations["boxes"]
|
| 53 |
|
| 54 |
+
|
| 55 |
with gr.Blocks() as demo:
|
| 56 |
with gr.Tab("Object annotation"):
|
| 57 |
annotator = image_annotator(
|
| 58 |
+
example_annotation,
|
| 59 |
label_list=["Person", "Vehicle"],
|
| 60 |
label_colors=[(0, 255, 0), (255, 0, 0)],
|
| 61 |
)
|
| 62 |
button_get = gr.Button("Get bounding boxes")
|
| 63 |
json_boxes = gr.JSON()
|
| 64 |
button_get.click(get_boxes_json, annotator, json_boxes)
|
| 65 |
+
|
| 66 |
with gr.Tab("Crop"):
|
| 67 |
with gr.Row():
|
| 68 |
+
annotator_crop = image_annotator(
|
| 69 |
+
example_crop,
|
| 70 |
+
image_type="numpy",
|
| 71 |
+
disable_edit_boxes=True
|
| 72 |
+
)
|
| 73 |
image_crop = gr.Image()
|
| 74 |
button_crop = gr.Button("Crop")
|
| 75 |
button_crop.click(crop, annotator_crop, image_crop)
|
src/frontend/Index.svelte
CHANGED
|
@@ -41,6 +41,7 @@
|
|
| 41 |
export let handle_size: number;
|
| 42 |
export let box_thickness: number;
|
| 43 |
export let box_selected_thickness: number;
|
|
|
|
| 44 |
|
| 45 |
export let gradio: Gradio<{
|
| 46 |
change: never;
|
|
@@ -114,6 +115,7 @@
|
|
| 114 |
handleSize={handle_size}
|
| 115 |
boxThickness={box_thickness}
|
| 116 |
boxSelectedThickness={box_selected_thickness}
|
|
|
|
| 117 |
>
|
| 118 |
{#if active_source === "upload"}
|
| 119 |
<UploadText i18n={gradio.i18n} type="image" />
|
|
|
|
| 41 |
export let handle_size: number;
|
| 42 |
export let box_thickness: number;
|
| 43 |
export let box_selected_thickness: number;
|
| 44 |
+
export let disable_edit_boxes: boolean;
|
| 45 |
|
| 46 |
export let gradio: Gradio<{
|
| 47 |
change: never;
|
|
|
|
| 115 |
handleSize={handle_size}
|
| 116 |
boxThickness={box_thickness}
|
| 117 |
boxSelectedThickness={box_selected_thickness}
|
| 118 |
+
disableEditBoxes={disable_edit_boxes}
|
| 119 |
>
|
| 120 |
{#if active_source === "upload"}
|
| 121 |
<UploadText i18n={gradio.i18n} type="image" />
|
src/frontend/shared/Canvas.svelte
CHANGED
|
@@ -17,6 +17,7 @@
|
|
| 17 |
export let value: null | AnnotatedImageData;
|
| 18 |
export let choices = [];
|
| 19 |
export let choicesColors = [];
|
|
|
|
| 20 |
|
| 21 |
let canvas: HTMLCanvasElement;
|
| 22 |
let ctx: CanvasRenderingContext2D;
|
|
@@ -123,51 +124,75 @@
|
|
| 123 |
}
|
| 124 |
|
| 125 |
function onAddBox() {
|
| 126 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
}
|
| 128 |
|
| 129 |
function onModalNewChange(event) {
|
| 130 |
newModalVisible = false;
|
| 131 |
const { detail } = event;
|
| 132 |
-
let label = detail.label;
|
| 133 |
-
let color = detail.color;
|
| 134 |
let ok = detail.ok;
|
| 135 |
if (ok) {
|
| 136 |
-
|
| 137 |
-
color = Colors[value.boxes.length % Colors.length];
|
| 138 |
-
} else {
|
| 139 |
-
color = colorHexToRGB(color);
|
| 140 |
-
}
|
| 141 |
-
let xmin = (imageWidth / 3) / scaleFactor;
|
| 142 |
-
let xmax = ((imageWidth / 3)*2) / scaleFactor;
|
| 143 |
-
let ymin = (imageHeight / 3) / scaleFactor;
|
| 144 |
-
let ymax = ((imageHeight / 3)*2) / scaleFactor;
|
| 145 |
-
let box = new Box(
|
| 146 |
-
draw,
|
| 147 |
-
canvasXmin,
|
| 148 |
-
canvasYmin,
|
| 149 |
-
canvasXmax,
|
| 150 |
-
canvasYmax,
|
| 151 |
-
label,
|
| 152 |
-
Math.round(xmin),
|
| 153 |
-
Math.round(ymin),
|
| 154 |
-
Math.round(xmax),
|
| 155 |
-
Math.round(ymax),
|
| 156 |
-
color,
|
| 157 |
-
boxAlpha,
|
| 158 |
-
boxMinSize,
|
| 159 |
-
handleSize,
|
| 160 |
-
boxThickness,
|
| 161 |
-
boxSelectedThickness
|
| 162 |
-
);
|
| 163 |
-
value.boxes = [box, ...value.boxes];
|
| 164 |
-
draw();
|
| 165 |
-
dispatch("change");
|
| 166 |
}
|
| 167 |
}
|
| 168 |
|
| 169 |
function onEditBox() {
|
| 170 |
-
if (selectedBox >= 0 && selectedBox < value.boxes.length) {
|
| 171 |
editModalVisible = true;
|
| 172 |
}
|
| 173 |
}
|
|
@@ -363,10 +388,12 @@
|
|
| 363 |
class="icon"
|
| 364 |
on:click={() => onAddBox()}><Add/></button
|
| 365 |
>
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
|
|
|
|
|
|
|
| 370 |
<button
|
| 371 |
class="icon"
|
| 372 |
on:click={() => onDeleteBox()}><Clear/></button
|
|
|
|
| 17 |
export let value: null | AnnotatedImageData;
|
| 18 |
export let choices = [];
|
| 19 |
export let choicesColors = [];
|
| 20 |
+
export let disableEditBoxes: boolean = false;
|
| 21 |
|
| 22 |
let canvas: HTMLCanvasElement;
|
| 23 |
let ctx: CanvasRenderingContext2D;
|
|
|
|
| 124 |
}
|
| 125 |
|
| 126 |
function onAddBox() {
|
| 127 |
+
if (!disableEditBoxes){
|
| 128 |
+
newModalVisible = true;
|
| 129 |
+
} else {
|
| 130 |
+
createBox();
|
| 131 |
+
}
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
function createBox(
|
| 135 |
+
label = null,
|
| 136 |
+
color = null,
|
| 137 |
+
xmin = null,
|
| 138 |
+
ymin = null,
|
| 139 |
+
xmax = null,
|
| 140 |
+
ymax = null
|
| 141 |
+
){
|
| 142 |
+
if (color === null || color === "") {
|
| 143 |
+
color = Colors[value.boxes.length % Colors.length];
|
| 144 |
+
} else {
|
| 145 |
+
color = colorHexToRGB(color);
|
| 146 |
+
}
|
| 147 |
+
if (label === null){
|
| 148 |
+
label = "";
|
| 149 |
+
}
|
| 150 |
+
if (xmin === null){
|
| 151 |
+
xmin = (imageWidth / 3) / scaleFactor;
|
| 152 |
+
}
|
| 153 |
+
if (xmax === null){
|
| 154 |
+
xmax = ((imageWidth / 3)*2) / scaleFactor;
|
| 155 |
+
}
|
| 156 |
+
if (ymin === null){
|
| 157 |
+
ymin = (imageHeight / 3) / scaleFactor;
|
| 158 |
+
}
|
| 159 |
+
if (ymax === null){
|
| 160 |
+
ymax = ((imageHeight / 3)*2) / scaleFactor;
|
| 161 |
+
}
|
| 162 |
+
let box = new Box(
|
| 163 |
+
draw,
|
| 164 |
+
canvasXmin,
|
| 165 |
+
canvasYmin,
|
| 166 |
+
canvasXmax,
|
| 167 |
+
canvasYmax,
|
| 168 |
+
label,
|
| 169 |
+
Math.round(xmin),
|
| 170 |
+
Math.round(ymin),
|
| 171 |
+
Math.round(xmax),
|
| 172 |
+
Math.round(ymax),
|
| 173 |
+
color,
|
| 174 |
+
boxAlpha,
|
| 175 |
+
boxMinSize,
|
| 176 |
+
handleSize,
|
| 177 |
+
boxThickness,
|
| 178 |
+
boxSelectedThickness
|
| 179 |
+
);
|
| 180 |
+
value.boxes = [box, ...value.boxes];
|
| 181 |
+
draw();
|
| 182 |
+
dispatch("change");
|
| 183 |
}
|
| 184 |
|
| 185 |
function onModalNewChange(event) {
|
| 186 |
newModalVisible = false;
|
| 187 |
const { detail } = event;
|
|
|
|
|
|
|
| 188 |
let ok = detail.ok;
|
| 189 |
if (ok) {
|
| 190 |
+
createBox(detail.label, detail.color)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
}
|
| 192 |
}
|
| 193 |
|
| 194 |
function onEditBox() {
|
| 195 |
+
if (selectedBox >= 0 && selectedBox < value.boxes.length && !disableEditBoxes) {
|
| 196 |
editModalVisible = true;
|
| 197 |
}
|
| 198 |
}
|
|
|
|
| 388 |
class="icon"
|
| 389 |
on:click={() => onAddBox()}><Add/></button
|
| 390 |
>
|
| 391 |
+
{#if !disableEditBoxes}
|
| 392 |
+
<button
|
| 393 |
+
class="icon"
|
| 394 |
+
on:click={() => onEditBox()}><Edit/></button
|
| 395 |
+
>
|
| 396 |
+
{/if}
|
| 397 |
<button
|
| 398 |
class="icon"
|
| 399 |
on:click={() => onDeleteBox()}><Clear/></button
|
src/frontend/shared/ImageAnnotator.svelte
CHANGED
|
@@ -30,6 +30,7 @@
|
|
| 30 |
export let boxMinSize: number;
|
| 31 |
export let handleSize: number;
|
| 32 |
export let boxThickness: number;
|
|
|
|
| 33 |
export let boxSelectedThickness: number;
|
| 34 |
export let max_file_size: number | null = null;
|
| 35 |
export let cli_upload: Client["upload"];
|
|
@@ -148,8 +149,9 @@
|
|
| 148 |
{labelColors}
|
| 149 |
{boxMinSize}
|
| 150 |
{interactive}
|
| 151 |
-
|
| 152 |
-
|
|
|
|
| 153 |
boxSelectedThickness={boxSelectedThickness}
|
| 154 |
src={value.image.url}
|
| 155 |
/>
|
|
|
|
| 30 |
export let boxMinSize: number;
|
| 31 |
export let handleSize: number;
|
| 32 |
export let boxThickness: number;
|
| 33 |
+
export let disableEditBoxes: boolean;
|
| 34 |
export let boxSelectedThickness: number;
|
| 35 |
export let max_file_size: number | null = null;
|
| 36 |
export let cli_upload: Client["upload"];
|
|
|
|
| 149 |
{labelColors}
|
| 150 |
{boxMinSize}
|
| 151 |
{interactive}
|
| 152 |
+
{handleSize}
|
| 153 |
+
{boxThickness}
|
| 154 |
+
{disableEditBoxes}
|
| 155 |
boxSelectedThickness={boxSelectedThickness}
|
| 156 |
src={value.image.url}
|
| 157 |
/>
|
src/frontend/shared/ImageCanvas.svelte
CHANGED
|
@@ -19,6 +19,7 @@
|
|
| 19 |
export let boxThickness: number;
|
| 20 |
export let boxSelectedThickness: number;
|
| 21 |
export let value: null | AnnotatedImageData;
|
|
|
|
| 22 |
|
| 23 |
let resolved_src: typeof src;
|
| 24 |
|
|
@@ -57,8 +58,9 @@
|
|
| 57 |
choices={labelList}
|
| 58 |
choicesColors={labelColors}
|
| 59 |
{boxMinSize}
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
|
|
|
| 63 |
imageUrl={resolved_src}
|
| 64 |
/>
|
|
|
|
| 19 |
export let boxThickness: number;
|
| 20 |
export let boxSelectedThickness: number;
|
| 21 |
export let value: null | AnnotatedImageData;
|
| 22 |
+
export let disableEditBoxes: boolean;
|
| 23 |
|
| 24 |
let resolved_src: typeof src;
|
| 25 |
|
|
|
|
| 58 |
choices={labelList}
|
| 59 |
choicesColors={labelColors}
|
| 60 |
{boxMinSize}
|
| 61 |
+
{handleSize}
|
| 62 |
+
{boxThickness}
|
| 63 |
+
{boxSelectedThickness}
|
| 64 |
+
{disableEditBoxes}
|
| 65 |
imageUrl={resolved_src}
|
| 66 |
/>
|
src/pyproject.toml
CHANGED
|
@@ -8,7 +8,7 @@ build-backend = "hatchling.build"
|
|
| 8 |
|
| 9 |
[project]
|
| 10 |
name = "gradio_image_annotation"
|
| 11 |
-
version = "0.0
|
| 12 |
description = "A Gradio component that can be used to annotate images with bounding boxes."
|
| 13 |
readme = "README.md"
|
| 14 |
license = "MIT"
|
|
|
|
| 8 |
|
| 9 |
[project]
|
| 10 |
name = "gradio_image_annotation"
|
| 11 |
+
version = "0.1.0"
|
| 12 |
description = "A Gradio component that can be used to annotate images with bounding boxes."
|
| 13 |
readme = "README.md"
|
| 14 |
license = "MIT"
|