Skip to content

Commit 4765a1e

Browse files
committed
February Release
1 parent 4ee3ec1 commit 4765a1e

30 files changed

Lines changed: 3413 additions & 185 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,6 @@ tools/fastai
133133

134134
# link checker
135135
checklink/cookies.txt
136+
137+
#ipyannotator
138+
**/**/autogenerated*/

.gitlab-ci.yml

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,19 @@ image: docker:latest
22
services:
33
- docker:dind
44

5+
variables:
6+
IMG_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
7+
GIT_STRATEGY: clone
8+
59
before_script:
610
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" "$CI_REGISTRY" --password-stdin
711
- docker pull $IMG_TAG || true
812
- apk update && apk add --no-cache git bash
913

10-
variables:
11-
IMG_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
12-
GIT_STRATEGY: clone
13-
1414
stages:
1515
- build
1616
- test
17+
- release
1718

1819

1920
build_image:
@@ -78,3 +79,15 @@ run_tests:
7879
--env MASTER_TOKEN=$MASTER_TOKEN
7980
$IMG_TAG
8081
/bin/bash -c "./scripts/test_nb.sh"
82+
83+
84+
build_whls:
85+
tags:
86+
- docker
87+
stage: release
88+
when: manual
89+
script:
90+
- >
91+
docker run -i --rm
92+
$IMG_TAG
93+
/bin/bash -c "poetry build -f wheel && poetry publish -r palaimon -u $POETRY_HTTP_BASIC_PYPI_USERNAME -p $POETRY_HTTP_BASIC_PYPI_PASSWORD"

Dockerfile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,18 @@ RUN git clone git://github.com/yyuu/pyenv.git .pyenv
4545

4646
RUN pyenv install 3.7.3 -f && pyenv global 3.7.3
4747

48+
# Poetry publish command has some bugs in handling config and env variables:
49+
# https://github.com/python-poetry/poetry/issues/2210
50+
# https://github.com/python-poetry/poetry/issues/858
51+
# _URL ending for repositories environment variable
52+
# and NO /simple/ or /legacy/ etc. endpoint for real url is a must
4853
ENV POETRY_VERSION=1.1.0 \
4954
PIP_DISABLE_PIP_VERSION_CHECK=on \
5055
POETRY_NO_INTERACTION=1 \
5156
POETRY_VIRTUALENVS_CREATE=false \
5257
PYTHONUNBUFFERED=1 \
53-
POETRY_HOME=/poetry
58+
POETRY_HOME=/poetry \
59+
POETRY_REPOSITORIES_PALAIMON_URL=https://pypi.palaimon.io/
5460

5561
# uses $POETRY_VERSION & $POETRY_HOME internally
5662
RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,7 @@ Also check out the following notebook for a more high level overview.
8585
    data science workflow. `nbs/08_tutorial_road_damage.ipynb`
8686
- Slides + recoding of jupytercon 2020 talk explaining the high level concepts / vision
8787
of ipyannotator. TODO add public link
88-
89-
88+
9089
## Jupyter lab trouble shooting
9190

9291
For clean (re)install make sure to have all the lab extencions active:

ipyannotator/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.3.0"
1+
__version__ = "0.3.5"

ipyannotator/_nbdev.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,21 @@
88
"draw_img": "01_bbox_canvas.ipynb",
99
"points2bbox_coords": "01_bbox_canvas.ipynb",
1010
"BBoxCanvas": "01_bbox_canvas.ipynb",
11+
"draw_bbox": "01a_datasets.ipynb",
12+
"xywh_to_xyxy": "01a_datasets.ipynb",
13+
"xyxy_to_xywh": "01a_datasets.ipynb",
14+
"bbox_intersection": "01a_datasets.ipynb",
15+
"overlap": "01a_datasets.ipynb",
16+
"sample_bbox": "01a_datasets.ipynb",
17+
"draw_rectangle": "01a_datasets.ipynb",
18+
"draw_ellipse": "01a_datasets.ipynb",
19+
"create_simple_object_detection_dataset": "01a_datasets.ipynb",
20+
"create_color_classification": "01a_datasets.ipynb",
21+
"create_shape_color_classification": "01a_datasets.ipynb",
22+
"create_object_detection": "01a_datasets.ipynb",
23+
"get_cifar10": "01a_datasets_download.ipynb",
24+
"get_oxford_102_flowers": "01a_datasets_download.ipynb",
25+
"get_cub_200_2011": "01a_datasets_download.ipynb",
1126
"NaviGUI": "02_navi_widget.ipynb",
1227
"NaviLogic": "02_navi_widget.ipynb",
1328
"Navi": "02_navi_widget.ipynb",
@@ -26,10 +41,15 @@
2641
"CaptureAnnotator": "06_capture_annotator.ipynb",
2742
"ImCanvas": "07_im2im_annotator.ipynb",
2843
"Im2ImAnnotatorGUI": "07_im2im_annotator.ipynb",
44+
"text_on_img": "07_im2im_annotator.ipynb",
45+
"flatten": "07_im2im_annotator.ipynb",
46+
"reconstruct_class_images": "07_im2im_annotator.ipynb",
2947
"Im2ImAnnotatorLogic": "07_im2im_annotator.ipynb",
3048
"Im2ImAnnotator": "07_im2im_annotator.ipynb"}
3149

3250
modules = ["bbox_canvas.py",
51+
"datasets/generators.py",
52+
"datasets/download.py",
3353
"navi_widget.py",
3454
"storage.py",
3555
"bbox_annotator.py",

ipyannotator/bbox_annotator.py

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,23 +53,43 @@ class BBoxAnnotatorLogic(HasTraits):
5353
bbox_coords = Dict()
5454
current_im_num = Int()
5555

56-
def __init__(self, project_path, image_dir='pics'):
56+
def __init__(self, project_path, file_name=None, image_dir='pics', results_dir=None):
5757
self.project_path = Path(project_path)
58-
self.image_dir, self.annotation_file_path = setup_project_paths(self.project_path, image_dir=image_dir)
59-
self.image_paths = get_image_list_from_folder(self.image_dir)
58+
self.image_dir, self.annotation_file_path = setup_project_paths(self.project_path,
59+
file_name=file_name,
60+
image_dir=image_dir,
61+
results_dir=results_dir)
62+
63+
# select images and bboxes only from given annotatin file
64+
if self.annotation_file_path.is_file():
65+
with self.annotation_file_path.open() as json_file:
66+
data = json.load(json_file)
67+
im_names = data.keys()
68+
self.image_paths = sorted(im for im in get_image_list_from_folder(self.image_dir) if str(im) in im_names)
69+
else:
70+
self.image_paths = sorted(get_image_list_from_folder(self.image_dir))
71+
72+
73+
if not self.image_paths:
74+
raise Exception ("!! No Images to dipslay !!")
75+
6076
self.current_im_num = len(self.image_paths)
77+
6178
self.annotations = AnnotationStorage(self.image_paths)
6279

80+
if self.annotation_file_path.exists():
81+
self.annotations.load(self.annotation_file_path)
82+
else:
83+
self.annotations.save(self.annotation_file_path)
84+
6385
def _update_im(self):
6486
self.image_path = str(self.image_paths[self.index])
6587

6688
def _update_coords(self): # from annotations
67-
im_name = self.__get_name_by_index(self.index)
68-
self.bbox_coords = self.annotations.get(im_name) or {}
89+
self.bbox_coords = self.annotations.get(self.image_path) or {}
6990

7091
def _update_annotations(self, index): # from coordinates
71-
im_name = self.__get_name_by_index(index)
72-
self.annotations[im_name] = self.bbox_coords
92+
self.annotations[str(self.image_paths[index])] = self.bbox_coords
7393

7494
def _save_annotations(self, *args, **kwargs): # to disk
7595
index = kwargs.pop('old_index', self.index)
@@ -90,9 +110,6 @@ def _idx_changed(self, change):
90110
self._update_im()
91111
self._update_coords()
92112

93-
def __get_name_by_index(self, idx):
94-
return self.image_paths[idx].name
95-
96113
# Cell
97114

98115
class BBoxAnnotator(BBoxAnnotatorGUI):
@@ -106,8 +123,9 @@ class BBoxAnnotator(BBoxAnnotatorGUI):
106123
"""
107124
debug_output = Output()
108125

109-
def __init__(self, project_path, canvas_size=(200, 400), image_dir='pics'):
110-
self._model = BBoxAnnotatorLogic(project_path, image_dir=image_dir)
126+
def __init__(self, project_path, canvas_size=(200, 400), file_name=None, image_dir='pics', results_dir=None):
127+
self._model = BBoxAnnotatorLogic(project_path, file_name=file_name,
128+
image_dir=image_dir, results_dir=results_dir)
111129

112130
super().__init__(canvas_size=canvas_size)
113131

ipyannotator/bbox_canvas.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,11 @@ def _update_canvas_bbox_coords(self, change):
175175
# print('-> Observe bbox_coords: ', change)
176176

177177
if change['new'] == self._canvas_bbox_coords: # change event from gui, do nothing
178-
print('-> GUI')
178+
pass
179+
# print('-> GUI')
179180
else: # recalculate canvas coordinates as bbox was set by backend:
180181
self._canvas_bbox_coords = {k: v * self._image_scale for k, v in self.bbox_coords.items()}
181-
print('-> Backend')
182+
# print('-> Backend')
182183
# print('<- Observe bbox_coords')
183184

184185

ipyannotator/capture_annotator.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,16 @@ class CaptureAnnotatorLogic(HasTraits):
153153
all_none = Bool()
154154

155155

156-
def __init__(self, project_path, question=None, image_dir='pics', filter_files=None):
156+
def __init__(self, project_path, question=None, image_dir='pics', filter_files=None, results_dir=None):
157157
self.project_path = Path(project_path)
158-
self.image_dir, self.annotation_file_path = setup_project_paths(self.project_path, image_dir=image_dir)
158+
self.image_dir, self.annotation_file_path = setup_project_paths(self.project_path, image_dir=image_dir, results_dir=results_dir)
159159

160160
self.image_paths = sorted(get_image_list_from_folder(self.image_dir)) #todo: use sorted in storage?
161+
161162
if filter_files:
162-
self.image_paths = [p for p in self.image_paths if p.name in filter_files]
163+
self.image_paths = [p for p in self.image_paths if str(p) in filter_files]
164+
if not self.image_paths:
165+
raise UserWarning("No image files to display! Check image_dir of filter.")
163166
self.current_im_num = len(self.image_paths)
164167
self.annotations = AnnotationStorage(self.image_paths)
165168
if question:
@@ -172,15 +175,14 @@ def _update_state(self, change=None): # from annotations
172175
state_images = self._get_state_names(self.index)
173176
current_state = {}
174177
for im_path in state_images:
175-
in_name = im_path.name
176-
current_state[im_path] = self.annotations.get(in_name) or {}
178+
current_state[str(im_path)] = self.annotations.get(str(im_path)) or {}
177179
self.all_none = all(value == {'answer': False} for value in current_state.values())
178180
self.current_state = current_state
179181

182+
180183
def _update_annotations(self, index): # from screen
181184
for p, anno in self.current_state.items():
182-
self.annotations[Path(p).name] = anno
183-
185+
self.annotations[str(p)] = anno
184186

185187
def _save_annotations(self, *args, **kwargs): # to disk
186188
index = kwargs.pop('old_index', self.index)
@@ -213,7 +215,7 @@ def _handle_grid_click(self, event, name=None):
213215
p = Path(self.image_dir, name)
214216
current_state = self.current_state.copy()
215217
if not p.is_dir():
216-
current_state[p] = {'answer': not self.current_state[p].get('answer', False)}
218+
current_state[str(p)] = {'answer': not self.current_state[str(p)].get('answer', False)}
217219
if self.all_none:
218220
self.all_none = False
219221
else:
@@ -237,12 +239,12 @@ class CaptureAnnotator(CaptureAnnotatorGUI):
237239
"""
238240

239241
def __init__(self, project_path, image_dir='pics', image_width=150, image_height=150,
240-
n_rows=3, n_cols=3, question=None, filter_files=None):
242+
n_rows=3, n_cols=3, question=None, filter_files=None, results_dir=None):
241243

242244
super().__init__(image_width, image_height, n_rows, n_cols)
243245

244246
self._model = CaptureAnnotatorLogic(project_path, question, image_dir,
245-
filter_files=filter_files)
247+
filter_files=filter_files, results_dir=results_dir)
246248

247249
self._save_btn.on_click(self._model._save_annotations)
248250

ipyannotator/datasets/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)