Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image resize on runtime #10

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions ipyannotator/bbox_canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,20 @@ def get_image_size(path):

# Internal Cell

def draw_img(canvas, file, clear=False):
# draws resized image on canvas and returns scale used
def draw_img(canvas, file, clear=False, canvas_size=None, rescale=1.0):
# draws an image on canvas, a specific size can be passed to scale image
with hold_canvas(canvas):
if clear:
canvas.clear()

sprite1 = Image.from_file(file)

width_canvas, height_canvas = canvas.width, canvas.height
if canvas_size:
width_canvas, height_canvas = canvas_size
# if no specific size is passed, use current canvas size
else:
width_canvas, height_canvas = canvas.width, canvas.height

width_img, height_img = get_image_size(file)

ratio_canvas = float(width_canvas) / height_canvas
Expand All @@ -73,8 +78,8 @@ def draw_img(canvas, file, clear=False):
scale = height_canvas / height_img

canvas.draw_image(sprite1, 0, 0,
width=width_img * min(1, scale),
height=height_img * min(1, scale))
width=(width_img * min(1, scale)) * rescale,
height=(height_img * min(1, scale)) * rescale)
return scale

# Internal Cell
Expand Down Expand Up @@ -202,7 +207,6 @@ def _draw_bbox(self, change):
def _clear_bbox(self):
self._multi_canvas[self._box_layer].clear()


@traitlets.observe('image_path')
def _draw_image(self, image):
self._image_scale = draw_img(self._multi_canvas[self._image_layer], self.image_path, clear=True)
Expand Down
3 changes: 3 additions & 0 deletions ipyannotator/capture_annotator.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ def __init__(self, image_width=150, image_height=150,
indent=False,
layout=Layout(width='100px'))

self._none_checkbox.add_class("none-checkbox-class")
display(HTML("<style>.none-checkbox-class {margin-left: 10px;}</style>"))

self._controls_box = HBox([self._navi, self._save_btn, self._none_checkbox],
layout=Layout(display='flex', justify_content='center', flex_flow='wrap', align_items='center'))

Expand Down
32 changes: 29 additions & 3 deletions ipyannotator/im2im_annotator.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,39 @@
class ImCanvas(HBox, HasTraits):
image_path = Unicode()
_image_scale = Float()
_image_rescale = Float(1.0)

def __init__(self, width=150, height=150):

self._canvas = Canvas(width=width, height=height)
self._initial_canvas_size = self._canvas.size

super().__init__([self._canvas])

def _draw_image(self, canvas_size=None):
self._image_scale = draw_img(self._canvas, self.image_path, clear=True,
canvas_size=canvas_size, rescale=self._image_rescale)

@observe('image_path')
def _draw_image(self, change):
self._image_scale = draw_img(self._canvas, self.image_path, clear=True)
def _call_draw_image(self, change):
self._draw_image(self._initial_canvas_size)

# Add value as a read-only property
@property
def image_scale(self):
return self._image_scale

@observe('_image_rescale')
def _redraw_image(self, change):
# Resize canvas
new_width = self._initial_canvas_size[0] * self._image_rescale
new_height = self._initial_canvas_size[1] * self._image_rescale
self._canvas.size = (new_width, new_height)

# As draw_image method uses canvas current size, we pass
# as parameter the initial size of canvas (before rescaling it too)
self._draw_image(self._initial_canvas_size)

def _clear_image(self):
self._canvas.clear()

Expand Down Expand Up @@ -81,7 +98,7 @@ def __init__(self, im_width=300, im_height=300,

self._image = ImCanvas(width=im_width, height=im_height)

self._navi = Navi()
self._navi = Navi(disable_resize=False)

self._save_btn = Button(description="Save",
layout=Layout(width='auto'))
Expand All @@ -90,6 +107,8 @@ def __init__(self, im_width=300, im_height=300,
self._controls_box = HBox([self._navi, self._save_btn],
layout=Layout(display='flex', justify_content='center', flex_flow='wrap', align_items='center'))

self._controls_box.add_class("im2im-annotator-class")
display(HTML("<style>.im2im-annotator-class {margin-top: 10px;}</style>"))

self._grid_box = CaptureGrid(grid_item=ImageButton, image_width=label_width, image_height=label_height, n_rows=n_rows, n_cols=n_cols)

Expand All @@ -98,6 +117,7 @@ def __init__(self, im_width=300, im_height=300,
self._labels_box = VBox(children = [self._grid_label, self._grid_box],
layout=Layout(display='flex', justify_content='center', flex_wrap='wrap', align_items='center'))

self._navi._size_dropdown.observe(self.change_scale, names='value')

super().__init__(header=None,
left_sidebar=VBox([self._image, self._controls_box], layout=Layout(display='flex', justify_content='center', flex_wrap='wrap', align_items='center')),
Expand All @@ -107,6 +127,12 @@ def __init__(self, im_width=300, im_height=300,
pane_widths=(6, 4, 0),
pane_heights=(1, 1, 1))


def change_scale(self, change):
new_scale = int(change['new'])
if new_scale:
self._image._image_rescale = new_scale / 100

def on_client_ready(self, callback):
self._image.observe_client_ready(callback)

Expand Down
35 changes: 28 additions & 7 deletions ipyannotator/navi_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,44 @@
# Internal Cell
from ipywidgets import (AppLayout, Button, IntSlider,
HBox, Output,
Layout, Label)
from traitlets import Int, observe, link, HasTraits
Layout, Label, Dropdown)
from IPython.display import display, HTML
from traitlets import Int, Bool, observe, link, HasTraits

# Internal Cell

class NaviGUI(HBox):
max_im_number = Int(0)
disable_resize = Bool(True)

def __init__(self):
self._im_number_slider = IntSlider(min=0, max=self.max_im_number-1,
value=0, description='Image Nr.')
value=0, description='Image Nr.', style={'description_width': 'initial'},
layout=Layout(width='250px'))

self._prev_btn = Button(description='< Previous',
layout=Layout(width='auto'))

self._next_btn = Button(description='Next >',
layout=Layout(width='auto'))

super().__init__(children=[self._prev_btn, self._im_number_slider, self._next_btn],
layout=Layout(display='flex', flex_flow='row wrap', align_items='center'))
self._size_dropdown = Dropdown(options=['50', '75', '100', '150', '200'],
value='100', description="Size", disabled=self.disable_resize,
layout=Layout(width='auto'), style={'description_width': 'initial'})

self._im_number_slider.add_class("navi-class")
self._prev_btn.add_class("navi-class")
self._next_btn.add_class("navi-class")
self._size_dropdown.add_class("navi-class")

display(HTML("<style>.navi-class {margin-left: 5px; margin-right: 5px;}</style>"))
display(HTML("<style>.navi-class .widget-readout {border-style: groove; display: flex; align-items: center; justify-content: center}</style>"))

super().__init__(children=[self._prev_btn, self._im_number_slider, self._size_dropdown,
self._next_btn], layout=Layout(display='inline-flex',
flex_flow='row wrap',
align_items='center',
justify_content='space-around'))

@observe('max_im_number')
def check_im_num(self, change):
Expand All @@ -37,6 +55,7 @@ def check_im_num(self, change):
class NaviLogic(HasTraits):
index = Int(0)
max_im_number = Int(0)
disable_resize = Bool(True)

def __init__(self):
super().__init__()
Expand All @@ -52,8 +71,9 @@ class Navi(NaviGUI):
Represents simple navigation module with slider.

"""
def __init__(self, max_im_number=1):
def __init__(self, max_im_number=1, disable_resize=True):
self.max_im_number = max_im_number
self.disable_resize = disable_resize

super().__init__()

Expand All @@ -64,4 +84,5 @@ def __init__(self, max_im_number=1):

# link slider value to button increment logic
link((self._im_number_slider, 'value'), (self.model, 'index'))
link((self, 'max_im_number'), (self.model, 'max_im_number'))
link((self, 'max_im_number'), (self.model, 'max_im_number'))
link((self, 'disable_resize'), (self.model, 'disable_resize'))
33 changes: 22 additions & 11 deletions nbs/01_bbox_canvas.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -285,15 +285,20 @@
"source": [
"#exporti\n",
"\n",
"def draw_img(canvas, file, clear=False):\n",
" # draws resized image on canvas and returns scale used\n",
"def draw_img(canvas, file, clear=False, canvas_size=None, rescale=1.0):\n",
" # draws an image on canvas, a specific size can be passed to scale image\n",
" with hold_canvas(canvas):\n",
" if clear:\n",
" canvas.clear()\n",
"\n",
" sprite1 = Image.from_file(file)\n",
"\n",
" width_canvas, height_canvas = canvas.width, canvas.height\n",
" if canvas_size:\n",
" width_canvas, height_canvas = canvas_size\n",
" # if no specific size is passed, use current canvas size\n",
" else:\n",
" width_canvas, height_canvas = canvas.width, canvas.height\n",
"\n",
" width_img, height_img = get_image_size(file)\n",
"\n",
" ratio_canvas = float(width_canvas) / height_canvas\n",
Expand All @@ -307,8 +312,8 @@
" scale = height_canvas / height_img\n",
"\n",
" canvas.draw_image(sprite1, 0, 0, \n",
" width=width_img * min(1, scale),\n",
" height=height_img * min(1, scale))\n",
" width=(width_img * min(1, scale)) * rescale,\n",
" height=(height_img * min(1, scale)) * rescale)\n",
" return scale"
]
},
Expand All @@ -319,7 +324,7 @@
"outputs": [],
"source": [
"file = \"../data/projects/bbox/pics/red400x640.png\"\n",
"canvas = Canvas(width=300, height=300)\n",
"canvas = Canvas(width=300, height=320)\n",
"draw_bg(canvas)\n",
"scale = draw_img(canvas, file)\n",
"print(scale)\n",
Expand Down Expand Up @@ -559,7 +564,7 @@
" else: # otherwise, save bbox values to backend\n",
" self.bbox_coords = dict({ k: v / self._image_scale for k, v in self._canvas_bbox_coords.items() })\n",
"# print(\"<- STOP DRAWING\")\n",
" \n",
"\n",
" \n",
" @traitlets.observe('bbox_coords')\n",
" def _update_canvas_bbox_coords(self, change):\n",
Expand Down Expand Up @@ -592,13 +597,12 @@
" \n",
" def _clear_bbox(self):\n",
" self._multi_canvas[self._box_layer].clear()\n",
" \n",
" \n",
"\n",
" @traitlets.observe('image_path')\n",
" def _draw_image(self, image):\n",
" self._image_scale = draw_img(self._multi_canvas[self._image_layer], self.image_path, clear=True)\n",
" self._im_name_box.value = Path(self.image_path).name\n",
"\n",
" \n",
" @property\n",
" def image_scale(self):\n",
" return self._image_scale\n",
Expand All @@ -612,13 +616,20 @@
" self._multi_canvas.on_client_ready(cb)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"gui = BBoxCanvas(width=100, height=100)\n",
"gui = BBoxCanvas(width=200, height=200)\n",
"gui"
]
},
Expand Down
2 changes: 1 addition & 1 deletion nbs/01b_tutorial_image_classification.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@
" n_cols=n_cols,\n",
" label_autosize=False\n",
" )\n",
"display(im2im)"
"im2im"
]
},
{
Expand Down
Loading