Note: The default ITS GitLab runner is a shared resource and is subject to slowdowns during heavy usage.
You can run your own GitLab runner that is dedicated just to your group if you need to avoid processing delays.

Commit b55f6486 authored by bernie wang's avatar bernie wang
Browse files

integreted 3d-2d project by Virginia

parent 67a4bfbc
<!DOCTYPE html>
<html lang="en">
<head>
<title>LiDAR Annotator</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link href="http://maxcdn.bootstrapcdn.com/font-awesome/4.6.0/css/font-awesome.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="styles/style.css" rel="stylesheet">
</head>
<body>
<nav class="tools">
<ul id="tools">
<!-- Commented out file input and export for evaluation -->
<li>
<input type="file" id="file_input" class="inputfile" multiple>
</li>
<!-- <li><a href="#" id="save"><i class="fa fa-floppy-o"></i></a></li> -->
<li><a href="#" id="next_frame"><i class="fas fa-caret-square-right">Next Frame</i></a></li>
<li><a href="#" class="selected" id="move"><i class="fa material-icons">3d_rotation</i></a></li>
<li><a href="#" id="move2D"><i class="fa fa-pencil"></i></a></li>
<!-- <li><a href="#" id="ids"><i class="fa fa-pencil"></i></a></li> -->
<li>
<button type='button' id='record' style="display: none;">Click to start recording</button>
<li>
<div>
<table id="object-table">
<thead>
<tr style="display:block;" >
<td>Object IDs</td>
<td></td>
</tr>
</thead>
<tbody style="overflow-y: scroll; height:12em; display:block;">
</tbody>
</table>
</div>
</li>
</ul>
</nav>
<div id="container"></div>
<div id="info">LiDAR Annotator</div>
<div id="draw_bounding_box_reminder"><p></p></div>
<div id="footer"><p></p></div>
<script src="js/libs/three.min.js"></script>
<script src="js/libs/OrbitControls.js"></script>
<script src="js/libs/Detector.js"></script>
<script src="js/libs/stats.min.js"></script>
<script src="js/libs/FileSaver.min.js"></script>
<script src="js/libs/dat.gui.min.js"></script>
<script src="js/box.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="js/utils.js"></script>
<script src="js/ObjectTable.js"></script>
<script src="js/Box.js?nocache"></script>
<script src="js/Evaluation.js?nocache"></script>
<script src="js/Evaluator.js?nocache"></script>
<script src="js/main.js?nocache"></script>
</body>
</html>
\ No newline at end of file
var maxSize = 2;
var SettingsControls = function() {
this.size = pointSize / maxSize;
};
var gui = new dat.GUI();
var settingsControls = new SettingsControls();
var settingsFolder = gui.addFolder('settings');
settingsFolder.add(settingsControls, 'size').min(0.0).max(1.0).step(0.05).onChange(function() {
pointcloud.material.size = settingsControls.size * maxSize;
pointMaterial.size = 4 * settingsControls.size * maxSize;
});
settingsFolder.open();
function next_frame(event) {
if (evaluation.is_done()) {
alert("You have completed the evaluation! Thank you for participating!");
evaluation.add_evaluator(evaluator);
evaluation.write_output();
return;
}
var response = confirm('Do you want to move on to the next frame? You cannot go back to edit previous frames.');
if (response == true) {
$("#next_frame").text("Next Frame (" + (evaluation.get_frame_number() + 1) +
"/" + evaluation.num_frames() + ")");
evaluation.add_evaluator(evaluator);
evaluation.next_frame();
reset();
data = evaluation.get_data();
show();
animate();
if (isRecording) {
toggleRecord(event);
}
select2DMode();
}
}
function toggleRecord(event) {
// pause recording
if (isRecording) {
$("#record").text("Click to resume recording");
evaluator.pause_recording();
move2DMode(event);
isRecording = false;
} else {
// resume recording
isRecording = true;
$("#record").text("Click to pause recording");
evaluator.resume_recording();
}
}
// controller for pressing hotkeys
function onKeyDown(event) {
if (isRecording) {
if (event.ctrlKey) {
toggleControl(false);
}
var KeyID = event.keyCode;
switch(KeyID)
{
case 8: // backspace
deleteSelectedBox();
break;
case 46: // delete
deleteSelectedBox();
break;
case 68:
default:
break;
}
}
}
// controller for releasing hotkeys
function onKeyUp(event) {
if(isRecording) {
var KeyID = event.keyCode;
switch(KeyID)
{
default:
toggleControl(true);
break;
}
}
}
// toggles between move2D and move3D
function toggleControl(b) {
if (b) {
controls.enabled = b;
controls.update();
} else {
if (move2D) {
controls.enabled = b;
controls.update();
}
}
}
\ No newline at end of file
function Evaluation() {
// this.test_filenames = [
// "0000000001.bin",
// "0000000013.bin",
// "0000000022.bin",
// "0000000049.bin",
// "0000000128.bin",
// "0000000003.bin",
// "0000000019.bin",
// "0000000023.bin",
// "0000000060.bin",
// "0000000133.bin"
// ];
this.test_data = [];
this.filenames = [];
this.index = 0;
this.evaluators = [];
this.get_filename = function() {
return this.filenames[this.index];
}
this.get_data = function() {
return this.test_data[this.index];
}
this.next_frame = function() {
this.index += 1;
}
this.is_done = function() {
return this.index == this.filenames.length - 1;
}
this.add_data = function(data) {
this.test_data.push(data);
}
this.add_filename = function(filename) {
this.filenames.push(filename);
}
this.get_frame_number = function() {
return this.index + 1;
}
this.num_frames = function() {
return this.test_data.length;
}
this.add_evaluator = function(evaluator) {
this.evaluators.push(evaluator);
}
this.write_output = function() {
// output_bounding_boxes = save(this.)
var output_evaluators = [];
for (var i = 0; i < this.evaluators.length; i++) {
// output_evaluators[this.filenames[i]] = this.evaluators[i].output();
console.log(this.evaluators[i].output());
output_evaluators.push(this.evaluators[i].output());
}
var output = {"frames": output_evaluators};
var stringifiedOutput = JSON.stringify(output);
var file = new File([stringifiedOutput], "test.json", {type: "/json;charset=utf-8"});
saveAs(file);
}
}
function Evaluator(angle, bounding_boxes, filename) {
this.add_box_count = 0;
this.resize_count = 0;
this.translate_count = 0;
this.rotate_count = 0;
this.delete_count = 0;
this.label_count = 0;
this.rotate_camera_count = 0;
this._3D_timer = new Timer();
this.timer = new Timer();
this.bounding_boxes = bounding_boxes;
this.filename = filename;
this.camera_angle = angle;
this.increment_add_box_count = function() {
this.add_box_count += 1;
};
this.increment_resize_count = function() {
this.resize_count += 1;
};
this.increment_translate_count = function() {
this.translate_count += 1;
};
this.increment_rotate_count = function() {
this.rotate_count += 1;
};
this.increment_delete_count = function() {
this.delete_count += 1;
};
this.increment_label_count = function() {
this.label_count += 1;
};
this.increment_rotate_camera_count = function(angle) {
if (angle != this.camera_angle) {
this.rotate_camera_count += 1;
}
this.camera_angle = angle;
}
this.resume_3D_time = function() {
this._3D_timer.resume();
}
this.pause_3D_time = function() {
this._3D_timer.pause();
}
this.get_3D_time_elapsed = function() {
return this._3D_timer.get_time_elapsed();
}
this.resume_time = function() {
this.timer.resume();
}
this.pause_time = function() {
this.timer.pause();
}
this.get_time_elapsed = function() {
return this.timer.get_time_elapsed();
}
this.pause_recording = function() {
this.pause_time();
if (!move2D) {
this.pause_3D_time();
}
}
this.resume_recording = function() {
this.resume_time();
if (!move2D) {
this.resume_3D_time();
}
}
this.output = function() {
return new OutputEvaluator(this);
}
}
function OutputEvaluator(eval) {
this.add_box_count = eval.add_box_count;
this.resize_count = eval.resize_count;
this.translate_count = eval.translate_count;
this.rotate_count = eval.rotate_count;
this.delete_count = eval.delete_count;
this.label_count = eval.label_count;
this.rotate_camera_count = eval.rotate_camera_count;
this.filename = eval.filename;
this.bounding_boxes = [];
this.time_elapsed = eval.get_time_elapsed();
this._3D_time_elapsed = eval.get_3D_time_elapsed();
for (var i = 0; i < eval.bounding_boxes.length; i++) {
this.bounding_boxes.push(eval.bounding_boxes[i].output());
}
this.camera_angle = eval.camera_angle;
}
function Timer() {
this.time_elapsed = 0;
this.date = new Date();
this.running = false;
this.resume = function() {
this.date = new Date();
this.running = true;
}
this.pause = function() {
current_time = new Date();
this.time_elapsed += current_time.getTime() - this.date.getTime();
this.state = current_time;
this.running = false;
}
this.get_time_elapsed = function() {
if (this.running) {
this.pause();
this.resume();
}
return this.time_elapsed / 1000;
}
}
\ No newline at end of file
var options = `<select>
<option value="car">Car</option>
<option value="van">Van</option>
<option value="truck">Truck</option>
<option value="pedestrian">Pedestrian</option>
<option value="cyclist">Cyclist</option>
<option value="sitter">Sitter</option>
<option value="tram">Tram</option>
<option value="misc">Misc</option>
/select`;
// method to add row to object id table
function addRow(box) {
$("#object-table tbody").append("<tr><td class='id'>" + box.id + "</td><td>" + options + "</td></tr>");
$("#object-table tbody select").last().focus();
}
// handler that highlights input and corresponding bounding box when input is selected
$("#object-table").on('mousedown', 'tbody tr', function() {
isMoving = false;
var boxId = $(this).find('.id').text();
var box = getBoxById(boxId);
selectRow(boxId);
box.select(null);
selectedBox = box;
var center = box.get_center();
var current_angle = camera.rotation.z;
console.log("current angle:", current_angle);
controls.target.set(center.x, 0, center.y);
// controls.target.set(0, 0, 0);
camera.updateProjectionMatrix();
controls.update();
controls.update();
camera.rotation.z = current_angle;
console.log("camera rotation: ", camera.rotation.z);
// camera.lookAt(new THREE.Vector3(center.x,0,center.y));
// controls.update();
});
// handler that saves input when input is changed
$("#object-table").on('change', 'tbody tr', updateObjectId);
// method to update Box's object id
function updateObjectId() {
var boxId = $(this).find(".id").text();
var input = $(this).find('select').val();
var box = getBoxById(boxId);
box.object_id = input;
evaluator.increment_label_count();
}
// method to get object id table row given id
function getRow(id) {
var row = $("#object-table tbody").find('td').filter(function() {
return $(this).text() == id.toString();}).closest("tr");
return row;
}
// method to select row of object id table given ids
function selectRow(id) {
var row = getRow(id);
$(row).find('select').get(0).focus();
}
// gets box given its id
function getBoxById(id) {
for (var i = 0; i < boundingBoxes.length; i++) {
if (boundingBoxes[i].id == id) {
return boundingBoxes[i];
}
}
}
\ No newline at end of file
function Box(anchor, cursor, angle, boundingBox, boxHelper) {
this.id = id; // id (int) of Box
this.object_id = 'car'; // object id (string)
this.color = hover_color.clone(); // color of corner points
this.angle = angle; // orientation of bounding box
this.anchor = anchor; // point where bounding box was created
this.cursor = cursor.clone(); // cursor
this.added = false; // (boolean) whether the box has been added to boundingboxes
this.boundingBox = boundingBox; // Box3; sets the size of the box
this.boxHelper = boxHelper; // BoxHelper; helps visualize the box
this.geometry = new THREE.Geometry(); // geometry for corner/rotating points
// visualizes the corners (in the non-rotated coordinates) of the box
this.points = new THREE.Points( this.geometry, pointMaterial );
this.points.frustumCulled = false; // allows
this.colors = []; // colors of the corner points
// add colors to points geometry
for (var i = 0; i < 6; i++) {
this.colors.push( this.color.clone().multiplyScalar( 7 ) );
}
this.geometry.colors = this.colors;
// order of corners is max, min, topleft, bottomright
this.geometry.vertices.push(anchor);
this.geometry.vertices.push(cursor);
this.geometry.vertices.push(anchor.clone());
this.geometry.vertices.push(cursor.clone());
this.geometry.vertices.push(getCenter(anchor.clone(), cursor.clone()));
this.get_center = function() {
var center3D = getCenter(this.geometry.vertices[0], this.geometry.vertices[1]);
return new THREE.Vector2(center3D.x, center3D.z);
}
// method for resizing bounding box given cursor coordinates
//
// since BoxHelper3 draws a box in the same orientation as that of the point cloud,
// we take the anchor and cursor, rotate them by the angle of the camera, draw the box,
// then rotate the box back
this.resize = function(cursor) {
// checks and executes only if anchor does not overlap with cursor to avoid 0 determinant
if (cursor.x != this.anchor.x && cursor.y != this.anchor.y && cursor.z != this.anchor.z) {
var v1 = cursor.clone();
var v2 = this.anchor.clone();
v1.y = 0;
v2.y = 0;
// rotate cursor and anchor
rotate(v1, v2, this.angle);
// calculating corner points and rotating point
var minVector = getMin(v1, v2);
var maxVector = getMax(v1, v2);
var topLeft = getTopLeft(v1, v2);
var bottomRight = getBottomRight(v1, v2);
var topCenter = getCenter(topLeft, maxVector);
var bottomCenter = getCenter(minVector, bottomRight);
// need to do this to make matrix invertible
maxVector.y = 0.00001;
// setting bounding box limits
this.boundingBox.set(minVector.clone(), maxVector.clone());
// rotate BoxHelper back
this.boxHelper.rotation.y = this.angle;
// setting y coordinate back to zero since we are done with drawing
maxVector.y = 0;
// rotate back the corner points
rotate(minVector, maxVector, -this.angle);
rotate(topLeft, bottomRight, -this.angle);
rotate(topCenter, bottomCenter, -this.angle);
// set updated corner points used to resize box
this.geometry.vertices[0] = maxVector.clone();
this.geometry.vertices[1] = minVector.clone();
this.geometry.vertices[2] = topLeft.clone();
this.geometry.vertices[3] = bottomRight.clone();
this.geometry.vertices[4] = bottomCenter.clone();
// tell scene to update corner points
this.geometry.verticesNeedUpdate = true;
}
}
// method to rotate bounding box by clicking and dragging rotate point,
// which is the top center point on the bounding box
this.rotate = function(cursor) {
// get corner points
var maxVector = this.geometry.vertices[0].clone();
var minVector = this.geometry.vertices[1].clone();
var topLeft = this.geometry.vertices[2].clone();
var bottomRight = this.geometry.vertices[3].clone();
var topCenter = getCenter(maxVector, topLeft);
var bottomCenter = this.geometry.vertices[4].clone();
// get relative angle of cursor with respect to
var center = getCenter(maxVector, minVector);
var angle = getAngle(center, bottomCenter, cursor, topCenter);
// update angle of Box and bounding box
this.angle = this.angle + angle;
this.boxHelper.rotation.y = this.angle;
// rotate and update corner points
rotate(minVector, maxVector, -angle);
rotate(topLeft, bottomRight, -angle);
rotate(topCenter, bottomCenter, -angle);
this.geometry.vertices[0] = maxVector.clone();
this.geometry.vertices[1] = minVector.clone();
this.geometry.vertices[2] = topLeft.clone();
this.geometry.vertices[3] = bottomRight.clone();
this.geometry.vertices[4] = bottomCenter.clone();
// tell scene to update corner points
this.geometry.verticesNeedUpdate = true;
}
// method to translate bounding box given a reference point
this.translate = function(v) {
// get difference in x and z coordinates between cursor when
// box was selected and current cursor position
var dx = v.x - this.cursor.x;
var dz = v.z - this.cursor.z;
// update all points related to box by dx and dz
this.anchor.x += dx;
this.anchor.z += dz;