diff --git a/config/config.json b/config/config.json index 54c7f98..f9be833 100644 --- a/config/config.json +++ b/config/config.json @@ -2,11 +2,75 @@ "datasets": [ { "name": "NuScenes", - "sequences": ["ONE"] + "sequences": [ + "ONE" + ], + "classes": [ + "human.pedestrian.adult", + "human.pedestrian.child", + "human.pedestrian.wheelchair", + "human.pedestrian.stroller", + "human.pedestrian.personal_mobility", + "human.pedestrian.police_officer", + "human.pedestrian.construction_worker", + "animal", + "vehicle.car", + "vehicle.motorcycle", + "vehicle.bicycle", + "vehicle.bus.bendy", + "vehicle.bus.rigid", + "vehicle.truck", + "vehicle.construction", + "vehicle.emergency.ambulance", + "vehicle.emergency.police", + "vehicle.trailer", + "movable_object.barrier", + "movable_object.trafficcone", + "movable_object.pushable_pullable", + "movable_object.debris", + "static_object.bicycle_rack" + ], + "class_colors": [ + "#3ABB9D", + "#4DA664", + "#2F6CAD", + "#4590B6", + "#5CADCF", + "#3585C5", + "#2CA786", + "#6ABB72", + "#E66B5B", + "#A28F85", + "#F79E3D", + "#75706B", + "#EE7841", + "#D1D5D8", + "#CC4846", + "#DC5047", + "#28324E", + "#EFEFEF", + "#485675", + "#F2D46F", + "#533D7F", + "#9069B5", + "#F7C23E" + ] }, { "name": "providentia", - "sequences": ["20201010_sequence1"] + "sequences": [ + "20201010_sequence1" + ], + "classes": [ + "car", + "trailer", + "motorcycle", + "bicycle", + "bus", + "van", + "pedestrian" + ], + "class_colors": ["#51C38C", "#EBCF36","#FF604B", "#F37CB2","#7d74f5", "#BC7C52","#74BAF5"] } ] } \ No newline at end of file diff --git a/js/base_label_tool.js b/js/base_label_tool.js index a428515..9159d46 100755 --- a/js/base_label_tool.js +++ b/js/base_label_tool.js @@ -29,7 +29,7 @@ let labelTool = { imageSizes: {}, originalAnnotations: [], // For checking modified or not skipFrameCount: 1, - targetClass: "vehicle", + targetClass: "", // pageBox: document.getElementById('page_num'), savedFrames: [], cubeArray: [], @@ -158,7 +158,8 @@ let labelTool = { pointSize: 1, pointMaterial: new THREE.PointsMaterial({size: 5, sizeAttenuation: false, vertexColors: THREE.VertexColors}), views: {perspective: "perspective", orthographic: "orthographic"}, - maxTrackIds: [0, 0, 0, 0, 0],// vehicle, truck, motorcycle, bicycle, pedestrian + classes: [], + classColors: [], /********** Externally defined functions ********** * Define these functions in the labeling tools. **************************************************/ @@ -337,7 +338,7 @@ let labelTool = { pointCloudFullURL = 'input/' + labelTool.currentDataset + '/' + labelTool.sequence + '/' + 'pointclouds/' + labelTool.fileNames[i] + '.pcd'; pcdLoader.load(pointCloudFullURL, function (mesh) { mesh.name = 'pointcloud-scan-' + i; - pointCloudScanList.push(mesh); + pointCloudScanMap[i] = mesh; if (i === labelTool.currentFileIndex) { scene.add(mesh); } @@ -349,7 +350,7 @@ let labelTool = { } labelTool.pointCloudLoaded = true; } else { - scene.add(pointCloudScanList[labelTool.currentFileIndex]); + scene.add(pointCloudScanMap[labelTool.currentFileIndex]); } @@ -383,14 +384,6 @@ let labelTool = { }); } }, - - setTrackIds: function () { - for (let annotationObj in annotationObjects.contents[labelTool.currentFileIndex]) { - let annotation = annotationObjects.contents[labelTool.currentFileIndex][annotationObj]; - let label = annotation["class"]; - classesBoundingBox[label].nextTrackId++; - } - }, loadAnnotationsNuscenes: function (annotations, fileIndex) { // Add new bounding boxes. for (let i in annotations) { @@ -409,14 +402,12 @@ let labelTool = { params.original.rotationPitch = parseFloat(annotation.rotationPitch); params.original.rotationRoll = parseFloat(annotation.rotationRoll); if (labelTool.showOriginalNuScenesLabels === true && labelTool.currentDataset === labelTool.datasets.NuScenes) { - classesBoundingBox.addNuSceneLabel(annotation.class); - classesBoundingBox.__target = Object.keys(classesBoundingBox.content)[0]; - params.trackId = classesBoundingBox.content[annotation.class].nextTrackId; - classesBoundingBox.content[annotation.class].nextTrackId++; + classesBoundingBox.currentClass = labelTool.classes[0]; + params.trackId = classesBoundingBox[annotation.class].nextTrackId; } else { params.trackId = annotation.trackId; - classesBoundingBox[annotation.class].nextTrackId++; } + classesBoundingBox[annotation.class].nextTrackId++; // Nuscenes labels are stored in global frame in the database // Nuscenes: labels (3d positions) are transformed from global frame to point cloud (global -> ego, ego -> point cloud) before exporting them @@ -449,7 +440,7 @@ let labelTool = { // add new entry to contents array annotationObjects.set(annotationObjects.__insertIndex, params); annotationObjects.__insertIndex++; - classesBoundingBox.target().nextTrackId++; + classesBoundingBox.getCurrentAnnotationClassObject().nextTrackId++; } } }, @@ -469,11 +460,9 @@ let labelTool = { params.original.rotationPitch = parseFloat(annotation.box3d.orientation.rotationPitch); params.rotationRoll = parseFloat(annotation.box3d.orientation.rotationRoll); params.original.rotationRoll = parseFloat(annotation.box3d.orientation.rotationRoll); - let classIdx; params.trackId = annotation.id; - classIdx = classesBoundingBox[annotation.category].index; - if (params.trackId > labelTool.maxTrackIds[classIdx]) { - labelTool.maxTrackIds[classIdx] = params.id; + if (params.trackId > classesBoundingBox[annotation.category].maxTrackId) { + classesBoundingBox[annotation.category].maxTrackId = params.id; } // Nuscenes labels are stored in global frame in the database // Nuscenes: labels (3d positions) are transformed from global frame to point cloud (global -> ego, ego -> point cloud) before exporting them @@ -504,37 +493,22 @@ let labelTool = { // add new entry to contents array annotationObjects.set(annotationObjects.__insertIndex, params); annotationObjects.__insertIndex++; - if (labelTool.showOriginalNuScenesLabels === true) { - classesBoundingBox.content[classesBoundingBox.targetName()].nextTrackId++; - } else { - if (isNaN(classesBoundingBox.target().nextTrackId)) { - classesBoundingBox.target().nextTrackId = 1; - } - classesBoundingBox.target().nextTrackId++; + if (isNaN(classesBoundingBox.getCurrentAnnotationClassObject().nextTrackId)) { + classesBoundingBox.getCurrentAnnotationClassObject().nextTrackId = 0; } - - + classesBoundingBox[classesBoundingBox.getCurrentClass()].nextTrackId++; } }//end for loop frame annotations // reset track ids for next frame if nuscenes dataset and showLabels=true if (labelTool.showOriginalNuScenesLabels === true && labelTool.currentDataset === labelTool.datasets.NuScenes) { - for (let i = 0; i < classesBoundingBox.classNameArray.length; i++) { - classesBoundingBox.content[classesBoundingBox.classNameArray[i]].nextTrackId = 0; + for (let i = 0; i < labelTool.classes.length; i++) { + classesBoundingBox[labelTool.classes[i]].nextTrackId = 0; } } // reset insert index annotationObjects.__insertIndex = 0; - - if (labelTool.showOriginalNuScenesLabels === true) { - let keys = Object.keys(classesBoundingBox.content); - for (let i = 0; i < labelTool.maxTrackIds.length; i++) { - classesBoundingBox.content[keys[i]].nextTrackId = labelTool.maxTrackIds[i] + 1; - } - } else { - let keys = Object.keys(classesBoundingBox); - for (let i = 0; i < labelTool.maxTrackIds.length; i++) { - classesBoundingBox[keys[i]].nextTrackId = labelTool.maxTrackIds[i] + 1; - } + for (let i = 0; i < labelTool.classes.length; i++) { + classesBoundingBox[labelTool.classes[i]].nextTrackId = classesBoundingBox[labelTool.classes[i]].maxTrackId + 1; } // project 3D positions of current frame into 2D camera images if (labelTool.pointCloudOnlyAnnotation === false) { @@ -561,11 +535,10 @@ let labelTool = { params.original.rotationPitch = parseFloat(annotation.box3d.orientation.rotationYaw); params.rotationRoll = parseFloat(annotation.box3d.orientation.rotationPitch); params.original.rotationRoll = parseFloat(annotation.box3d.orientation.rotationPitch); - let classIdx; params.trackId = annotation.id; - classIdx = classesBoundingBox[annotation.category].index; - if (params.trackId > labelTool.maxTrackIds[classIdx]) { - labelTool.maxTrackIds[classIdx] = params.trackId; + // } + if (params.trackId > classesBoundingBox[annotation.category].maxTrackId) { + classesBoundingBox[annotation.category].maxTrackId = params.id; } params.x = parseFloat(annotation.box3d.location.x); params.y = parseFloat(annotation.box3d.location.y); @@ -595,17 +568,15 @@ let labelTool = { annotationObjects.set(annotationObjects.__insertIndex, params); annotationObjects.__insertIndex++; if (isNaN(classesBoundingBox[params.class].nextTrackId)) { - classesBoundingBox[params.class].nextTrackId = 1; + classesBoundingBox[params.class].nextTrackId = 0; } classesBoundingBox[params.class].nextTrackId++; } } // reset insert index annotationObjects.__insertIndex = 0; - - let keys = Object.keys(classesBoundingBox); - for (let i = 0; i < labelTool.maxTrackIds.length; i++) { - classesBoundingBox[keys[i]].nextTrackId = labelTool.maxTrackIds[i] + 1; + for (let i = 0; i < labelTool.classes.length; i++) { + classesBoundingBox[labelTool.classes[i]].nextTrackId = classesBoundingBox[labelTool.classes[i]].maxTrackId + 1; } }, @@ -655,7 +626,7 @@ let labelTool = { return annotationFiles; }, - initializePointCloudWindow: function () { + initPointCloudWindow: function () { let pointCloudContainer; if (labelTool.pointCloudOnlyAnnotation === true) { pointCloudContainer = $("#label-tool-wrapper"); @@ -664,7 +635,18 @@ let labelTool = { } pointCloudContainer.append('
'); this.localOnInitialize["PCD"](); - }, initializeClassPicker: function () { + }, initClasses: function () { + for (let i = 0; i < labelTool.classes.length; i++) { + classesBoundingBox[labelTool.classes[i]] = { + color: labelTool.classColors[i], + index: i, + nextTrackId: 0, + maxTrackId: -1 + }; + } + + }, initClassPicker: function () { + classesBoundingBox.currentClass = labelTool.classes[0]; $(function () { $('#class-picker>ul>li').hover(function () { $(this).css('background-color', "#535353"); @@ -678,7 +660,6 @@ let labelTool = { } }); }); - let toasts = $(".toasts")[0]; this.logger = new Toast(toasts); }, setPanelSize: function (newFileIndex) { @@ -734,7 +715,6 @@ let labelTool = { let topElem = $("#layout_layout_panel_top")[0]; let newImagePanelHeight = topElem.offsetHeight; let newWidth; - let newWidthBackFront; if (labelTool.currentDataset === labelTool.datasets.NuScenes) { newWidth = newImagePanelHeight * labelTool.imageAspectRatioNuScenes; } @@ -809,7 +789,7 @@ let labelTool = { w2ui['layout'].resizer = 10; w2ui['layout'].resize(); w2ui['layout'].refresh(); - }, initializeCameraWindows: function () { + }, initCameraWindows: function () { this.setImageSize(); this.initPanes(); let imageContainer = $("#layout_layout_panel_top .w2ui-panel-content"); @@ -935,7 +915,7 @@ let labelTool = { this.currentFileIndex = 0; this.fileNames = []; this.originalAnnotations = []; - this.targetClass = "vehicle"; + this.targetClass = this.classes[0]; this.savedFrames = []; this.cubeArray = []; this.currentCameraChannelIndex = 0; @@ -949,29 +929,32 @@ let labelTool = { this.selectedMesh = undefined; this.pointCloudLoaded = false; - // classesBoundingBox - classesBoundingBox.colorIdx = 0; - classesBoundingBox.__target = Object.keys(classesBoundingBox)[0]; - // pcd label tool folderBoundingBox3DArray = []; folderPositionArray = []; folderRotationArray = []; folderSizeArray = []; - pointCloudScanList = []; + pointCloudScanMap = []; let classPickerElem = $('#class-picker ul li'); classPickerElem.css('background-color', '#353535'); $(classPickerElem[0]).css('background-color', '#525252'); classPickerElem.css('border-bottom', '0px'); + // classesBoundingBox + classesBoundingBox.colorIdx = 0; + classesBoundingBox.currentClass = labelTool.classes[0]; classPickerElem.each(function (i, item) { - let propNamesArray = Object.getOwnPropertyNames(classesBoundingBox); - let color = classesBoundingBox[propNamesArray[i]].color; + let color = labelTool.classColors[i]; let attribute = "20px solid" + ' ' + color; $(item).css("border-left", attribute); $(item).css('border-bottom', '0px'); }); + for (let i = 0; i < labelTool.classes.length; i++) { + delete classesBoundingBox[labelTool.classes[i]]; + } + // remove guiClassesBoundingBox + $("#class-picker").remove(); if (labelTool.pointCloudOnlyAnnotation === false) { // image label tool @@ -994,7 +977,6 @@ let labelTool = { w2ui['layout'].resize(); } - classesBoundingBox.content = []; $(".frame-selector__frames").empty(); }, @@ -1038,14 +1020,14 @@ let labelTool = { }, start() { this.initTimer(); this.setFileNames(); - this.initTrackIDs(); - this.initializeClassPicker(); + this.initClasses(); + this.initClassPicker(); this.initFrameSelector(); if (labelTool.pointCloudOnlyAnnotation === false) { - this.initializeCameraWindows(); + this.initCameraWindows(); this.loadImageData(); } - this.initializePointCloudWindow(); + this.initPointCloudWindow(); this.loadPointCloudData(); this.loadAnnotations(); }, @@ -1060,13 +1042,10 @@ let labelTool = { parameters.currentDataset = labelTool.datasetArray[0]; labelTool.currentDatasetIdx = 0; labelTool.sequence = labelTool.dataStructure.datasets[0].sequences[0]; + labelTool.classes = labelTool.dataStructure.datasets[0].classes; + labelTool.classColors = labelTool.dataStructure.datasets[0].class_colors; + labelTool.targetClass = labelTool.classes[0]; }, - initTrackIDs() { - for (let i = 0; i < labelTool.maxTrackIds.length; i++) { - labelTool.maxTrackIds[i] = 0; - } - }, - setFileNames() { let fileNameArray = []; if (labelTool.currentDataset === labelTool.datasets.NuScenes) { @@ -1284,8 +1263,6 @@ let labelTool = { // if (objectIndexByTrackIdAndClass !== -1) { // next frame contains a new object -> add tooltip for new object let classTooltipElement = $("
" + trackId + "
"); - // set background color - let color = classesBoundingBox[className].color; let imagePaneHeight = parseInt($("#layout_layout_resizer_top").css("top"), 10); const vector = new THREE.Vector3(mesh.position.x, mesh.position.y, mesh.position.z + mesh.scale.z / 2); const canvas = renderer.domElement; @@ -1775,27 +1752,12 @@ function calculateAndDrawLineSegments(channelObj, className, horizontal, selecte let lineArray = []; let channelIdx = getChannelIndexByName(channel); // temporary color bottom 4 lines in yellow to check if projection matrix is correct - // let color = '#ffff00'; // uncomment line to use yellow to color bottom 4 lines let color; if (selected === true) { color = "#ff0000"; } else { - if (labelTool.showOriginalNuScenesLabels === true && labelTool.currentDataset === labelTool.datasets.NuScenes) { - let classIdx = classesBoundingBox.classNameArray.indexOf(className); - color = classesBoundingBox.colorArray[classIdx]; - } else { - color = classesBoundingBox[className].color; - } - } - - // color objects that are selected in red - - - let imageHeight = parseInt($("#layout_layout_resizer_top").css("top"), 10); - let imageWidth; - if (labelTool.currentDataset === labelTool.datasets.NuScenes) { - imageWidth = imageHeight * labelTool.imageAspectRatioNuScenes; + color = classesBoundingBox[className].color; } // bottom four lines @@ -1804,9 +1766,7 @@ function calculateAndDrawLineSegments(channelObj, className, horizontal, selecte lineArray.push(drawLine(channelIdx, channelObj.projectedPoints[2], channelObj.projectedPoints[3], color)); lineArray.push(drawLine(channelIdx, channelObj.projectedPoints[3], channelObj.projectedPoints[0], color)); - // draw line for orientation - let pointZero; let pointOne; let pointTwo; diff --git a/js/pcd_label_tool.js b/js/pcd_label_tool.js index 222ab85..bb9a6a6 100755 --- a/js/pcd_label_tool.js +++ b/js/pcd_label_tool.js @@ -52,8 +52,9 @@ let interpolationObjIndexNextFile = -1; let interpolateBtn; let pointSizeSlider; -let guiAnnotationClasses = new dat.GUI({autoPlace: true, width: 90, resizable: false}); -let guiBoundingBoxAnnotationMap; +let guiAnnotationClasses; +let guiBoundingBoxAnnotationsInitialized = false; +let guiBoundingBoxMenuInitialized = false; let guiOptions = new dat.GUI({autoPlace: true, width: 350, resizable: false}); let guiOptionsOpened = true; let numGUIOptions = 17; @@ -87,7 +88,7 @@ let activeColorMap = 'colorMapJet.js'; let currentPoints3D = []; let currentDistances = []; let spriteBehindObject; -let pointCloudScanList = []; +let pointCloudScanMap = []; let pointCloudScanNoGroundList = []; let useTransformControls; let dragControls = false; @@ -97,34 +98,6 @@ let pointSizeMax = 1; let defaultBoxHeight = 1.468628; let gridSize = 200; -let parametersBoundingBox = { - "Vehicle": function () { - classesBoundingBox.select("vehicle"); - $('#class-picker ul li').css('background-color', '#323232'); - $($('#class-picker ul li')[0]).css('background-color', '#525252'); - }, - "Truck": function () { - classesBoundingBox.select("truck"); - $('#class-picker ul li').css('background-color', '#323232'); - $($('#class-picker ul li')[1]).css('background-color', '#525252'); - }, - "Motorcycle": function () { - classesBoundingBox.select("motorcycle"); - $('#class-picker ul li').css('background-color', '#323232'); - $($('#class-picker ul li')[2]).css('background-color', '#525252'); - }, - "Bicycle": function () { - classesBoundingBox.select("bicycle"); - $('#class-picker ul li').css('background-color', '#323232'); - $($('#class-picker ul li')[3]).css('background-color', '#525252'); - }, - "Pedestrian": function () { - classesBoundingBox.select("pedestrian"); - $('#class-picker ul li').css('background-color', '#323232'); - $($('#class-picker ul li')[4]).css('background-color', '#525252'); - }, -}; - let parameters = { point_size: 0.05, download_video: function () { @@ -679,13 +652,9 @@ function get3DLabel(parameters) { let cubeGeometry = new THREE.BoxBufferGeometry(1.0, 1.0, 1.0);//width, length, height let color; if (parameters.fromFile === true) { - if (labelTool.showOriginalNuScenesLabels === true && labelTool.currentDataset === labelTool.datasets.NuScenes) { - color = classesBoundingBox.content[parameters.class].color; - } else { - color = classesBoundingBox[parameters.class].color; - } + color = classesBoundingBox[parameters.class].color; } else { - color = classesBoundingBox.target().color; + color = classesBoundingBox.getCurrentAnnotationClassObject().color; } let cubeMaterial = new THREE.MeshBasicMaterial({ @@ -771,7 +740,7 @@ function updateXPos(newFileIndex, value) { * @param label */ function setHighestAvailableTrackId(label) { - for (let newTrackId = 1; newTrackId <= annotationObjects.contents[labelTool.currentFileIndex].length; newTrackId++) { + for (let newTrackId = 0; newTrackId <= annotationObjects.contents[labelTool.currentFileIndex].length; newTrackId++) { let exist = false; for (let i = 0; i < annotationObjects.contents[labelTool.currentFileIndex].length; i++) { if (label === annotationObjects.contents[labelTool.currentFileIndex][i]["class"] && newTrackId === annotationObjects.contents[labelTool.currentFileIndex][i]["trackId"]) { @@ -781,18 +750,10 @@ function setHighestAvailableTrackId(label) { } if (exist === false) { // track id was not used yet - if (labelTool.showOriginalNuScenesLabels === true) { - classesBoundingBox.content[label].nextTrackId = newTrackId; - } else { - classesBoundingBox[label].nextTrackId = newTrackId; - } + classesBoundingBox[label].nextTrackId = newTrackId; break; } - if (labelTool.showOriginalNuScenesLabels === true) { - classesBoundingBox.content[label].nextTrackId = annotationObjects.contents[labelTool.currentFileIndex].length + 1; - } else { - classesBoundingBox[label].nextTrackId = annotationObjects.contents[labelTool.currentFileIndex].length + 1; - } + classesBoundingBox[label].nextTrackId = annotationObjects.contents[labelTool.currentFileIndex].length + 1; } } @@ -864,18 +825,8 @@ function deleteObject(bboxClass, trackId, labelIndex) { // remove sprite from DOM tree $("#tooltip-" + bboxClass.charAt(0) + trackId).remove(); labelTool.selectedMesh = undefined; - // reduce track id by 1 for this class - if (labelTool.showOriginalNuScenesLabels) { - classesBoundingBox.content[bboxClass].nextTrackId--; - } else { - if (labelIndex === annotationObjects.contents[labelTool.currentFileIndex].length) { - // decrement track id if the last object in the list was deleted - classesBoundingBox[bboxClass].nextTrackId--; - } else { - // otherwise not last object was deleted -> find out the highest possible track id - setHighestAvailableTrackId(bboxClass); - } - } + + setHighestAvailableTrackId(bboxClass); // if last object in current frame was deleted than disable interpolation mode if (annotationObjects.contents[labelTool.currentFileIndex].length === 0) { interpolationMode = false; @@ -903,9 +854,9 @@ function deleteObject(bboxClass, trackId, labelIndex) { function addBoundingBoxGui(bbox, bboxEndParams) { let insertIndex = folderBoundingBox3DArray.length; let bb; - if (guiOptions.__folders[bbox.class + ' ' + bbox.trackId] === undefined){ + if (guiOptions.__folders[bbox.class + ' ' + bbox.trackId] === undefined) { bb = guiOptions.addFolder(bbox.class + ' ' + bbox.trackId); - }else{ + } else { bb = guiOptions.__folders[bbox.class + ' ' + bbox.trackId]; } @@ -2017,6 +1968,14 @@ function changeDataset(datasetName) { labelTool.currentDataset = datasetName; labelTool.currentDatasetIdx = labelTool.datasetArray.indexOf(datasetName); labelTool.sequence = labelTool.dataStructure.datasets[labelTool.datasetArray.indexOf(datasetName)].sequences[0]; + labelTool.classes = labelTool.dataStructure.datasets[labelTool.datasetArray.indexOf(datasetName)].classes; + labelTool.classColors = labelTool.dataStructure.datasets[labelTool.datasetArray.indexOf(datasetName)].class_colors; + labelTool.initClasses(); + initGuiBoundingBoxAnnotations(); + // move button to left + $("#left-btn").css("left", 0); + // move class picker to left + $("#class-picker").css("left", 10); labelTool.start(); } @@ -2184,33 +2143,6 @@ function onDocumentMouseMove(event) { mousePos.y = -(event.clientY / window.innerHeight) * 2 + 1; } -function increaseTrackId(label, dataset) { - let classesBB; - if (dataset === labelTool.datasets.NuScenes) { - classesBB = classesBoundingBox.content; - } - - // find out the lowest possible track id for a specific class - - for (let newTrackId = 1; newTrackId <= annotationObjects.contents[labelTool.currentFileIndex].length; newTrackId++) { - let exist = false; - for (let i = 0; i < annotationObjects.contents[labelTool.currentFileIndex].length; i++) { - if (label !== annotationObjects.contents[labelTool.currentFileIndex]["class"]) { - continue; - } - if (newTrackId === annotationObjects.contents[labelTool.currentFileIndex][i]["trackId"]) { - exist = true; - break; - } - } - if (exist === false) { - // track id was not used yet - return newTrackId; - } - } - return -1; -} - function disableStartPose() { // disable slider folderPositionArray[interpolationObjIndexNextFile].domElement.style.opacity = 0.5; @@ -2525,6 +2457,7 @@ function mouseUpLogic(ev) { let classPickerElem = $('#class-picker ul li'); classPickerElem.css('background-color', '#353535'); $(classPickerElem[classesBoundingBox[obj["class"]].index]).css('background-color', '#525252'); + classesBoundingBox.currentClass = obj["class"]; } else { @@ -2588,11 +2521,11 @@ function mouseUpLogic(ev) { let trackId = -1; let insertIndex; - setHighestAvailableTrackId(classesBoundingBox.targetName()); + setHighestAvailableTrackId(classesBoundingBox.getCurrentClass()); if (labelTool.showOriginalNuScenesLabels === true && labelTool.currentDataset === labelTool.datasets.NuScenes) { if (annotationObjects.__selectionIndexCurrentFrame === -1) { // no object selected in 3d scene (new object was created)-> use selected class from class menu - trackId = classesBoundingBox.content[classesBoundingBox.targetName()].nextTrackId; + trackId = classesBoundingBox.content[classesBoundingBox.getCurrentClass()].nextTrackId; insertIndex = annotationObjects.contents[labelTool.currentFileIndex].length; } else { // object was selected in 3d scene @@ -2602,7 +2535,7 @@ function mouseUpLogic(ev) { } } else { if (annotationObjects.__selectionIndexCurrentFrame === -1) { - trackId = classesBoundingBox[classesBoundingBox.targetName()].nextTrackId; + trackId = classesBoundingBox[classesBoundingBox.getCurrentClass()].nextTrackId; insertIndex = annotationObjects.contents[labelTool.currentFileIndex].length; clickedObjectIndexPrevious = annotationObjects.__selectionIndexCurrentFrame; } else { @@ -2620,7 +2553,7 @@ function mouseUpLogic(ev) { // average car height in meters (ref: https://www.carfinderservice.com/car-advice/a-careful-look-at-different-sedan-dimensions) let addBboxParameters = getDefaultObject(); - addBboxParameters.class = classesBoundingBox.targetName(); + addBboxParameters.class = classesBoundingBox.getCurrentClass(); addBboxParameters.x = xPos; addBboxParameters.y = yPos; if (labelTool.currentDataset === labelTool.datasets.providentia) { @@ -2635,7 +2568,7 @@ function mouseUpLogic(ev) { addBboxParameters.rotationPitch = 0; addBboxParameters.rotationRoll = 0; addBboxParameters.original = { - class: classesBoundingBox.targetName(), + class: classesBoundingBox.getCurrentClass(), x: (groundPointMouseUp.x + groundPointMouseDown.x) / 2, y: (groundPointMouseUp.y + groundPointMouseDown.y) / 2, z: zPos + defaultBoxHeight / 2 - labelTool.positionLidarNuscenes[2], @@ -2678,7 +2611,7 @@ function mouseUpLogic(ev) { if (channelObj.channel !== undefined && channelObj.channel !== '') { if (addBboxParameters.channels[i].projectedPoints !== undefined && addBboxParameters.channels[i].projectedPoints.length === 8) { let horizontal = addBboxParameters.width > addBboxParameters.length; - addBboxParameters.channels[i]["lines"] = calculateAndDrawLineSegments(channelObj, classesBoundingBox.targetName(), horizontal, true); + addBboxParameters.channels[i]["lines"] = calculateAndDrawLineSegments(channelObj, classesBoundingBox.getCurrentClass(), horizontal, true); } } } @@ -2693,12 +2626,12 @@ function mouseUpLogic(ev) { } $("#tooltip-" + annotationObjects.contents[labelTool.currentFileIndex][insertIndex]["class"].charAt(0) + annotationObjects.contents[labelTool.currentFileIndex][insertIndex]["trackId"]).hide(); // move left button to right - $("#left-btn").css("left", window.innerWidth / 3 - 70); + $("#left-btn").css("left", window.innerWidth / 3); showHelperViews(xPos, yPos, zPos); annotationObjects.__insertIndex++; - classesBoundingBox.target().nextTrackId++; + classesBoundingBox.getCurrentAnnotationClassObject().nextTrackId++; for (let channelIdx in labelTool.camChannels) { if (labelTool.camChannels.hasOwnProperty(channelIdx)) { let camChannel = labelTool.camChannels[channelIdx].channel; @@ -2767,7 +2700,7 @@ function mouseDownLogic(ev) { if (birdsEyeViewFlag === true) { groundPlane.position.x = clickedPoint.x; groundPlane.position.y = clickedPoint.y; - groundPlane.position.z = clickedPoint.z; + groundPlane.position.z = -10;//clickedPoint.z; let normal = clickedObjects[0].face; if ([normal.a, normal.b, normal.c].toString() == [6, 3, 2].toString() || [normal.a, normal.b, normal.c].toString() == [7, 6, 2].toString()) { groundPlane.rotation.x = Math.PI / 2; @@ -2796,19 +2729,18 @@ function mouseDownLogic(ev) { let trackId = annotationObjects.contents[labelTool.currentFileIndex][clickedObjectIndex]["trackId"]; deleteObject(bboxClass, trackId, clickedObjectIndex); // move button to left - $("#left-btn").css("left", -70); + $("#left-btn").css("left", 0); }//end right click } else { for (let i = 0; i < annotationObjects.contents[labelTool.currentFileIndex].length; i++) { $("#tooltip-" + annotationObjects.contents[labelTool.currentFileIndex][i]["class"].charAt(0) + annotationObjects.contents[labelTool.currentFileIndex][i]["trackId"]).show(); } if (birdsEyeViewFlag === true) { - console.log("unselected"); clickedObjectIndex = -1; groundPlaneArray = []; groundPlane.position.x = 0; groundPlane.position.y = 0; - groundPlane.position.z = 0; + groundPlane.position.z = -10; groundPlaneArray.push(groundPlane); let groundObject = ray.intersectObjects(groundPlaneArray); if (groundObject !== undefined && groundObject[0] !== undefined) { @@ -2996,7 +2928,7 @@ function createGrid() { translationX = 0; } else { posZLidar = labelTool.positionLidar[2]; - translationX = gridSize/2; + translationX = gridSize / 2; } grid.translateZ(-posZLidar); grid.translateX(translationX); @@ -3089,7 +3021,7 @@ function loadDetectedBoxes() { } params.fileIndex = frameNumber - 1; annotationObjects.set(objectIndexWithinFrame, params); - classesBoundingBox.target().nextTrackId++; + classesBoundingBox.getCurrentAnnotationClassObject().nextTrackId++; } } } @@ -3097,6 +3029,31 @@ function loadDetectedBoxes() { rawFile.send(null); } +function initGuiBoundingBoxAnnotations() { + let parametersBoundingBox = {}; + for (let i = 0; i < labelTool.classes.length; i++) { + parametersBoundingBox[labelTool.classes[i]] = + function () { + classesBoundingBox.select(labelTool.classes[i]); + $('#class-picker ul li').css('background-color', '#323232'); + $($('#class-picker ul li')[i]).css('background-color', '#525252'); + } + } + let guiAnnotationClassesWidth; + if (labelTool.currentDataset === labelTool.datasets.NuScenes) { + guiAnnotationClassesWidth = 220; + } else { + guiAnnotationClassesWidth = 90; + } + guiAnnotationClasses = new dat.GUI({autoPlace: true, width: guiAnnotationClassesWidth, resizable: false}); + + let guiBoundingBoxAnnotationMap = {}; + for (let i = 0; i < labelTool.classes.length; i++) { + guiBoundingBoxAnnotationMap[labelTool.classes[i]] = guiAnnotationClasses.add(parametersBoundingBox, labelTool.classes[i]).name(labelTool.classes[i]); + } + guiAnnotationClasses.domElement.id = 'class-picker'; +} + function init() { if (WEBGL.isWebGLAvailable() === false) { document.body.appendChild(WEBGL.getWebGLErrorMessage()); @@ -3174,15 +3131,13 @@ function init() { annotationObjects.contents.push([]); } - if (guiBoundingBoxAnnotationMap === undefined) { - guiBoundingBoxAnnotationMap = { - "Vehicle": guiAnnotationClasses.add(parametersBoundingBox, "Vehicle").name("Vehicle"), - "Truck": guiAnnotationClasses.add(parametersBoundingBox, "Truck").name("Truck"), - "Motorcycle": guiAnnotationClasses.add(parametersBoundingBox, "Motorcycle").name("Motorcycle"), - "Bicycle": guiAnnotationClasses.add(parametersBoundingBox, "Bicycle").name("Bicycle"), - "Pedestrian": guiAnnotationClasses.add(parametersBoundingBox, "Pedestrian").name("Pedestrian"), - }; - guiAnnotationClasses.domElement.id = 'class-picker'; + if (guiBoundingBoxAnnotationsInitialized === false) { + guiBoundingBoxAnnotationsInitialized = true; + initGuiBoundingBoxAnnotations(); + } + + if (guiBoundingBoxMenuInitialized === false) { + guiBoundingBoxMenuInitialized = true; // 3D BB controls guiOptions.add(parameters, 'download').name("Download Annotations"); guiOptions.add(parameters, 'download_video').name("Create and Download Video"); @@ -3209,7 +3164,7 @@ function init() { labelTool.removeObject("planeObject"); }); pointSizeSlider = guiOptions.add(parameters, 'point_size').name("Point Size").min(0.001).max(pointSizeMax).step(0.001).onChange(function (value) { - pointCloudScanList[labelTool.currentFileIndex].material.size = value; + pointCloudScanMap[labelTool.currentFileIndex].material.size = value; }); disablePointSizeSlider(); let showOriginalNuScenesLabelsCheckbox = guiOptions.add(parameters, 'show_nuscenes_labels').name('NuScenes Labels').listen(); @@ -3300,7 +3255,7 @@ function init() { addObject(pointCloudScanNoGroundList[labelTool.currentFileIndex], "pointcloud-scan-no-ground-" + labelTool.currentFileIndex); } else { labelTool.removeObject("pointcloud-scan-no-ground-" + labelTool.currentFileIndex); - addObject(pointCloudScanList[labelTool.currentFileIndex], "pointcloud-scan-" + labelTool.currentFileIndex); + addObject(pointCloudScanMap[labelTool.currentFileIndex], "pointcloud-scan-" + labelTool.currentFileIndex); } }); @@ -3451,13 +3406,15 @@ function init() { hideProjectedPoints(); } } - } + }// end if guiBoundingBoxMenuInitialized + let classPickerElem = $('#class-picker ul li'); classPickerElem.css('background-color', '#353535'); $(classPickerElem[0]).css('background-color', '#525252'); classPickerElem.css('border-bottom', '0px'); - - + if (labelTool.currentDataset === labelTool.datasets.NuScenes) { + $("#class-picker").css("width", '220px'); + } $('#bounding-box-3d-menu').css('width', '480px'); $('#bounding-box-3d-menu ul li').css('background-color', '#353535'); $("#bounding-box-3d-menu .close-button").click(function () { @@ -3468,16 +3425,12 @@ function init() { $("#right-btn").css("right", 0); } }); - guiOptions.open(); classPickerElem.each(function (i, item) { - let propNamesArray = Object.getOwnPropertyNames(classesBoundingBox); - let color = classesBoundingBox[propNamesArray[i]].color; + let color = labelTool.classColors[i]; let attribute = "20px solid" + ' ' + color; $(item).css("border-left", attribute); $(item).css('border-bottom', '0px'); }); - initViews(); - } \ No newline at end of file diff --git a/js/util/boundingbox.js b/js/util/boundingbox.js index be8b1ba..c1e5db2 100644 --- a/js/util/boundingbox.js +++ b/js/util/boundingbox.js @@ -64,7 +64,7 @@ let annotationObjects = { this.contents[params.fileIndex].insertIndex = insertIndex; if (params.fromFile === false && this.__selectionIndexCurrentFrame === -1) { if (labelTool.showOriginalNuScenesLabels === true && labelTool.currentDataset === labelTool.datasets.NuScenes) { - this.contents[params.fileIndex][insertIndex]["trackId"] = classesBoundingBox.content[params.class].nextTrackId; + this.contents[params.fileIndex][insertIndex]["trackId"] = classesBoundingBox[params.class].nextTrackId; } else { this.contents[params.fileIndex][insertIndex]["trackId"] = classesBoundingBox[params.class].nextTrackId; } @@ -81,7 +81,7 @@ let annotationObjects = { } // return if same class was chosen again - let currentClassLabel = classesBoundingBox.getCurrentClass(); + let currentClassLabel = this.contents[labelTool.currentFileIndex][selectedObjectIndex]["class"]; if (currentClassLabel === newClassLabel) { return false; } @@ -89,7 +89,7 @@ let annotationObjects = { // update id of sprite let currentTrackId = this.contents[labelTool.currentFileIndex][selectedObjectIndex]["trackId"]; - let spriteElem = $("#class-" + this.contents[labelTool.currentFileIndex][selectedObjectIndex]["class"].charAt(0) + currentTrackId); + let spriteElem = $("#class-" + currentClassLabel.charAt(0) + currentTrackId); // use original track id if original class selected let nextTrackIdNewClass; if (newClassLabel === this.contents[labelTool.currentFileIndex][selectedObjectIndex]["original"]["class"]) { @@ -108,8 +108,9 @@ let annotationObjects = { // update track id this.contents[labelTool.currentFileIndex][selectedObjectIndex]["trackId"] = nextTrackIdNewClass; - // decrease track id of current (previous) class - classesBoundingBox[currentClassLabel]["nextTrackId"] = classesBoundingBox[currentClassLabel]["nextTrackId"] - 1; + // set next highest track ID of current class + + setHighestAvailableTrackId(currentClassLabel); // increase track id of new class classesBoundingBox[newClassLabel]["nextTrackId"] = classesBoundingBox[newClassLabel]["nextTrackId"] + 1; @@ -123,6 +124,9 @@ let annotationObjects = { // ul number div div[class c] input folderBoundingBox3DArray[selectedObjectIndex].domElement.children[0].children[4].children[0].children[1].children[0].value = nextTrackIdNewClass; + guiOptions.__folders[newClassLabel + ' ' + nextTrackIdNewClass] = guiOptions.__folders[currentClassLabel + ' ' + currentTrackId]; + delete guiOptions.__folders[currentClassLabel + ' ' + currentTrackId]; + // open current folder folderBoundingBox3DArray[selectedObjectIndex].open(); folderPositionArray[selectedObjectIndex].open(); diff --git a/js/util/classesBoundingBox.js b/js/util/classesBoundingBox.js index d2381a7..1e81e19 100644 --- a/js/util/classesBoundingBox.js +++ b/js/util/classesBoundingBox.js @@ -1,76 +1,10 @@ let classesBoundingBox = { - "vehicle": { - color: '#51C38C', - index: 0, - nextTrackId: 1 - }, - "truck": { - color: '#EBCF36', - index: 1, - nextTrackId: 1 - }, - "motorcycle": { - color: '#FF604B', - index: 2, - nextTrackId: 1 - }, - "bicycle": { - color: '#F37CB2', - index: 3, - nextTrackId: 1 - - }, - "pedestrian": { - color: '#74BAF5', - index: 4, - nextTrackId: 1 - }, - // nuscenes - classNameArray: ["human.pedestrian.adult", - "human.pedestrian.child", - "human.pedestrian.wheelchair", - "human.pedestrian.stroller", - "human.pedestrian.personal_mobility", - "human.pedestrian.police_officer", - "human.pedestrian.construction_worker", - "animal", - "vehicle.car", - "vehicle.motorcycle", - "vehicle.bicycle", - "vehicle.bus.bendy", - "vehicle.bus.rigid", - "vehicle.truck", - "vehicle.construction", - "vehicle.emergency.ambulance", - "vehicle.emergency.police", - "vehicle.trailer", - "movable_object.barrier", - "movable_object.trafficcone", - "movable_object.pushable_pullable", - "movable_object.debris", - "static_object.bicycle_rack"], - // nuscenes - colorArray: ['#3ABB9D', '#4DA664', '#2F6CAD', '#4590B6', '#5CADCF', '#3585C5', '#2CA786', '#6ABB72', '#E66B5B', '#A28F85', - '#F79E3D', '#75706B', '#EE7841', '#D1D5D8', '#CC4846', '#DC5047', '#28324E', '#EFEFEF', '#485675', '#F2D46F', '#533D7F', - '#9069B5', '#F7C23E'], colorIdx: 0, - content: [], - addNuSceneLabel: function (label) { - if (this.content[label] === undefined) { - this.content[label] = {color: this.colorArray[this.colorIdx], index: this.colorIdx, nextTrackId: 1}; - this.colorIdx++; - } - }, - target: function () { - if (labelTool.showOriginalNuScenesLabels === true && labelTool.currentDataset === labelTool.datasets.NuScenes) { - return this.content[this.__target]; - } else { - return this[this.__target]; - } - + getCurrentAnnotationClassObject: function () { + return this[this.currentClass]; }, select: function (label) { - this.onChange(label); + this.onChangeAnnotationClass(label); if (annotationObjects.getSelectedBoundingBox() !== undefined) { annotationObjects.changeClass(annotationObjects.__selectionIndexCurrentFrame, label); @@ -85,22 +19,16 @@ let classesBoundingBox = { }; operationStack.push(changeClassOperation); } - - this.__target = label; this.currentClass = label; }, - onChange: function (label) { - this.__target = label; + onChangeAnnotationClass: function (currentClass) { + this.currentClass = currentClass; }, - color: function (label) { + getColorByClass: function (label) { return this[label].color; }, - targetName: function () { - return this.__target; - }, getCurrentClass: function () { return this.currentClass; }, - __target: "vehicle", - currentClass: "vehicle" + currentClass: "" }; \ No newline at end of file