Skip to content

Commit 45efaad

Browse files
authored
HTML Formatting (#77)
* Add imantics thumbnail * Html formatting * Show category with image thumbnail * Fixed create annotation bug * Removed unused buttons
1 parent 12675e7 commit 45efaad

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1328
-433
lines changed

app/api/annotations.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from flask_restplus import Namespace, Resource, reqparse
22
from flask_login import login_required, current_user
3+
from imantics import Color
34

45
from ..models import AnnotationModel
5-
from ..util import query_util, color_util
6+
from ..util import query_util
67

78
import datetime
89

@@ -35,7 +36,6 @@ def post(self):
3536

3637
try:
3738
annotation = AnnotationModel(image_id=image_id, category_id=category_id, metadata=metadata)
38-
annotation.color = color_util.random_color_hex() if color is None else color
3939
annotation.save()
4040
except (ValueError, TypeError) as e:
4141
return {'message': str(e)}, 400

app/api/categories.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from flask_login import login_required, current_user
33

44
from ..util.pagination_util import Pagination
5-
from ..util import query_util, color_util
5+
from ..util import query_util
66
from ..models import CategoryModel, AnnotationModel
77

88
import datetime

app/api/datasets.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,11 @@ def get(self, dataset_id):
241241

242242
for image in images:
243243
image_id = image.get('id')
244-
image['annotations'] = AnnotationModel.objects(image_id=image_id, deleted=False).count()
244+
query = AnnotationModel.objects(image_id=image_id, deleted=False)
245+
image['annotations'] = query.count()
246+
category_ids = query.distinct('category_id')
247+
image['categories'] = query_util.fix_ids(CategoryModel.objects(id__in=category_ids).only('name', 'color'))
248+
245249

246250
subdirectories = [f for f in sorted(os.listdir(directory))
247251
if os.path.isdir(directory + f)]

app/api/images.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from werkzeug.datastructures import FileStorage
44
from flask import send_file
55

6-
from ..util import query_util, coco_util, thumbnail_util
6+
from ..util import query_util, coco_util
77
from ..models import *
88

99
import datetime
@@ -184,7 +184,7 @@ def post(self, from_id, to_id):
184184

185185

186186
@api.route('/<int:image_id>/thumbnail')
187-
class ImageCoco(Resource):
187+
class ImageThumbnail(Resource):
188188

189189
@api.expect(image_download)
190190
@login_required
@@ -206,7 +206,7 @@ def get(self, image_id):
206206
if height < 1:
207207
height = image.height
208208

209-
pil_image = thumbnail_util.generate_thumbnail(image, save=False)
209+
pil_image = image.thumbnail()
210210
pil_image.thumbnail((width, height), Image.ANTIALIAS)
211211

212212
image_io = io.BytesIO()

app/models.py

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
import json
44
import datetime
55
import numpy as np
6+
import imantics as im
67

8+
from PIL import Image
79
from flask_mongoengine import MongoEngine
810
from mongoengine.queryset.visitor import Q
911
from flask_login import UserMixin, current_user
1012

1113

12-
from .util import color_util
1314
from .config import Config
1415
from PIL import Image
1516

@@ -129,6 +130,10 @@ def thumbnail_path(self):
129130
os.makedirs(directory)
130131

131132
return '/'.join(folders)
133+
134+
def thumbnail(self):
135+
image = self().draw(color_by_category=True, bbox=False)
136+
return Image.fromarray(image)
132137

133138
def copy_annotations(self, annotations):
134139
"""
@@ -148,6 +153,15 @@ def copy_annotations(self, annotations):
148153

149154
return annotations.count()
150155

156+
def __call__(self):
157+
158+
image = im.Image.from_path(self.path)
159+
for annotation in AnnotationModel.objects(image_id=self.id, deleted=False).all():
160+
if not annotation.is_empty():
161+
image.add(annotation())
162+
163+
return image
164+
151165

152166
class AnnotationModel(db.DynamicDocument):
153167

@@ -196,7 +210,7 @@ def save(self, copy=False, *args, **kwargs):
196210
self.metadata = dataset.default_annotation_metadata.copy()
197211

198212
if self.color is None:
199-
self.color = color_util.random_color_hex()
213+
self.color = im.Color.random().hex
200214

201215
if current_user:
202216
self.creator = current_user.username
@@ -225,6 +239,23 @@ def clone(self):
225239

226240
return AnnotationModel(**create)
227241

242+
def __call__(self):
243+
244+
category = CategoryModel.objects(id=self.category_id).first()
245+
if category:
246+
category = category()
247+
248+
data = {
249+
'image': None,
250+
'category': category,
251+
'color': self.color,
252+
'polygons': self.segmentation,
253+
'width': self.width,
254+
'height': self.height,
255+
'metadata': self.metadata
256+
}
257+
258+
return im.Annotation(**data)
228259

229260
class CategoryModel(db.DynamicDocument):
230261

@@ -260,7 +291,7 @@ def bulk_create(cls, categories):
260291
def save(self, *args, **kwargs):
261292

262293
if not self.color:
263-
self.color = color_util.random_color_hex()
294+
self.color = im.Color.random().hex
264295

265296
if current_user:
266297
self.creator = current_user.username
@@ -269,6 +300,16 @@ def save(self, *args, **kwargs):
269300

270301
return super(CategoryModel, self).save(*args, **kwargs)
271302

303+
def __call__(self):
304+
""" Generates imantics category object """
305+
data = {
306+
'name': self.name,
307+
'color': self.color,
308+
'parent': self.supercategory,
309+
'metadata': self.metadata,
310+
'id': self.id
311+
}
312+
return im.Category(**data)
272313

273314
class LicenseModel(db.DynamicDocument):
274315
id = db.SequenceField(primary_key=True)

app/util/thumbnail_util.py

Lines changed: 0 additions & 46 deletions
This file was deleted.

client/src/App.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<div id="app">
3-
<NavBar v-show="showNavBar"/>
3+
<NavBar v-show="showNavBar" />
44
<RouterView :key="$route.fullPath" />
55
</div>
66
</template>

client/src/components/Metadata.vue

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
<template>
22
<div>
3-
<i class="fa fa-plus" style="float: right; margin: 0 4px; color: green" @click="createMetadata" />
3+
<i
4+
class="fa fa-plus"
5+
style="float: right; margin: 0 4px; color: green"
6+
@click="createMetadata"
7+
/>
48

59
<p class="title" style="margin: 0">{{ title }}</p>
610

@@ -17,15 +21,28 @@
1721
<li v-if="metadataList.length == 0" class="list-group-item meta-item">
1822
<i class="subtitle">No items in metadata.</i>
1923
</li>
20-
<li v-for="(object, index) in metadataList" :key="index" class="list-group-item meta-item">
24+
<li
25+
v-for="(object, index) in metadataList"
26+
:key="index"
27+
class="list-group-item meta-item"
28+
>
2129
<div class="row" style="cell">
22-
2330
<div class="col-sm">
24-
<input v-model="object.key" type="text" class="meta-input" :placeholder="keyTitle">
31+
<input
32+
v-model="object.key"
33+
type="text"
34+
class="meta-input"
35+
:placeholder="keyTitle"
36+
/>
2537
</div>
2638

2739
<div class="col-sm">
28-
<input v-model="object.value" type="text" class="meta-input" :placeholder="valueTitle">
40+
<input
41+
v-model="object.value"
42+
type="text"
43+
class="meta-input"
44+
:placeholder="valueTitle"
45+
/>
2946
</div>
3047
</div>
3148
</li>

client/src/components/NavBar.vue

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
<template>
22
<nav class="navbar navbar-expand-lg navbar-dark fixed-top">
3-
43
<a class="navbar-brand" href="/">
54
<strong>{{ name }}</strong>
65
<span class="subscript">{{ version }}</span>
76
</a>
87

9-
<button class="navbar-toggler"
10-
type="button" data-toggle="collapse"
8+
<button
9+
class="navbar-toggler"
10+
type="button"
11+
data-toggle="collapse"
1112
data-target="#navbarSupportedContent"
1213
aria-controls="navbarSupportedContent"
1314
aria-expanded="false"
@@ -18,7 +19,6 @@
1819

1920
<div class="collapse navbar-collapse" id="navbarSupportedContent">
2021
<ul class="navbar-nav mr-auto">
21-
2222
<li class="nav-item" :class="{ active: $route.name === 'datasets' }">
2323
<RouterLink class="nav-link" to="/datasets">Datasets</RouterLink>
2424
</li>
@@ -28,20 +28,26 @@
2828
<li class="nav-item" :class="{ active: $route.name === 'undo' }">
2929
<RouterLink class="nav-link" to="/undo">Undo</RouterLink>
3030
</li>
31-
<li v-show="$store.getters['user/isAdmin']" class="nav-item" :class="{ active: $route.name === 'admin' }">
31+
<li
32+
v-show="$store.getters['user/isAdmin']"
33+
class="nav-item"
34+
:class="{ active: $route.name === 'admin' }"
35+
>
3236
<RouterLink class="nav-link" to="/admin/panel">Admin</RouterLink>
3337
</li>
3438
<li class="nav-item">
3539
<a class="nav-link" href="/api">API</a>
3640
</li>
3741
<li class="nav-item">
38-
<a class="nav-link" href="https://github.com/jsbroks/coco-annotator/wiki">Help</a>
42+
<a
43+
class="nav-link"
44+
href="https://github.com/jsbroks/coco-annotator/wiki"
45+
>Help</a
46+
>
3947
</li>
40-
4148
</ul>
4249
<Status />
4350
<User v-if="loginEnabled" />
44-
4551
</div>
4652
</nav>
4753
</template>

client/src/components/Pagination.vue

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,19 @@
77
<span class="sr-only">Previous</span>
88
</a>
99
</li>
10-
<li v-for="pageIndex in range" :key="pageIndex" :class="{ 'page-item': true, active: pageIndex + startPage == page }">
11-
<a class="page-link" @click="page = pageIndex + startPage">{{ pageIndex + startPage}}</a>
10+
<li
11+
v-for="pageIndex in range"
12+
:key="pageIndex"
13+
:class="{ 'page-item': true, active: pageIndex + startPage == page }"
14+
>
15+
<a class="page-link" @click="page = pageIndex + startPage">{{
16+
pageIndex + startPage
17+
}}</a>
1218
</li>
13-
<li :class="{ 'page-item': true, disabled: page == pages }" @click="nextPage">
19+
<li
20+
:class="{ 'page-item': true, disabled: page == pages }"
21+
@click="nextPage"
22+
>
1423
<a class="page-link" aria-label="Next">
1524
<span aria-hidden="true">&raquo;</span>
1625
<span class="sr-only">Next</span>

0 commit comments

Comments
 (0)