Skip to content

Commit

Permalink
feat: Image annotator #1323 (#1400)
Browse files Browse the repository at this point in the history
  • Loading branch information
mturoci authored May 17, 2022
1 parent 8e493d7 commit c0c1143
Show file tree
Hide file tree
Showing 12 changed files with 1,189 additions and 131 deletions.
32 changes: 32 additions & 0 deletions py/examples/image_annotator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Form / Image Annotator
# Use when you need to annotate images.
# #form #annotator #image
# ---
from h2o_wave import main, app, Q, ui


@app('/demo')
async def serve(q: Q):
if q.args.annotator is not None:
q.page['example'].items = [
ui.text(f'annotator={q.args.annotator}'),
ui.button(name='back', label='Back', primary=True),
]
else:
q.page['example'] = ui.form_card(box='1 1 9 -1', items=[
ui.image_annotator(
name='annotator',
title='Drag to annotate',
image='https://images.pexels.com/photos/2696064/pexels-photo-2696064.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1',
image_height='700px',
tags=[
ui.image_annotator_tag(name='p', label='Person', color='$cyan'),
ui.image_annotator_tag(name='f', label='Food', color='$blue'),
],
items=[
ui.image_annotator_item(shape=ui.image_annotator_rect(x1=649, y1=393, x2=383, y2=25), tag='p'),
],
),
ui.button(name='submit', label='Submit', primary=True)
])
await q.page.save()
1 change: 1 addition & 0 deletions py/examples/tour.conf
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ table_menu.py
table_markdown.py
tags.py
image.py
image_annotator.py
file_stream.py
frame.py
frame_path.py
Expand Down
281 changes: 279 additions & 2 deletions py/h2o_wave/types.py

Large diffs are not rendered by default.

