Skip to content

Instantly share code, notes, and snippets.

@ikeyasu
Created April 17, 2018 14:18
Show Gist options
  • Save ikeyasu/7dc265082645bf50aa320e039dce904a to your computer and use it in GitHub Desktop.
Save ikeyasu/7dc265082645bf50aa320e039dce904a to your computer and use it in GitHub Desktop.
mturk-ball.html
<div style="display:none;">&nbsp;</div>
<link href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/smoothness/jquery-ui.css" rel="stylesheet" /><script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script><script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.js"></script>
<div style="display:inline-block;vertical-align:top;">
<h1>Draw a box around each of balls.</h1>
<p>Draw a rectangle using your mouse over each balls. You need to draw like the following image.</p>
<p>
<img src="https://s3.amazonaws.com/ikeyasu-turk/balls/sample.png">
</p>
<div id="bbox_annotator" style="display:inline-block">&nbsp;</div><p/><p/>
<p id="button_paragraph"><input id="annotation_data" name="annotation_data" type="hidden" /> <input id="reset_button" type="reset" /></p>
</div>
<script type="text/javascript">
(function() {
var BBoxSelector;
BBoxSelector = (function() {
function BBoxSelector(image_frame, options) {
if (options == null) {
options = {};
}
options.input_method || (options.input_method = "text");
this.image_frame = image_frame;
this.border_width = options.border_width || 2;
this.selector = $('<div class="bbox_selector"></div>');
this.selector.css({
"border": this.border_width + "px dotted rgb(127,255,127)",
"position": "absolute"
});
this.image_frame.append(this.selector);
this.selector.css({
"border-width": this.border_width
});
this.selector.hide();
this.create_label_box(options);
}
BBoxSelector.prototype.create_label_box = function(options) {
var label, _i, _len, _ref;
options.labels || (options.labels = ["object"]);
this.label_box = $('<div class="label_box"></div>');
this.label_box.css({
"position": "absolute"
});
this.label_box.css({
"z-index": "1000"
});
this.image_frame.append(this.label_box);
switch (options.input_method) {
case 'select':
if (typeof options.labels === "string") {
options.labels = [options.labels];
}
this.label_input = $('<select class="label_input" name="label"></select>');
this.label_box.append(this.label_input);
this.label_input.append($('<option value>choose an item</option>'));
_ref = options.labels;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
label = _ref[_i];
this.label_input.append('<option value="' + label + '">' + label + '</option>');
}
this.label_input.change(function(e) {
return this.blur();
});
break;
case 'text':
if (typeof options.labels === "string") {
options.labels = [options.labels];
}
this.label_input = $('<input class="label_input" name="label" ' + 'type="text" value>');
this.label_box.append(this.label_input);
this.label_input.autocomplete({
source: options.labels || [''],
autoFocus: true
});
break;
case 'fixed':
if ($.isArray(options.labels)) {
options.labels = options.labels[0];
}
this.label_input = $('<input class="label_input" name="label" type="text">');
this.label_box.append(this.label_input);
this.label_input.val(options.labels);
break;
default:
throw 'Invalid label_input parameter: ' + options.input_method;
}
return this.label_box.hide();
};
BBoxSelector.prototype.crop = function(pageX, pageY) {
var point;
return point = {
x: Math.min(Math.max(Math.round(pageX - this.image_frame.offset().left), 0), Math.round(this.image_frame.width() - 1)),
y: Math.min(Math.max(Math.round(pageY - this.image_frame.offset().top), 0), Math.round(this.image_frame.height() - 1))
};
};
BBoxSelector.prototype.start = function(pageX, pageY) {
this.pointer = this.crop(pageX, pageY);
this.offset = this.pointer;
this.refresh();
this.selector.show();
$('body').css('cursor', 'crosshair');
return document.onselectstart = function() {
return false;
};
};
BBoxSelector.prototype.update_rectangle = function(pageX, pageY) {
this.pointer = this.crop(pageX, pageY);
return this.refresh();
};
BBoxSelector.prototype.input_label = function(options) {
$('body').css('cursor', 'default');
document.onselectstart = function() {
return true;
};
this.label_box.show();
return this.label_input.focus();
};
BBoxSelector.prototype.finish = function(options) {
var data;
this.label_box.hide();
this.selector.hide();
data = this.rectangle();
data.label = $.trim(this.label_input.val().toLowerCase());
if (options.input_method !== 'fixed') {
this.label_input.val('');
}
return data;
};
BBoxSelector.prototype.rectangle = function() {
var rect, x1, x2, y1, y2;
x1 = Math.min(this.offset.x, this.pointer.x);
y1 = Math.min(this.offset.y, this.pointer.y);
x2 = Math.max(this.offset.x, this.pointer.x);
y2 = Math.max(this.offset.y, this.pointer.y);
return rect = {
left: x1,
top: y1,
width: x2 - x1 + 1,
height: y2 - y1 + 1
};
};
BBoxSelector.prototype.refresh = function() {
var rect;
rect = this.rectangle();
this.selector.css({
left: (rect.left - this.border_width) + 'px',
top: (rect.top - this.border_width) + 'px',
width: rect.width + 'px',
height: rect.height + 'px'
});
return this.label_box.css({
left: (rect.left - this.border_width) + 'px',
top: (rect.top + rect.height + this.border_width) + 'px'
});
};
BBoxSelector.prototype.get_input_element = function() {
return this.label_input;
};
return BBoxSelector;
})();
this.BBoxAnnotator = (function() {
function BBoxAnnotator(options) {
var annotator, image_element;
annotator = this;
this.annotator_element = $(options.id || "#bbox_annotator");
this.border_width = options.border_width || 2;
this.show_label = options.show_label || (options.input_method !== "fixed");
this.image_frame = $('<div class="image_frame"></div>');
this.annotator_element.append(this.image_frame);
image_element = new Image();
image_element.src = options.url;
image_element.onload = function() {
options.width || (options.width = image_element.width);
options.height || (options.height = image_element.height);
annotator.annotator_element.css({
"width": (options.width + annotator.border_width * 2) + 'px',
"height": (options.height + annotator.border_width * 2) + 'px',
"cursor": "crosshair"
});
annotator.image_frame.css({
"background-image": "url('" + image_element.src + "')",
"width": options.width + "px",
"height": options.height + "px",
"position": "relative"
});
annotator.selector = new BBoxSelector(annotator.image_frame, options);
return annotator.initialize_events(annotator.selector, options);
};
image_element.onerror = function() {
return annotator.annotator_element.text("Invalid image URL: " + options.url);
};
this.entries = [];
this.onchange = options.onchange;
}
BBoxAnnotator.prototype.initialize_events = function(selector, options) {
var annotator, status;
status = 'free';
this.hit_menuitem = false;
annotator = this;
this.annotator_element.mousedown(function(e) {
if (!annotator.hit_menuitem) {
switch (status) {
case 'free':
case 'input':
if (status === 'input') {
selector.get_input_element().blur();
}
if (e.which === 1) {
selector.start(e.pageX, e.pageY);
status = 'hold';
}
}
}
annotator.hit_menuitem = false;
return true;
});
$(window).mousemove(function(e) {
switch (status) {
case 'hold':
selector.update_rectangle(e.pageX, e.pageY);
}
return true;
});
$(window).mouseup(function(e) {
switch (status) {
case 'hold':
selector.update_rectangle(e.pageX, e.pageY);
selector.input_label(options);
status = 'input';
if (options.input_method === 'fixed') {
selector.get_input_element().blur();
}
}
return true;
});
selector.get_input_element().blur(function(e) {
var data;
switch (status) {
case 'input':
data = selector.finish(options);
if (data.label) {
annotator.add_entry(data);
if (annotator.onchange) {
annotator.onchange(annotator.entries);
}
}
status = 'free';
}
return true;
});
selector.get_input_element().keypress(function(e) {
switch (status) {
case 'input':
if (e.which === 13) {
selector.get_input_element().blur();
}
}
return e.which !== 13;
});
selector.get_input_element().mousedown(function(e) {
return annotator.hit_menuitem = true;
});
selector.get_input_element().mousemove(function(e) {
return annotator.hit_menuitem = true;
});
selector.get_input_element().mouseup(function(e) {
return annotator.hit_menuitem = true;
});
return selector.get_input_element().parent().mousedown(function(e) {
return annotator.hit_menuitem = true;
});
};
BBoxAnnotator.prototype.add_entry = function(entry) {
var annotator, box_element, close_button, text_box;
this.entries.push(entry);
box_element = $('<div class="annotated_bounding_box"></div>');
box_element.appendTo(this.image_frame).css({
"border": this.border_width + "px solid rgb(127,255,127)",
"position": "absolute",
"top": (entry.top - this.border_width) + "px",
"left": (entry.left - this.border_width) + "px",
"width": entry.width + "px",
"height": entry.height + "px",
"color": "rgb(127,255,127)",
"font-family": "monospace",
"font-size": "small"
});
close_button = $('<div></div>').appendTo(box_element).css({
"position": "absolute",
"top": "-8px",
"right": "-8px",
"width": "16px",
"height": "0",
"padding": "16px 0 0 0",
"overflow": "hidden",
"color": "#fff",
"background-color": "#030",
"border": "2px solid #fff",
"-moz-border-radius": "18px",
"-webkit-border-radius": "18px",
"border-radius": "18px",
"cursor": "pointer",
"-moz-user-select": "none",
"-webkit-user-select": "none",
"user-select": "none",
"text-align": "center"
});
$("<div></div>").appendTo(close_button).html('×').css({
"display": "block",
"text-align": "center",
"width": "16px",
"position": "absolute",
"top": "-2px",
"left": "0",
"font-size": "16px",
"line-height": "16px",
"font-family": '"Helvetica Neue", Consolas, Verdana, Tahoma, Calibri, ' + 'Helvetica, Menlo, "Droid Sans", sans-serif'
});
text_box = $('<div></div>').appendTo(box_element).css({
"overflow": "hidden"
});
if (this.show_label) {
text_box.text(entry.label);
}
annotator = this;
box_element.hover((function(e) {
return close_button.show();
}), (function(e) {
return close_button.hide();
}));
close_button.mousedown(function(e) {
return annotator.hit_menuitem = true;
});
close_button.click(function(e) {
var clicked_box, index;
clicked_box = close_button.parent(".annotated_bounding_box");
index = clicked_box.prevAll(".annotated_bounding_box").length;
clicked_box.detach();
annotator.entries.splice(index, 1);
return annotator.onchange(annotator.entries);
});
return close_button.hide();
};
BBoxAnnotator.prototype.clear_all = function(e) {
$(".annotated_bounding_box").detach();
this.entries.splice(0);
return this.onchange(this.entries);
};
return BBoxAnnotator;
})();
}).call(this);
// Main entry point. Use a placeholder for image urls.
$(document).ready(function() {
var assignment_id = turkGetParam('assignmentId', "");
// Initialize the bounding-box annotator.
var annotator = new BBoxAnnotator({
url: "${image_url}",
input_method: 'fixed', // Can be one of ['text', 'select', 'fixed']
labels: ["dress", "top", "skirt", "pants", "shoes"], // Label of the object.
onchange: function(entries) {
$("#annotation_data").val(JSON.stringify(entries));
if (entries.length > 0 &&
assignment_id != "" &&
assignment_id != "ASSIGNMENT_ID_NOT_AVAILABLE") {
$("#submitButton").removeAttr("disabled");
}
else {
$("#submitButton").attr("disabled", "disabled");
}
}
});
// Initialize the reset button.
$("#reset_button").click(function(e) {
annotator.clear_all();
});
// Disable the submission at the beginning.
$("#submitButton").attr("disabled", "disabled");
$("#submitButton").detach().appendTo("#button_paragraph");
if (assignment_id == "ASSIGNMENT_ID_NOT_AVAILABLE") {
$("#submitButton").val("This is preview");
}
console.log(assignment_id);
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment