From c6bda41923c5d348a7b8079ce4dc5514bbc14897 Mon Sep 17 00:00:00 2001 From: John Doherty Date: Wed, 20 May 2015 14:36:37 -0700 Subject: [PATCH] lots of minor ui changes --- cli.py | 4 +- models.py | 1 + public/job.js | 2 + public/objectui.js | 132 +++++++++++++++++++++++++++++++++++++++--- public/stylesheet.css | 17 ++++++ public/tracks.js | 25 ++++++-- public/ui.js | 76 ++++++++++++++++++------ public/visualizer.js | 2 +- server.py | 1 + 9 files changed, 225 insertions(+), 35 deletions(-) diff --git a/cli.py b/cli.py index b304050..64ebc10 100644 --- a/cli.py +++ b/cli.py @@ -147,6 +147,7 @@ def setup(self): parser.add_argument("--blow-radius", default = 3) parser.add_argument("--run-initial-tracking", action="store_true") parser.add_argument("--homography") + parser.add_argument("--pointmode", action="store_true", default=False) return parser def title(self, args): @@ -242,7 +243,8 @@ def __call__(self, args, group): trainwith = trainer, isfortraining = args.for_training, blowradius = args.blow_radius, - homographylocation = homographydir) + homographylocation = homographydir, + pointmode = args.pointmode) if args.for_training: video.trainvalidator = qa.tolerable(args.for_training_overlap, diff --git a/models.py b/models.py index a7c2fd7..acb1842 100644 --- a/models.py +++ b/models.py @@ -36,6 +36,7 @@ class Video(turkic.database.Base): trainvalidator = Column(PickleType, nullable = True, default = None) blowradius = Column(Integer, default = 5) homographylocation = Column(String(250), nullable = True, default = None) + pointmode = Column(Boolean, default = False) def __getitem__(self, frame): path = Video.getframepath(frame, self.location) diff --git a/public/job.js b/public/job.js index fa86580..a318760 100644 --- a/public/job.js +++ b/public/job.js @@ -19,6 +19,7 @@ function Job(data) this.onlinetrackers = []; this.bidirectionaltrackers = []; this.multiobjecttrackers = []; + this.pointmode = null; this.frameurl = function(i) { @@ -51,6 +52,7 @@ function job_import(data) job.bidirectionaltrackers = data["trackers"]["bidirectional"]; job.multiobjecttrackers = data["trackers"]["multiobject"]; job.nextid = parseInt(data["nextid"]); + job.pointmode = parseInt(data["pointmode"]) ? true : false; console.log("Job configured!"); console.log(" Slug: " + job.slug); diff --git a/public/objectui.js b/public/objectui.js index 4cfb5e3..75dc82e 100644 --- a/public/objectui.js +++ b/public/objectui.js @@ -27,7 +27,9 @@ function TrackEditor(shortcuts, videoframe) pos.ybr = y + (0.5 * pos.height); pos.xtl = x - (0.5 * pos.width); pos.ytl = y - (0.5 * pos.height); + pos.generated = false; me.track.moveboundingbox(pos); + if (pos.outside) me.track.setoutside(false); }); } @@ -108,7 +110,7 @@ function TrackEditor(shortcuts, videoframe) this.initializeshortucts(); } -function TrackObjectUI(button, container, videoframe, job, player, tracks, shortcuts, autotracker) +function TrackObjectUI(button, container, copypastecontainer, videoframe, job, player, tracks, shortcuts, autotracker) { var me = this; @@ -121,10 +123,10 @@ function TrackObjectUI(button, container, videoframe, job, player, tracks, short this.shortcuts = shortcuts; this.autotracker = autotracker; - this.copypastehandler = new CopyPasteHandler(); + this.copypastehandler = new CopyPasteHandler(copypastecontainer, this.job); this.trackeditor = new TrackEditor(this.shortcuts, this.videoframe); - this.drawer = new BoxDrawer(videoframe); + this.drawer = new BoxDrawer(videoframe, {"width":10, "height":10}, this.job.pointmode); this.counter = job.nextid; @@ -135,6 +137,93 @@ function TrackObjectUI(button, container, videoframe, job, player, tracks, short this.selectedobject = null; + this.defaultsize = function(container) { + $("" + + "").appendTo(container); + + var sizeeditor = $("
").appendTo(container); + var testbox = $("
").css({ + "border": "solid 2px blue", + "width": this.drawer.defaultsize["width"] + "px", + "height": this.drawer.defaultsize["height"] + "px", + "margin-bottom": "10px", + "margin-top": "20px" + }) + + $("").appendTo(sizeeditor); + $("
") + .slider({ + min: 0, + max: 200, + value: this.drawer.defaultsize ["width"], + slide: function (event, ui) { + testbox.css({width: ui.value}); + } + }) + .css({"width":"200px"}) + .appendTo(sizeeditor); + + $("").appendTo(sizeeditor); + $("
") + .slider({ + min: 0, + max: 200, + value: this.drawer.defaultsize ["height"], + slide: function (event, ui) { + testbox.css({height: ui.value}); + } + }) + .css({"width":"200px"}) + .appendTo(sizeeditor); + + testbox.appendTo(sizeeditor); + + if (this.drawer.oneclick) { + $("#usedefaultsize").attr('checked', 'checked'); + } else { + sizeeditor.hide(); + } + + $("#usedefaultsize").change(function() { + if ($(this).is(":checked")) { + sizeeditor.show(); + } else { + sizeeditor.hide(); + } + }); + } + + this.defaultclass = function(container) { + var html = "

Select default class

"; + for (var i in job.labels) + { + html += "
" + + "" + + "
"; + } + + this.classifyinst = $("
" + html + "

").appendTo(container); + + } + + this.defaultsdialog = function(container) { + this.defaultclass(container); + if (!this.job.pointmode) { + this.defaultsize(container); + } + } + + this.savedefaults = function() { + if (!this.job.pointmode) { + if (!this.job.pointmode) this.drawer.oneclick = $("#usedefaultsize").attr('checked'); + this.drawer.defaultsize["width"] = $('#defaultwidth').slider("option", "value"); + this.drawer.defaultsize["height"] = $('#defaultheight').slider("option", "value"); + } + + alert($("input[name=classification]:checked").val()); + + } + this.deselectcurrentobject = function() { this.selectedobject = null; @@ -204,6 +293,7 @@ function TrackObjectUI(button, container, videoframe, job, player, tracks, short console.log("Received new track object drawing"); var track = tracks.add(player.frame, position, this.currentcolor[0], false); + if (this.job.pointmode) this.tracks.resizable(false); this.drawer.disable(); ui_disable(); @@ -227,7 +317,7 @@ function TrackObjectUI(button, container, videoframe, job, player, tracks, short this.setupnewobject(this.currentobject); this.tracks.draggable(true); - if ($("#annotateoptionsresize:checked").size() == 0) + if (!this.job.pointmode && $("#annotateoptionsresize:checked").size() == 0) { this.tracks.resizable(true); } @@ -238,6 +328,7 @@ function TrackObjectUI(button, container, videoframe, job, player, tracks, short this.tracks.dim(false); this.currentobject.track.highlight(false); + this.selectobject(this.currentobject); this.button.button("option", "disabled", false); @@ -722,10 +813,10 @@ function TrackObject(job, player, container, color, copypastehandler, autotracke me.track.tracktopreviouskeyframe(); }); $("#trackobject" + this.id + "cutend").click(function() { - me.copypastehandler.cut(me.track, me.player.frame); + me.copypastehandler.cut(me, me.player.frame); }); $("#trackobject" + this.id + "paste").click(function() { - me.copypastehandler.paste(me.track); + me.copypastehandler.paste(me); }); this.player.onupdate.push(function() { @@ -1105,23 +1196,46 @@ function TrackObject(job, player, container, color, copypastehandler, autotracke } } -function CopyPasteHandler() +function CopyPasteHandler(container, job) { + var me = this; + this.annotations = null; - this.cut = function(track, frame) { + this.job = job; + this.container = container; + this.container.hide(); + + this.cut = function(trackobject, frame) { + var track = trackobject.track; this.annotations = track.annotationstoend(frame); + + this.container.empty(); + this.container.append("
Clipboard
"); + this.container.append("Cut: " + this.annotations.length + " frames
"); + this.container.append("From: " + this.job.labels[track.label] + " " + track.id + "
"); + $("") + .appendTo(this.container) + .click(function() { + me.annotations = null; + me.container.slideUp(null, function() {me.container.empty();}); + }); + + this.container.slideDown(); track.cleartoend(frame); } - this.paste = function(track) { + this.paste = function(trackobject) { if (!this.annotations) { alert("Nothing to paste"); return; } + var track = trackobject.track; var range = this.framerange(); track.clearbetweenframes(range['min'], range['max']); track.addannotations(this.annotations); + trackobject.toggletooltip(false); + setTimeout(function() {trackobject.hidetooltip();}, 3000); } this.framerange = function() { diff --git a/public/stylesheet.css b/public/stylesheet.css index c448e4c..bbdb02e 100644 --- a/public/stylesheet.css +++ b/public/stylesheet.css @@ -145,6 +145,23 @@ canvas width : 80px; } +#copypastecontainer +{ + + font-family : Arial; + font-size : 14px; + background-color: yellow; + padding: 5px; + border-bottom: 2px solid black; +} + +#copypastecontainer .title +{ + text-align: center; + font-weight: bold; + margin-bottom: 3px; +} + #newobjectcontainer { text-align : center; diff --git a/public/tracks.js b/public/tracks.js index e6e0119..12ad78c 100644 --- a/public/tracks.js +++ b/public/tracks.js @@ -1,10 +1,13 @@ /* * Allows the user to draw a box on the screen. */ -function BoxDrawer(container) +function BoxDrawer(container, defaultsize, oneclick) { var me = this; + this.defaultsize = defaultsize; + this.oneclick = oneclick; + this.onstartdraw = []; this.onstopdraw = [] @@ -79,7 +82,18 @@ function BoxDrawer(container) { if (this.enabled) { - if (!this.drawing) + if (this.oneclick) + { + this.drawing = true; + var minx = xc - (this.defaultsize["width"] / 2); + var miny = yc - (this.defaultsize["height"] / 2); + var maxx = xc + (this.defaultsize["width"] / 2); + var maxy = yc + (this.defaultsize["height"] / 2); + this.startx = minx; + this.starty = miny; + this.finishdrawing(maxx, maxy); + } + else if (!this.drawing) { this.startdrawing(xc, yc); } @@ -186,7 +200,7 @@ function BoxDrawer(container) } this.drawing = false; - this.handle.remove(); + if (this.handle) this.handle.remove(); this.startx = 0; this.starty = 0; } @@ -694,6 +708,7 @@ function Track(player, topviewplayer, color, position, runtracking) this.journal.mark(this.player.frame, pos); this.journal.artificialright = this.journal.rightmost(); this.journal.cleartonextkeyframe(this.player.frame); + this.journal.artificialright = this.journal.rightmost(); this.draw(this.player.frame, pos); } @@ -1365,7 +1380,7 @@ function Journal(start, blowradius) var item = this.annotations[t]; itemtime = parseInt(t); - if (itemtime > frame) + if (itemtime > frame && !item.generated) { if (next == null || itemtime < nexttime) { @@ -1388,7 +1403,7 @@ function Journal(start, blowradius) var item = this.annotations[t]; itemtime = parseInt(t); - if (itemtime < frame) + if (itemtime < frame && !item.generated) { if (previous == null || itemtime > previoustime) { diff --git a/public/ui.js b/public/ui.js index 8ba4c19..ca23255 100644 --- a/public/ui.js +++ b/public/ui.js @@ -13,7 +13,7 @@ function ui_build(job) } var tracks = new TrackCollection(player, planeview, job); var autotracker = new AutoTracker(job, tracks); - var objectui = new TrackObjectUI($("#newobjectbutton"), $("#objectcontainer"), videoframe, job, player, tracks, shortcut, autotracker); + var objectui = new TrackObjectUI($("#newobjectbutton"), $("#objectcontainer"), $("#copypastecontainer"), videoframe, job, player, tracks, shortcut, autotracker); if (planeview) { planeview.initializetracks(tracks); @@ -27,6 +27,7 @@ function ui_build(job) ui_setupclickskip(job, player, tracks, objectui); ui_setupkeyboardshortcuts(shortcut, job, player); ui_loadprevious(job, objectui); + ui_setupnewobjectdefaults(objectui); $("#newobjectbutton").click(function() { if (!mturk_submitallowed()) @@ -65,6 +66,7 @@ function ui_setup(job) "" + "").appendTo(screen).css("width", "100%"); + $("
").appendTo(screen) var playerwidth = Math.max(720, job.width); @@ -93,8 +95,11 @@ function ui_setup(job) $("#homography").append(""); $("#topbar").append("
" + - "
New Object
"); + "
New Object
" + + "
Defaults
" + + "
"); + $("
").appendTo("#sidebar"); $("
").appendTo("#sidebar"); $("
Tracking Options
") @@ -146,9 +151,13 @@ function ui_setup(job) $("#advancedoptions").hide(); + if (!job.pointmode) { + $("#advancedoptions").append( + "" + + " "); + } + $("#advancedoptions").append( - "" + - " " + "" + " " + "" + @@ -327,20 +336,22 @@ function ui_setupbuttons(job, player, tracks, autotracker) console.log("Changed algorighm to: " + autotracker.algorithm); eventlog("trackingalgorithm", "FPS = " + autotracker.algorithm); }); + + if (!job.pointmode) { + $("#annotateoptionsresize").button().click(function() { + var resizable = $(this).attr("checked") ? false : true; + tracks.resizable(resizable); - $("#annotateoptionsresize").button().click(function() { - var resizable = $(this).attr("checked") ? false : true; - tracks.resizable(resizable); - - if (resizable) - { - eventlog("disableresize", "Objects can be resized"); - } - else - { - eventlog("disableresize", "Objects can not be resized"); - } - }); + if (resizable) + { + eventlog("disableresize", "Objects can be resized"); + } + else + { + eventlog("disableresize", "Objects can not be resized"); + } + }); + } $("#annotateoptionshideboxes").button().click(function() { var visible = !$(this).attr("checked"); @@ -409,8 +420,9 @@ function ui_setupkeyboardshortcuts(shortcutmanager, job, player) skipcallback(job.skip > 0 ? -job.skip : -1)); } -function ui_canresize() +function ui_canresize(job) { + if (job.pointmode) return false; return !$("#annotateoptionsresize").attr("checked"); } @@ -488,7 +500,7 @@ function ui_setupclickskip(job, player, tracks, objectui) $("#newobjectbutton").button("option", "disabled", false); $("#playbutton").button("option", "disabled", false); tracks.draggable(true); - tracks.resizable(ui_canresize()); + tracks.resizable(ui_canresize(job)); tracks.recordposition(); objectui.enable(); } @@ -526,6 +538,32 @@ function ui_loadprevious(job, objectui) }); } +function ui_setupnewobjectdefaults(objectui) { + var dialog = $("#dialog").dialog({ + autoOpen: false, + height: 300, + width: 350, + modal: true, + buttons: { + "Save": function() { + objectui.savedefaults(); + dialog.dialog("close"); + }, + Cancel: function() { + dialog.dialog("close"); + } + }, + close: function() {} + }); + + $("#newobjectdefaults") + .button({icons: {primary: 'ui-icon-gear'}}) + .click(function() { + dialog.dialog("open"); + objectui.defaultsdialog(dialog); + }); +} + function ui_setupsubmit(job, tracks) { $("#submitbutton").button({ diff --git a/public/visualizer.js b/public/visualizer.js index 33df8df..7ca2a31 100644 --- a/public/visualizer.js +++ b/public/visualizer.js @@ -44,7 +44,7 @@ function PlaneView(handle, player, homography) this.drawalltrajectories = function(tracks) { for (var i in tracks.tracks) { - this.drawtrajectory(tracks.tracks[i]); + //this.drawtrajectory(tracks.tracks[i]); } } diff --git a/server.py b/server.py index b25b6d2..bd21844 100644 --- a/server.py +++ b/server.py @@ -70,6 +70,7 @@ def getjob(id, verified): "homography": homography, "trackers": tracking.api.gettrackers(), "nextid": video.nextid(), + "pointmode": int(video.pointmode), } @handler()