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;
this.cursor = v.clone();
for (var i = 0; i < this.geometry.vertices.length; i++) {
var p = this.geometry.vertices[i];