diff --git a/src/bower_components/video-tagging/optional-tags.html b/src/bower_components/video-tagging/optional-tags.html index 0e2e16688d..6d9abbbbba 100644 --- a/src/bower_components/video-tagging/optional-tags.html +++ b/src/bower_components/video-tagging/optional-tags.html @@ -28,6 +28,7 @@ }, createTagControls: function(tagsArray) { $('#buttonsContainer').empty(); + this.colors = this.generateRandomColors(tagsArray.length) for(var index = 0;index < tagsArray.length;index++){ var btn = document.createElement("input"); btn.id = tagsArray[index]; @@ -46,6 +47,7 @@ self.fire('ontagsubmitted', {tagid:e.target.id}); } }); + btn.style.color = this.colors[index]; btn.value = tagsArray[index]; Polymer.dom(this.$.buttonsContainer).appendChild(btn); } @@ -85,7 +87,151 @@ $(this.buttonsContainer).find('.tagButtons').each(function(index){ this.disabled = !enable; }); - } + }, + + generateRandomColors: function(number){ + /* + https://stackoverflow.com/questions/10014271/generate-random-color-distinguishable-to-humans + This generates colors using the following algorithm: + Each time you create a color: + Create a random, but attractive, color{ + Red, Green, and Blue are set to random luminosity. + One random value is reduced significantly to prevent grayscale. + Another is increased by a random amount up to 100%. + They are mapped to a random total luminosity in a medium-high range (bright but not white). + } + Check for similarity to other colors{ + Check if the colors are very close together in value. + Check if the colors are of similar hue and saturation. + Check if the colors are of similar luminosity. + If the random color is too similar to another, + and there is still a good opportunity to change it: + Change the hue of the random color and try again. + } + Output array of all colors generated + */ + //if we've passed preloaded colors and they're in hex format + if(typeof(arguments[1])!='undefined'&&arguments[1].constructor==Array&&arguments[1][0]&&arguments[1][0].constructor!=Array){ + for(var i=0;i360){ //if it's too high + hsl[0]-=360 //decrease it mod 360 + }else if(hsl[0]<0){ //if it's too low + hsl[0]+=360 //increase it mod 360 + } + return hslToRGB(hsl); //convert back to rgb + },differenceRecursions={//stores recursion data, so if all else fails we can use one of the hues already generated + differences:[],//used to calculate the most distant hue + values:[]//used to store the actual colors + },fixDifference=function(color){//recursively asserts that the current color is distinctive + if(differenceRecursions.values.length>23){//first, check if this is the 25th recursion or higher. (can we try any more unique hues?) + //if so, get the biggest value in differences that we have and its corresponding value + var ret=differenceRecursions.values[differenceRecursions.differences.indexOf(Math.max.apply(null,differenceRecursions.differences))]; + differenceRecursions={differences:[],values:[]}; //then reset the recursions array, because we're done now + return ret; //and then return up the recursion chain + } //okay, so we still have some hues to try. + var differences=[]; //an array of the "difference" numbers we're going to generate. + for(var i=0;i1){ //if there's a problem with range or luminosity + //set the biggest difference for these colors to be whatever is most significant + differences.push(Math.min(differenceRange+lumDifference,sumDifference)); + } + differences.push(sumDifference); //otherwise output the raw difference in RGB values + } + var breakdownAt=64, //if you're generating this many colors or more, don't try so hard to make unique hues, because you might fail. + breakdownFactor=25, //how much should additional colors decrease the acceptable difference + shiftByDegrees=15, //how many degrees of hue should we iterate through if this fails + acceptableDifference=250, //how much difference is unacceptable between colors + breakVal=loadedColors.length/number*(number-breakdownAt), //break down progressively (if it's the second color, you can still make it a unique hue) + totalDifference=Math.min.apply(null,differences); //get the color closest to the current color + if(totalDifference>acceptableDifference-(breakVal<0?0:breakVal)*breakdownFactor){ //if the current color is acceptable + differenceRecursions={differences:[],values:[]} //reset the recursions object, because we're done + return color; //and return that color + } //otherwise the current color is too much like another + //start by adding this recursion's data into the recursions object + differenceRecursions.differences.push(totalDifference); + differenceRecursions.values.push(color); + color=shiftHue(color,shiftByDegrees); //then increment the color's hue + return fixDifference(color); //and try again + },color=function(){ //generate a random color + var scale=function(x){ //maps [0,1] to [300,510] + return x*210+300 //(no brighter than #ff0 or #0ff or #f0f, but still pretty bright) + },randVal=function(){ //random value between 300 and 510 + return Math.floor(scale(Math.random())) + },luminosity=randVal(), //random luminosity + red=randVal(), //random color values + green=randVal(), //these could be any random integer but we'll use the same function as for luminosity + blue=randVal(), + rescale, //we'll define this later + thisColor=[red,green,blue], //an array of the random values + /* + #ff0 and #9e0 are not the same colors, but they are on the same range of the spectrum, namely without blue. + Try to choose colors such that consecutive colors are on different ranges of the spectrum. + This shouldn't always happen, but it should happen more often then not. + Using a factor of 2.3, we'll only get the same range of spectrum 15% of the time. + */ + valueToReduce=Math.floor(lastLoadedReduction+1+Math.random()*2.3)%3, //which value to reduce + /* + Because 300 and 510 are fairly close in reference to zero, + increase one of the remaining values by some arbitrary percent betweeen 0% and 100%, + so that our remaining two values can be somewhat different. + */ + valueToIncrease=Math.floor(valueToIncrease+1+Math.random()*2)%3, //which value to increase (not the one we reduced) + increaseBy=Math.random()+1; //how much to increase it by + lastLoadedReduction=valueToReduce; //next time we make a color, try not to reduce the same one + thisColor[valueToReduce]=Math.floor(thisColor[valueToReduce]/16); //reduce one of the values + thisColor[valueToIncrease]=Math.ceil(thisColor[valueToIncrease]*increaseBy) //increase one of the values + rescale=function(x){ //now, rescale the random numbers so that our output color has the luminosity we want + return x*luminosity/thisColor.reduce(function(a,b){return a+b}) //sum red, green, and blue to get the total luminosity + }; + thisColor=fixDifference(thisColor.map(function(a){return rescale(a)})); //fix the hue so that our color is recognizable + if(Math.max.apply(null,thisColor)>255){ //if any values are too large + rescale=function(x){ //rescale the numbers to legitimate hex values + return x*255/Math.max.apply(null,thisColor) + } + thisColor=thisColor.map(function(a){return rescale(a)}); + } + return thisColor; + }; + for(var i=loadedColors.length;i \ No newline at end of file diff --git a/src/bower_components/video-tagging/video-tagging.html b/src/bower_components/video-tagging/video-tagging.html index 4a6e7ba7a7..3fa19aa823 100644 --- a/src/bower_components/video-tagging/video-tagging.html +++ b/src/bower_components/video-tagging/video-tagging.html @@ -204,7 +204,7 @@ } }); //bind keys (note this currently overrides any listener on the parent controls needs a more elegant way to work only when control is in focus) - window.addEventListener("keydown", (function(canMove) { + window.addEventListener("keyup", (function(canMove) { return function(e) { if (!canMove) return false; canMove = false; @@ -260,6 +260,9 @@ arr.push(e.detail.tagid); this.addTagsToRegion(arr); this.emitRegionToHost();//Persist + selected_region = this.selectedRegionId + this.showAllRegions(); + this.regionSelected(selected_region) }); this.addEventListener("ontagdeleted", function(e) { var regionId = this.selectedRegionId -1;//Revert to zero-based array @@ -271,6 +274,9 @@ } } this.emitRegionToHost(); + selected_region = this.selectedRegionId + this.showAllRegions(); + this.regionSelected(selected_region) }); }, @@ -364,7 +370,8 @@ var xOffset = parseFloat(this.overlay.style.left); var yOffset = parseFloat(this.overlay.style.top); this.addDivToRegion(x1 + (isNaN(xOffset) ? 0 : xOffset), y1 + (isNaN(yOffset) ? 0 : yOffset), - x2 + (isNaN(xOffset) ? 0 : xOffset), y2 + (isNaN(yOffset) ? 0 : yOffset), region.name); //add frame + x2 + (isNaN(xOffset) ? 0 : xOffset), y2 + (isNaN(yOffset) ? 0 : yOffset), + region.name, region.tags); //add frame this.updateRegionZIndices();//update region z indecies this.regionSelected(region.name);//Select it by default //if there is only one tag enable it by default @@ -524,10 +531,15 @@ * @params {x1, y1, x2, y2} region coordinates. * @param {regionId} The region id, which is the region index + 1. */ - addDivToRegion: function(x1, y1, x2, y2, regionId) { + addDivToRegion: function(x1, y1, x2, y2, regionId, tags) { var div = document.createElement("div"); div.id = regionId; div.classList.add("regionCanvas"); + if (tags.length > 0){ + div.style.borderColor = this.optionalTags.colors[this.inputtagsarray.indexOf(tags[0])]; + }else { + div.style.borderColor = null; + } if(this.regiontype.toLowerCase() === "point") { div.style.width = this.regionsize - 1 + "px";//Compensate for 1px border div.style.height = this.regionsize - 1 + "px"; @@ -606,8 +618,10 @@ y2 = (region.y2 * heightRatio); var xOffset = parseFloat(this.overlay.style.left); var yOffset = parseFloat(this.overlay.style.top); + this.addDivToRegion(x1 + (isNaN(xOffset) ? 0 : xOffset), y1 + (isNaN(yOffset) ? 0 : yOffset), - x2 + (isNaN(xOffset) ? 0 : xOffset), y2 + (isNaN(yOffset) ? 0 : yOffset), region.name); //add frame + x2 + (isNaN(xOffset) ? 0 : xOffset), y2 + (isNaN(yOffset) ? 0 : yOffset), + region.name, region.tags); //add frame //Only 1 region - select it and show tags if (regions.length === 1) { this.regionSelected(region.name); @@ -771,7 +785,7 @@ //bind keys (note this currently overrides any listener on the parent controls needs a more elegant way to work only when control is in focus) - window.addEventListener("keydown", (function(canMove) { + window.addEventListener("keyup", (function(canMove) { return function(e) { if (!canMove) return false; canMove = false; @@ -783,6 +797,23 @@ case 39: // right self.stepFwdClicked(); break; + case 9: //tab + if (self.selectedRegionId){ + if (self.selectedRegionId >= self.frames[self.getCurrentFrame()].length){ + self.regionSelected(0) + } + // self.selectedRegionId += 1 + self.regionSelected(parseInt(self.selectedRegionId)+1) + } else{ + self.regionSelected(0) + } + break; + case 68:// d for duplicate + if (self.imageIndex > 0){ + self.frames[self.imageIndex] = JSON.parse(JSON.stringify(self.frames[self.imageIndex-1])); + } + self.playingCallback(); + break; case 46: //delete case 8: //backspace if($('.regionCanvasSelected')[0]){ @@ -897,7 +928,7 @@ } }, - stepBwdClicked: function() { + stepBwdClicked: function(fireEvents = true) { if (!this.canMove) return; if (this.imagelist){//image handling if (this.imageIndex > 0) { @@ -915,6 +946,7 @@ this.playingCallback(); } } + if(fireEvents)$('#video-tagging').trigger('stepBwdClicked-AfterStep'); }, videoSrcChanged: function(newValue, oldValue) { if(this.video){ diff --git a/src/bower_components/video-tagging/video-taggingstyles.html b/src/bower_components/video-tagging/video-taggingstyles.html index 839ae06ea4..273bf0e93b 100644 --- a/src/bower_components/video-tagging/video-taggingstyles.html +++ b/src/bower_components/video-tagging/video-taggingstyles.html @@ -76,7 +76,6 @@ } - /*region div and label*/ .regionLabel{ background:rgb(59,56,56); @@ -98,7 +97,7 @@ z-index: 100; background-color: transparent; position: absolute !important; - border: 4px solid blue; + border: 2px solid; border-radius: 8px; } @@ -122,7 +121,7 @@ .regionCanvasSelected{ - border: 4px solid #C00000; + border: 5px solid; border-radius: 8px; } diff --git a/src/index.js b/src/index.js index 3d1f57fb46..466b3cad33 100644 --- a/src/index.js +++ b/src/index.js @@ -272,6 +272,12 @@ function openPath(pathName, isDir) { $('title').text(`Image Tagging Job: ${path.basename(videotagging.curImg.src)}`); }); + $("#video-tagging").on("stepBwdClicked-AfterStep", () => { + //update title to match src + $('title').text(`Image Tagging Job: ${path.basename(videotagging.curImg.src)}`); + + }); + //auto-save $("#video-tagging").off("stepFwdClicked-BeforeStep"); diff --git a/src/lib/detection_algorithms/cntkfastrcnn/reviewer.js b/src/lib/detection_algorithms/cntkfastrcnn/reviewer.js index 095df3c524..86d932fcb7 100644 --- a/src/lib/detection_algorithms/cntkfastrcnn/reviewer.js +++ b/src/lib/detection_algorithms/cntkfastrcnn/reviewer.js @@ -2,7 +2,7 @@ const path = require('path'); const config_path = path.join(__dirname, 'cntk-config.json'); const cntkConfig = require(config_path); -const cntkModel= require('cntk-fastercnn'); +const cntkModel= require('cntk-fastrcnn'); // An model reviewer class that provides functionality to review images using the model // Constructor parameters: