Skip to content

Commit

Permalink
Keypoints (#122)
Browse files Browse the repository at this point in the history
* Keypoints visual circles

* Keypoints paperjs object

* Add keypoints to models

* Created Keypoints object

* Keypoint visualization logic

* Fixed saving keypoint logic

* Create Keypoints panel

* Setting keypoint edges

* Fixed model

* Export keypoints and bug fixes

* Simplified clamp function

* Fixed js lint

* Keypoint delete using delete key

* Keypoints shortcut

* Fixed keypoint line error
  • Loading branch information
jsbroks authored Feb 23, 2019
1 parent 9cfb516 commit 91f2e9c
Show file tree
Hide file tree
Showing 20 changed files with 1,087 additions and 59 deletions.
7 changes: 6 additions & 1 deletion app/api/annotator.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ def post(self):
if db_category is None:
continue

db_category.update(set__color=category.get('color'))
db_category.update(
set__color=category.get('color'),
set__keypoint_edges=category.get('keypoint_edges', []),
set__keypoint_labels=category.get('keypoint_labels', [])
)

# Iterate every annotation from the data annotations
for annotation in category.get('annotations', []):
Expand All @@ -63,6 +67,7 @@ def post(self):

# Update annotation in database
db_annotation.update(
set__keypoints=annotation.get('keypoints', []),
set__metadata=annotation.get('metadata'),
set__color=annotation.get('color')
)
Expand Down
7 changes: 7 additions & 0 deletions app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ class AnnotationModel(db.DynamicDocument):
height = db.IntField()

color = db.StringField()

keypoints = db.ListField(default=[])

metadata = db.DictField(default={})
paper_object = db.ListField(default=[])
Expand Down Expand Up @@ -311,6 +313,10 @@ class CategoryModel(db.DynamicDocument):
deleted = db.BooleanField(default=False)
deleted_date = db.DateTimeField()

keypoint_edges = db.ListField(default=[])
keypoint_labels = db.ListField(default=[])


@classmethod
def bulk_create(cls, categories):

Expand Down Expand Up @@ -462,6 +468,7 @@ def api_json(self):
"name": self.name
}


class CocoImportModel(db.DynamicDocument):
id = db.SequenceField(primary_key=True)
creator = db.StringField(required=True)
Expand Down
58 changes: 43 additions & 15 deletions app/util/coco_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,24 +114,40 @@ def get_image_coco(image):
annotations = []

for category in bulk_categories:

category = category[1]
category_annotations = AnnotationModel.objects(
deleted=False, category_id=category[1].id, image_id=image.get('id')
deleted=False, category_id=category.id, image_id=image.get('id')
).exclude('paper_object', 'deleted_date').all()

if len(category_annotations) == 0:
continue

has_keypoints = len(category.keypoint_labels) > 0

for annotation in category_annotations:
annotation = fix_ids(annotation)

if len(annotation.get('segmentation')) != 0:
if len(annotation.get('segmentation', [])) != 0 or \
len(annotation.get('keypoints', [])) != 0:
del annotation['deleted']
del annotation['paper_object']

if not has_keypoints:
del annotation['keypoints']
else:
arr = np.array(annotation.get('keypoints', []))
arr = arr[2::3]
annotation['num_keypoints'] = len(arr[arr > 0])

annotations.append(annotation)

category = fix_ids(category[1])
category = fix_ids(category)
del category['deleted']
if has_keypoints:
category['keypoints'] = category.pop('keypoint_labels')
category['skeleton'] = category.pop('keypoint_edges')
else:
del category['keypoint_edges']
del category['keypoint_labels']
categories.append(category)

del image['deleted']
Expand Down Expand Up @@ -169,7 +185,15 @@ def get_dataset_coco(dataset):

for category in categories:
category = fix_ids(category[1])

del category['deleted']
if len(category.keypoint_labels) > 0:
category['keypoints'] = category.pop('keypoint_labels')
category['skeleton'] = category.pop('keypoint_edges')
else:
del category['keypoint_edges']
del category['keypoint_labels']

coco.get('categories').append(category)

for image in images:
Expand All @@ -180,8 +204,19 @@ def get_dataset_coco(dataset):
annotations = fix_ids(annotations.all())

for annotation in annotations:
if len(annotation.get('segmentation', [])) != 0:

has_keypoints = len(annotation.get('keypoints', [])) > 0
has_segmentation = len(annotation.get('segmentation', [])) > 0

if has_keypoints or has_keypoints:
del annotation['deleted']

if not has_keypoints:
del annotation['keypoints']
else:
arr = np.array(annotation.get('keypoints', []))
arr = arr[2::3]
annotation['num_keypoints'] = len(arr[arr > 0])
coco.get('annotations').append(annotation)

image = fix_ids(image)
Expand All @@ -192,11 +227,4 @@ def get_dataset_coco(dataset):


def _fit(value, max_value, min_value):

if value > max_value:
return max_value

if value < min_value:
return min_value

return value
return max(min(value, max_value), min_value)
88 changes: 88 additions & 0 deletions client/src/components/PanelInputDropdown.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<template>
<div class="input-group tool-input-group">
<div class="input-group-prepend tool-option-pre">
<span class="input-group-text tool-option-font">{{ name }}</span>
</div>
<select v-model="localValue" class="form-control tool-option-input">
<option :key="option.key" v-for="option in options" :value="option.key" :selected="option.selected">{{ option.value }}</option>
</select>
</div>
</template>

<script>
export default {
name: "PanelInputString",
model: {
prop: "value",
event: "update"
},
props: {
name: {
type: String,
required: true
},
value: {
type: [Number, Array, Object, String],
required: true
},
values: {
type: Object,
required: true
}
},
data() {
return {
localValue: this.value
};
},
watch: {
localValue() {
this.$emit("update", this.localValue);
},
value(newValue) {
this.localValue = newValue;
}
},
computed: {
options() {
let array = [];
Object.keys(this.values).forEach(k => {
array.push({
key: k,
value: this.values[k],
selected: this.value == k
});
});
return array;
}
}
};
</script>

<style scoped>
.tool-input-group {
padding-top: 3px;
}
.tool-option-pre {
background-color: #383c4a;
}
.tool-option-font {
border-color: #4b5162;
background-color: #383c4a;
color: white;
font-size: 12px;
height: 20px;
}
.tool-option-input {
display: table-cell;
border-color: #4b5162;
color: white;
padding: 0 0 0 3px;
background-color: #383c4a;
font-size: 12px;
height: 20px;
}
</style>
28 changes: 28 additions & 0 deletions client/src/components/PanelText.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<template>
<div class="tool-option-input tool-option-font">
<p>{{ name }}</p>
</div>
</template>

<script>
export default {
name: "PanelButton",
props: {
name: {
type: String,
required: true
}
}
};
</script>

<style scoped>
.tool-option-font {
border-color: #4b5162;
background-color: #383c4a;
color: white;
font-size: 12px;
height: 20px;
padding: 2px 0 0 0;
}
</style>
Loading

0 comments on commit 91f2e9c

Please sign in to comment.