100 changes: 99 additions & 1 deletion py/h2o_wave/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -2298,7 +2298,7 @@ def text_annotator_item(
Args:
text: Text to be highlighted.
tag: Tag connected to the highlighted text.
tag: The `name` of the text annotator tag to refer to for the `label` and `color` of this item.
Returns:
A `h2o_wave.types.TextAnnotatorItem` instance.
"""
Expand Down Expand Up @@ -2340,6 +2340,104 @@ def text_annotator(
))


def image_annotator_tag(
name: str,
label: str,
color: str,
) -> ImageAnnotatorTag:
"""Create a unique tag type for use in an image annotator.
Args:
name: An identifying name for this tag.
label: Text to be displayed for the annotation.
color: Hex or RGB color string to be used as the background color.
Returns:
A `h2o_wave.types.ImageAnnotatorTag` instance.
"""
return ImageAnnotatorTag(
name,
label,
color,
)


def image_annotator_rect(
x1: int,
y1: int,
x2: int,
y2: int,
) -> ImageAnnotatorShape:
"""Create a rectangular annotation shape.
Args:
x1: `x` coordinate of the rectangle's corner.
y1: `y` coordinate of the rectangle's corner.
x2: `x` coordinate of the diagonally opposite corner.
y2: `y` coordinate of the diagonally opposite corner.
Returns:
A `h2o_wave.types.ImageAnnotatorRect` instance.
"""
return ImageAnnotatorShape(rect=ImageAnnotatorRect(
x1,
y1,
x2,
y2,
))


def image_annotator_item(
shape: ImageAnnotatorShape,
tag: str,
) -> ImageAnnotatorItem:
"""Create an annotator item with initial selected tags or no tag for plaintext.
Args:
shape: The annotation shape.
tag: The `name` of the image annotator tag to refer to for the `label` and `color` of this item.
Returns:
A `h2o_wave.types.ImageAnnotatorItem` instance.
"""
return ImageAnnotatorItem(
shape,
tag,
)


def image_annotator(
name: str,
image: str,
title: str,
tags: List[ImageAnnotatorTag],
items: Optional[List[ImageAnnotatorItem]] = None,
trigger: Optional[bool] = None,
image_height: Optional[str] = None,
) -> Component:
"""Create an image annotator component.
This component allows annotating and labeling parts of an image by drawing shapes with a pointing device.
Args:
name: An identifying name for this component.
image: The path or URL of the image to be presented for annotation.
title: The image annotator's title.
tags: The master list of tags that can be used for annotations.
items: Annotations to display on the image, if any.
trigger: True if the form should be submitted as soon as an annotation is drawn.
image_height: The card’s image height. The actual image size is used by default.
Returns:
A `h2o_wave.types.ImageAnnotator` instance.
"""
return Component(image_annotator=ImageAnnotator(
name,
image,
title,
tags,
items,
trigger,
image_height,
))


def facepile(
items: List[Component],
name: Optional[str] = None,
Expand Down
108 changes: 107 additions & 1 deletion r/R/ui.R
Original file line number Diff line number Diff line change
Expand Up @@ -2679,7 +2679,7 @@ ui_text_annotator_tag <- function(
#' Create an annotator item with initial selected tags or no tag for plaintext.
#'
#' @param text Text to be highlighted.
#' @param tag Tag connected to the highlighted text.
#' @param tag The `name` of the text annotator tag to refer to for the `label` and `color` of this item.
#' @return A TextAnnotatorItem instance.
#' @export
ui_text_annotator_item <- function(
Expand Down Expand Up @@ -2730,6 +2730,112 @@ ui_text_annotator <- function(
return(.o)
}

#' Create a unique tag type for use in an image annotator.
#'
#' @param name An identifying name for this tag.
#' @param label Text to be displayed for the annotation.
#' @param color Hex or RGB color string to be used as the background color.
#' @return A ImageAnnotatorTag instance.
#' @export
ui_image_annotator_tag <- function(
name,
label,
color) {
.guard_scalar("name", "character", name)
.guard_scalar("label", "character", label)
.guard_scalar("color", "character", color)
.o <- list(
name=name,
label=label,
color=color)
class(.o) <- append(class(.o), c(.wave_obj, "WaveImageAnnotatorTag"))
return(.o)
}

#' Create a rectangular annotation shape.
#'
#' @param x1 `x` coordinate of the rectangle's corner.
#' @param y1 `y` coordinate of the rectangle's corner.
#' @param x2 `x` coordinate of the diagonally opposite corner.
#' @param y2 `y` coordinate of the diagonally opposite corner.
#' @return A ImageAnnotatorRect instance.
#' @export
ui_image_annotator_rect <- function(
x1,
y1,
x2,
y2) {
.guard_scalar("x1", "numeric", x1)
.guard_scalar("y1", "numeric", y1)
.guard_scalar("x2", "numeric", x2)
.guard_scalar("y2", "numeric", y2)
.o <- list(rect=list(
x1=x1,
y1=y1,
x2=x2,
y2=y2))
class(.o) <- append(class(.o), c(.wave_obj, "WaveImageAnnotatorShape"))
return(.o)
}

#' Create an annotator item with initial selected tags or no tag for plaintext.
#'
#' @param shape The annotation shape.
#' @param tag The `name` of the image annotator tag to refer to for the `label` and `color` of this item.
#' @return A ImageAnnotatorItem instance.
#' @export
ui_image_annotator_item <- function(
shape,
tag) {
.guard_scalar("shape", "WaveImageAnnotatorShape", shape)
.guard_scalar("tag", "character", tag)
.o <- list(
shape=shape,
tag=tag)
class(.o) <- append(class(.o), c(.wave_obj, "WaveImageAnnotatorItem"))
return(.o)
}

#' Create an image annotator component.
#'
#' This component allows annotating and labeling parts of an image by drawing shapes with a pointing device.
#'
#' @param name An identifying name for this component.
#' @param image The path or URL of the image to be presented for annotation.
#' @param title The image annotator's title.
#' @param tags The master list of tags that can be used for annotations.
#' @param items Annotations to display on the image, if any.
#' @param trigger True if the form should be submitted as soon as an annotation is drawn.
#' @param image_height The card’s image height. The actual image size is used by default.
#' @return A ImageAnnotator instance.
#' @export
ui_image_annotator <- function(
name,
image,
title,
tags,
items = NULL,
trigger = NULL,
image_height = NULL) {
.guard_scalar("name", "character", name)
.guard_scalar("image", "character", image)
.guard_scalar("title", "character", title)
.guard_vector("tags", "WaveImageAnnotatorTag", tags)
.guard_vector("items", "WaveImageAnnotatorItem", items)
.guard_scalar("trigger", "logical", trigger)
.guard_scalar("image_height", "character", image_height)
.o <- list(image_annotator=list(
name=name,
image=image,
title=title,
tags=tags,
items=items,
trigger=trigger,
image_height=image_height))
class(.o) <- append(class(.o), c(.wave_obj, "WaveComponent"))
return(.o)
}

#' A face pile displays a list of personas. Each circle represents a person and contains their image or initials.
#' Often this control is used when sharing who has access to a specific view or file.
#'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,39 @@
<option name="Python" value="true"/>
</context>
</template>
<template name="w_image_annotator_rect" value="ui.image_annotator_rect(x1=$x1$,y1=$y1$,x2=$x2$,y2=$y2$),$END$" description="Create a minimal Wave ImageAnnotatorRect." toReformat="true" toShortenFQNames="true">
<variable name="x1" expression="" defaultValue="&quot;None&quot;" alwaysStopAt="true"/>
<variable name="y1" expression="" defaultValue="&quot;None&quot;" alwaysStopAt="true"/>
<variable name="x2" expression="" defaultValue="&quot;None&quot;" alwaysStopAt="true"/>
<variable name="y2" expression="" defaultValue="&quot;None&quot;" alwaysStopAt="true"/>
<context>
<option name="Python" value="true"/>
</context>
</template>
<template name="w_image_annotator_tag" value="ui.image_annotator_tag(name='$name$',label='$label$',color='$color$'),$END$" description="Create a minimal Wave ImageAnnotatorTag." toReformat="true" toShortenFQNames="true">
<variable name="name" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="label" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="color" expression="" defaultValue="" alwaysStopAt="true"/>
<context>
<option name="Python" value="true"/>
</context>
</template>
<template name="w_image_annotator_item" value="ui.image_annotator_item(shape=$shape$,tag='$tag$'),$END$" description="Create a minimal Wave ImageAnnotatorItem." toReformat="true" toShortenFQNames="true">
<variable name="shape" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="tag" expression="" defaultValue="" alwaysStopAt="true"/>
<context>
<option name="Python" value="true"/>
</context>
</template>
<template name="w_image_annotator" value="ui.image_annotator(name='$name$',image='$image$',title='$title$',tags=[&#10; $tags$ &#10;]),$END$" description="Create a minimal Wave ImageAnnotator." toReformat="true" toShortenFQNames="true">
<variable name="name" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="image" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="title" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="tags" expression="" defaultValue="" alwaysStopAt="true"/>
<context>
<option name="Python" value="true"/>
</context>
</template>
<template name="w_label" value="ui.label(label='$label$'),$END$" description="Create a minimal Wave Label." toReformat="true" toShortenFQNames="true">
<variable name="label" expression="" defaultValue="" alwaysStopAt="true"/>
<context>
Expand Down Expand Up @@ -1195,7 +1228,7 @@
<option name="Python" value="true"/>
</context>
</template>
<template name="w_full_component" value="ui.component(text=$text$,text_xl=$text_xl$,text_l=$text_l$,text_m=$text_m$,text_s=$text_s$,text_xs=$text_xs$,label=$label$,separator=$separator$,progress=$progress$,message_bar=$message_bar$,textbox=$textbox$,checkbox=$checkbox$,toggle=$toggle$,choice_group=$choice_group$,checklist=$checklist$,dropdown=$dropdown$,combobox=$combobox$,slider=$slider$,spinbox=$spinbox$,date_picker=$date_picker$,color_picker=$color_picker$,button=$button$,buttons=$buttons$,mini_button=$mini_button$,mini_buttons=$mini_buttons$,file_upload=$file_upload$,table=$table$,link=$link$,links=$links$,tabs=$tabs$,expander=$expander$,frame=$frame$,markup=$markup$,template=$template$,picker=$picker$,range_slider=$range_slider$,stepper=$stepper$,visualization=$visualization$,vega_visualization=$vega_visualization$,stats=$stats$,inline=$inline$,image=$image$,persona=$persona$,text_annotator=$text_annotator$,facepile=$facepile$,copyable_text=$copyable_text$,menu=$menu$,tags=$tags$),$END$" description="Create Wave Component with full attributes." toReformat="true" toShortenFQNames="true">
<template name="w_full_component" value="ui.component(text=$text$,text_xl=$text_xl$,text_l=$text_l$,text_m=$text_m$,text_s=$text_s$,text_xs=$text_xs$,label=$label$,separator=$separator$,progress=$progress$,message_bar=$message_bar$,textbox=$textbox$,checkbox=$checkbox$,toggle=$toggle$,choice_group=$choice_group$,checklist=$checklist$,dropdown=$dropdown$,combobox=$combobox$,slider=$slider$,spinbox=$spinbox$,date_picker=$date_picker$,color_picker=$color_picker$,button=$button$,buttons=$buttons$,mini_button=$mini_button$,mini_buttons=$mini_buttons$,file_upload=$file_upload$,table=$table$,link=$link$,links=$links$,tabs=$tabs$,expander=$expander$,frame=$frame$,markup=$markup$,template=$template$,picker=$picker$,range_slider=$range_slider$,stepper=$stepper$,visualization=$visualization$,vega_visualization=$vega_visualization$,stats=$stats$,inline=$inline$,image=$image$,persona=$persona$,text_annotator=$text_annotator$,image_annotator=$image_annotator$,facepile=$facepile$,copyable_text=$copyable_text$,menu=$menu$,tags=$tags$),$END$" description="Create Wave Component with full attributes." toReformat="true" toShortenFQNames="true">
<variable name="text" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="text_xl" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="text_l" expression="" defaultValue="" alwaysStopAt="true"/>
Expand Down Expand Up @@ -1240,6 +1273,7 @@
<variable name="image" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="persona" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="text_annotator" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="image_annotator" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="facepile" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="copyable_text" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="menu" expression="" defaultValue="" alwaysStopAt="true"/>
Expand Down Expand Up @@ -1354,6 +1388,48 @@
<option name="Python" value="true"/>
</context>
</template>
<template name="w_full_image_annotator_rect" value="ui.image_annotator_rect(x1=$x1$,y1=$y1$,x2=$x2$,y2=$y2$),$END$" description="Create Wave ImageAnnotatorRect with full attributes." toReformat="true" toShortenFQNames="true">
<variable name="x1" expression="" defaultValue="&quot;None&quot;" alwaysStopAt="true"/>
<variable name="y1" expression="" defaultValue="&quot;None&quot;" alwaysStopAt="true"/>
<variable name="x2" expression="" defaultValue="&quot;None&quot;" alwaysStopAt="true"/>
<variable name="y2" expression="" defaultValue="&quot;None&quot;" alwaysStopAt="true"/>
<context>
<option name="Python" value="true"/>
</context>
</template>
<template name="w_full_image_annotator_shape" value="ui.image_annotator_shape(rect=$rect$),$END$" description="Create Wave ImageAnnotatorShape with full attributes." toReformat="true" toShortenFQNames="true">
<variable name="rect" expression="" defaultValue="" alwaysStopAt="true"/>
<context>
<option name="Python" value="true"/>
</context>
</template>
<template name="w_full_image_annotator_tag" value="ui.image_annotator_tag(name='$name$',label='$label$',color='$color$'),$END$" description="Create Wave ImageAnnotatorTag with full attributes." toReformat="true" toShortenFQNames="true">
<variable name="name" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="label" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="color" expression="" defaultValue="" alwaysStopAt="true"/>
<context>
<option name="Python" value="true"/>
</context>
</template>
<template name="w_full_image_annotator_item" value="ui.image_annotator_item(shape=$shape$,tag='$tag$'),$END$" description="Create Wave ImageAnnotatorItem with full attributes." toReformat="true" toShortenFQNames="true">
<variable name="shape" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="tag" expression="" defaultValue="" alwaysStopAt="true"/>
<context>
<option name="Python" value="true"/>
</context>
</template>
<template name="w_full_image_annotator" value="ui.image_annotator(name='$name$',image='$image$',title='$title$',trigger=$trigger$,image_height='$image_height$',tags=[&#10; $tags$ &#10;],items=[&#10; $items$ &#10;]),$END$" description="Create Wave ImageAnnotator with full attributes." toReformat="true" toShortenFQNames="true">
<variable name="name" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="image" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="title" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="trigger" expression="" defaultValue="&quot;False&quot;" alwaysStopAt="true"/>
<variable name="image_height" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="tags" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="items" expression="" defaultValue="" alwaysStopAt="true"/>
<context>
<option name="Python" value="true"/>
</context>
</template>
<template name="w_full_label" value="ui.label(label='$label$',required=$required$,disabled=$disabled$,width='$width$',visible=$visible$,tooltip='$tooltip$',name='$name$'),$END$" description="Create Wave Label with full attributes." toReformat="true" toShortenFQNames="true">
<variable name="label" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="required" expression="" defaultValue="&quot;False&quot;" alwaysStopAt="true"/>
Expand Down
Loading

0 comments on commit c0c1143

Please sign in to comment.