edgargg commited on
Commit
07b52cf
1 Parent(s): b8ca14d

Upload folder using huggingface_hub

Browse files
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
- example = {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- "label": "Gradio",
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
- {"image": "https://gradio-builds.s3.amazonaws.com/demo-files/base.png"},
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(example, image_type="numpy")
 
 
 
 
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
- example = {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- "label": "Gradio",
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
- {"image": "https://gradio-builds.s3.amazonaws.com/demo-files/base.png"},
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(example, image_type="numpy")
 
 
 
 
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
- newModalVisible = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- if (color === null || color === "") {
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
- <button
367
- class="icon"
368
- on:click={() => onEditBox()}><Edit/></button
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
- handleSize={handleSize}
152
- boxThickness={boxThickness}
 
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
- handleSize={handleSize}
61
- boxThickness={boxThickness}
62
- boxSelectedThickness={boxSelectedThickness}
 
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.8"
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"