You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1219 lines
30 KiB
JavaScript

import { vector4to3, vector3_nomalize, psr_to_xyz, matmul } from "./util.js";
import { globalObjectCategory } from "./obj_cfg.js";
import { MovableView } from "./popup_dialog.js";
function BoxImageContext(ui) {
this.ui = ui;
// draw highlighted box
this.updateFocusedImageContext = function (box) {
var scene_meta = box.world.frameInfo.sceneMeta;
let bestImage = choose_best_camera_for_point(scene_meta, box.position);
if (!bestImage) {
return;
}
if (!scene_meta.calib.camera) {
return;
}
var calib = scene_meta.calib.camera[bestImage];
if (!calib) {
return;
}
if (calib) {
var img = box.world.cameras.getImageByName(bestImage);
if (img && img.naturalWidth > 0) {
this.clear_canvas();
var imgfinal = box_to_2d_points(box, calib);
if (imgfinal != null) {
// if projection is out of range of the image, stop drawing.
var ctx = this.ui.getContext("2d");
ctx.lineWidth = 0.5;
// note: 320*240 should be adjustable
var crop_area = crop_image(
img.naturalWidth,
img.naturalHeight,
ctx.canvas.width,
ctx.canvas.height,
imgfinal
);
ctx.drawImage(
img,
crop_area[0],
crop_area[1],
crop_area[2],
crop_area[3],
0,
0,
ctx.canvas.width,
ctx.canvas.height
); // ctx.canvas.clientHeight);
//ctx.drawImage(img, 0,0,img.naturalWidth, img.naturalHeight, 0, 0, 320, 180);// ctx.canvas.clientHeight);
var imgfinal = vectorsub(imgfinal, [crop_area[0], crop_area[1]]);
var trans_ratio = {
x: ctx.canvas.height / crop_area[3],
y: ctx.canvas.height / crop_area[3],
};
draw_box_on_image(ctx, box, imgfinal, trans_ratio, true);
}
}
}
};
this.clear_canvas = function () {
var c = this.ui;
var ctx = c.getContext("2d");
ctx.clearRect(0, 0, c.width, c.height);
};
function vectorsub(vs, v) {
var ret = [];
var vl = v.length;
for (var i = 0; i < vs.length / vl; i++) {
for (var j = 0; j < vl; j++) ret[i * vl + j] = vs[i * vl + j] - v[j];
}
return ret;
}
function crop_image(imgWidth, imgHeight, clientWidth, clientHeight, corners) {
var maxx = 0,
maxy = 0,
minx = imgWidth,
miny = imgHeight;
for (var i = 0; i < corners.length / 2; i++) {
var x = corners[i * 2];
var y = corners[i * 2 + 1];
if (x > maxx) maxx = x;
else if (x < minx) minx = x;
if (y > maxy) maxy = y;
else if (y < miny) miny = y;
}
var targetWidth = (maxx - minx) * 1.5;
var targetHeight = (maxy - miny) * 1.5;
if (targetWidth / targetHeight > clientWidth / clientHeight) {
//increate height
targetHeight = (targetWidth * clientHeight) / clientWidth;
} else {
targetWidth = (targetHeight * clientWidth) / clientHeight;
}
var centerx = (maxx + minx) / 2;
var centery = (maxy + miny) / 2;
return [
centerx - targetWidth / 2,
centery - targetHeight / 2,
targetWidth,
targetHeight,
];
}
function draw_box_on_image(ctx, box, box_corners, trans_ratio, selected) {
var imgfinal = box_corners;
if (!selected) {
let target_color = null;
if (box.world.data.cfg.color_obj == "category") {
target_color = globalObjectCategory.get_color_by_category(box.obj_type);
} // by id
else {
let idx = box.obj_track_id
? parseInt(box.obj_track_id)
: box.obj_local_id;
target_color = globalObjectCategory.get_color_by_id(idx);
}
//ctx.strokeStyle = get_obj_cfg_by_type(box.obj_type).color;
//var c = get_obj_cfg_by_type(box.obj_type).color;
var r = "0x" + (target_color.x * 256).toString(16);
var g = "0x" + (target_color.y * 256).toString(16);
var b = "0x" + (target_color.z * 256).toString(16);
ctx.fillStyle =
"rgba(" + parseInt(r) + "," + parseInt(g) + "," + parseInt(b) + ",0.2)";
} else {
ctx.strokeStyle = "#ff00ff";
ctx.fillStyle = "rgba(255,0,255,0.2)";
}
// front panel
ctx.beginPath();
ctx.moveTo(
imgfinal[3 * 2] * trans_ratio.x,
imgfinal[3 * 2 + 1] * trans_ratio.y
);
for (var i = 0; i < imgfinal.length / 2 / 2; i++) {
ctx.lineTo(
imgfinal[i * 2 + 0] * trans_ratio.x,
imgfinal[i * 2 + 1] * trans_ratio.y
);
}
ctx.closePath();
ctx.fill();
// frame
ctx.beginPath();
ctx.moveTo(
imgfinal[3 * 2] * trans_ratio.x,
imgfinal[3 * 2 + 1] * trans_ratio.y
);
for (var i = 0; i < imgfinal.length / 2 / 2; i++) {
ctx.lineTo(
imgfinal[i * 2 + 0] * trans_ratio.x,
imgfinal[i * 2 + 1] * trans_ratio.y
);
}
//ctx.stroke();
//ctx.strokeStyle="#ff00ff";
//ctx.beginPath();
ctx.moveTo(
imgfinal[7 * 2] * trans_ratio.x,
imgfinal[7 * 2 + 1] * trans_ratio.y
);
for (var i = 4; i < imgfinal.length / 2; i++) {
ctx.lineTo(
imgfinal[i * 2 + 0] * trans_ratio.x,
imgfinal[i * 2 + 1] * trans_ratio.y
);
}
ctx.moveTo(
imgfinal[0 * 2] * trans_ratio.x,
imgfinal[0 * 2 + 1] * trans_ratio.y
);
ctx.lineTo(
imgfinal[4 * 2 + 0] * trans_ratio.x,
imgfinal[4 * 2 + 1] * trans_ratio.y
);
ctx.moveTo(
imgfinal[1 * 2] * trans_ratio.x,
imgfinal[1 * 2 + 1] * trans_ratio.y
);
ctx.lineTo(
imgfinal[5 * 2 + 0] * trans_ratio.x,
imgfinal[5 * 2 + 1] * trans_ratio.y
);
ctx.moveTo(
imgfinal[2 * 2] * trans_ratio.x,
imgfinal[2 * 2 + 1] * trans_ratio.y
);
ctx.lineTo(
imgfinal[6 * 2 + 0] * trans_ratio.x,
imgfinal[6 * 2 + 1] * trans_ratio.y
);
ctx.moveTo(
imgfinal[3 * 2] * trans_ratio.x,
imgfinal[3 * 2 + 1] * trans_ratio.y
);
ctx.lineTo(
imgfinal[7 * 2 + 0] * trans_ratio.x,
imgfinal[7 * 2 + 1] * trans_ratio.y
);
ctx.stroke();
}
}
class ImageContext extends MovableView {
constructor(parentUi, name, autoSwitch, cfg, on_img_click) {
// create ui
let template = document.getElementById("image-wrapper-template");
let tool = template.content.cloneNode(true);
// this.boxEditorHeaderUi.appendChild(tool);
// return this.boxEditorHeaderUi.lastElementChild;
parentUi.appendChild(tool);
let ui = parentUi.lastElementChild;
let handle = ui.querySelector("#move-handle");
super(handle, ui);
this.ui = ui;
this.cfg = cfg;
this.on_img_click = on_img_click;
this.autoSwitch = autoSwitch;
this.setImageName(name);
}
remove() {
this.ui.remove();
}
setImageName(name) {
this.name = name;
this.ui.querySelector("#header").innerText =
(this.autoSwitch ? "auto-" : "") + name;
}
get_selected_box = null;
init_image_op(func_get_selected_box) {
this.ui.onclick = (e) => this.on_click(e);
this.get_selected_box = func_get_selected_box;
// var h = parentUi.querySelector("#resize-handle");
// h.onmousedown = resize_mouse_down;
// c.onresize = on_resize;
}
clear_main_canvas() {
var boxes = this.ui.querySelector("#svg-boxes").children;
if (boxes.length > 0) {
for (var c = boxes.length - 1; c >= 0; c--) {
boxes[c].remove();
}
}
var points = this.ui.querySelector("#svg-points").children;
if (points.length > 0) {
for (var c = points.length - 1; c >= 0; c--) {
points[c].remove();
}
}
}
world = null;
img = null;
attachWorld(world) {
this.world = world;
}
hide() {
this.ui.style.display = "none";
}
hidden() {
this.ui.style.display == "none";
}
show() {
this.ui.style.display = "";
}
drawing = false;
points = [];
polyline;
all_lines = [];
img_lidar_point_map = {};
point_color_by_distance(x, y) {
// x,y are image coordinates
let p = this.img_lidar_point_map[y * this.img.width + x];
let distance = Math.sqrt(p[1] * p[1] + p[2] * p[2] + p[3] * p[3]);
if (distance > 60.0) distance = 60.0;
else if (distance < 10.0) distance = 10.0;
return [(distance - 10) / 50.0, 1 - (distance - 10) / 50.0, 0]
.map((c) => {
let hex = Math.floor(c * 255).toString(16);
if (hex.length == 1) hex = "0" + hex;
return hex;
})
.reduce((a, b) => a + b, "#");
}
to_polyline_attr(points) {
return points.reduce(function (x, y) {
return String(x) + "," + y;
});
}
to_viewbox_coord(x, y) {
var div = this.ui.querySelector("#maincanvas-svg");
x = Math.round((x * 2048) / div.clientWidth);
y = Math.round((y * 1536) / div.clientHeight);
return [x, y];
}
on_click(e) {
var p = this.to_viewbox_coord(e.layerX, e.layerY);
var x = p[0];
var y = p[1];
console.log("clicked", x, y);
if (!this.drawing) {
if (e.ctrlKey) {
this.drawing = true;
var svg = this.ui.querySelector("#maincanvas-svg");
//svg.style.position = "absolute";
this.polyline = document.createElementNS(
"http://www.w3.org/2000/svg",
"polyline"
);
svg.appendChild(this.polyline);
this.points.push(x);
this.points.push(y);
this.polyline.setAttribute("class", "maincanvas-line");
this.polyline.setAttribute(
"points",
this.to_polyline_attr(this.points)
);
var c = this.ui;
c.onmousemove = on_move;
c.ondblclick = on_dblclick;
c.onkeydown = on_key;
} else {
// not drawing
//this is a test
if (false) {
let nearest_x = 100000;
let nearest_y = 100000;
let selected_pts = [];
for (let i = x - 100; i < x + 100; i++) {
if (i < 0 || i >= this.img.width) continue;
for (let j = y - 100; j < y + 100; j++) {
if (j < 0 || j >= this.img.height) continue;
let lidarpoint = this.img_lidar_point_map[j * this.img.width + i];
if (lidarpoint) {
//console.log(i,j, lidarpoint);
selected_pts.push(lidarpoint); //index of lidar point
if (
(i - x) * (i - x) + (j - y) * (j - y) <
(nearest_x - x) * (nearest_x - x) +
(nearest_y - y) * (nearest_y - y)
) {
nearest_x = i;
nearest_y = j;
}
}
}
}
console.log("nearest", nearest_x, nearest_y);
this.draw_point(nearest_x, nearest_y);
if (nearest_x < 100000) {
this.on_img_click([
this.img_lidar_point_map[
nearest_y * this.img.width + nearest_x
][0],
]);
}
}
}
} else {
if (
this.points[this.points.length - 2] != x ||
this.points[this.points.length - 1] != y
) {
this.points.push(x);
this.points.push(y);
this.polyline.setAttribute(
"points",
this.to_polyline_attr(this.points)
);
}
}
function on_move(e) {
var p = to_viewbox_coord(e.layerX, e.layerY);
var x = p[0];
var y = p[1];
console.log(x, y);
this.polyline.setAttribute(
"points",
this.to_polyline_attr(this.points) + "," + x + "," + y
);
}
function on_dblclick(e) {
this.points.push(this.points[0]);
this.points.push(this.points[1]);
this.polyline.setAttribute("points", this.to_polyline_attr(this.points));
console.log(this.points);
all_lines.push(this.points);
this.drawing = false;
this.points = [];
var c = this.ui;
c.onmousemove = null;
c.ondblclick = null;
c.onkeypress = null;
c.blur();
}
function cancel() {
polyline.remove();
this.drawing = false;
this.points = [];
var c = this.ui;
c.onmousemove = null;
c.ondblclick = null;
c.onkeypress = null;
c.blur();
}
function on_key(e) {
if (e.key == "Escape") {
cancel();
}
}
}
// all boxes
getCalib() {
var scene_meta = this.world.sceneMeta;
if (!scene_meta.calib.camera) {
return null;
}
//var active_camera_name = this.world.cameras.active_name;
var calib = scene_meta.calib.camera[this.name];
return calib;
}
get_trans_ratio() {
var img = this.world.cameras.getImageByName(this.name);
if (!img || img.width == 0) {
return null;
}
var clientWidth, clientHeight;
clientWidth = 2048;
clientHeight = 1536;
var trans_ratio = {
x: clientWidth / img.naturalWidth,
y: clientHeight / img.naturalHeight,
};
return trans_ratio;
}
show_image() {
var svgimage = this.ui.querySelector("#svg-image");
// active img is set by global, it's not set sometimes.
var img = this.world.cameras.getImageByName(this.name);
if (img) {
svgimage.setAttribute("xlink:href", img.src);
}
this.img = img;
}
points_to_svg(points, trans_ratio, cssclass, radius = 2) {
var ptsFinal = points.map(function (x, i) {
if (i % 2 == 0) {
return Math.round(x * trans_ratio.x);
} else {
return Math.round(x * trans_ratio.y);
}
});
var svg = document.createElementNS("http://www.w3.org/2000/svg", "g");
if (cssclass) {
svg.setAttribute("class", cssclass);
}
for (let i = 0; i < ptsFinal.length; i += 2) {
let x = ptsFinal[i];
let y = ptsFinal[i + 1];
let p = document.createElementNS("http://www.w3.org/2000/svg", "circle");
p.setAttribute("cx", x);
p.setAttribute("cy", y);
p.setAttribute("r", 2);
p.setAttribute("stroke-width", "1");
if (!cssclass) {
let image_x = points[i];
let image_y = points[i + 1];
let color = point_color_by_distance(image_x, image_y);
color += "24"; //transparency
p.setAttribute("stroke", color);
p.setAttribute("fill", color);
}
svg.appendChild(p);
}
return svg;
}
draw_point(x, y) {
let trans_ratio = this.get_trans_ratio();
let svg = this.ui.querySelector("#svg-points");
let pts_svg = this.points_to_svg([x, y], trans_ratio, "radar-points");
svg.appendChild(pts_svg);
}
render_2d_image() {
if (this.cfg.disableMainImageContext) return;
this.clear_main_canvas();
this.show_image();
this.draw_svg();
}
hide_canvas() {
//document.getElementsByClassName("ui-wrapper")[0].style.display="none";
this.ui.style.display = "none";
}
show_canvas() {
this.ui.style.display = "inline";
}
draw_svg() {
// draw picture
var img = this.world.cameras.getImageByName(this.name);
if (!img || img.width == 0) {
this.hide_canvas();
return;
}
this.show_canvas();
var trans_ratio = this.get_trans_ratio();
var calib = this.getCalib();
if (!calib) {
return;
}
let svg = this.ui.querySelector("#svg-boxes");
// draw boxes
this.world.annotation.boxes.forEach((box) => {
var imgfinal = box_to_2d_points(box, calib);
if (imgfinal) {
var box_svg = this.box_to_svg(
box,
imgfinal,
trans_ratio,
this.get_selected_box() == box
);
svg.appendChild(box_svg);
}
});
svg = this.ui.querySelector("#svg-points");
// draw radar points
if (this.cfg.projectRadarToImage) {
this.world.radars.radarList.forEach((radar) => {
let pts = radar.get_unoffset_radar_points();
let ptsOnImg = points3d_to_image2d(pts, calib);
// there may be none after projecting
if (ptsOnImg && ptsOnImg.length > 0) {
let pts_svg = this.points_to_svg(
ptsOnImg,
trans_ratio,
radar.cssStyleSelector
);
svg.appendChild(pts_svg);
}
});
}
// project lidar points onto camera image
if (this.cfg.projectLidarToImage) {
let pts = this.world.lidar.get_all_points();
let ptsOnImg = points3d_to_image2d(
pts,
calib,
true,
this.img_lidar_point_map,
img.width,
img.height
);
// there may be none after projecting
if (ptsOnImg && ptsOnImg.length > 0) {
let pts_svg = this.points_to_svg(ptsOnImg, trans_ratio);
svg.appendChild(pts_svg);
}
}
}
box_to_svg(box, box_corners, trans_ratio, selected) {
var imgfinal = box_corners.map(function (x, i) {
if (i % 2 == 0) {
return Math.round(x * trans_ratio.x);
} else {
return Math.round(x * trans_ratio.y);
}
});
var svg = document.createElementNS("http://www.w3.org/2000/svg", "g");
svg.setAttribute("id", "svg-box-local-" + box.obj_local_id);
if (selected) {
svg.setAttribute("class", box.obj_type + " box-svg box-svg-selected");
} else {
if (box.world.data.cfg.color_obj == "id") {
svg.setAttribute("class", "color-" + (box.obj_track_id % 33));
} // by id
else {
svg.setAttribute("class", box.obj_type + " box-svg");
}
}
var front_panel = document.createElementNS(
"http://www.w3.org/2000/svg",
"polygon"
);
svg.appendChild(front_panel);
front_panel.setAttribute(
"points",
imgfinal.slice(0, 4 * 2).reduce(function (x, y) {
return String(x) + "," + y;
})
);
/*
var back_panel = document.createElementNS("http://www.w3.org/2000/svg", 'polygon');
svg.appendChild(back_panel);
back_panel.setAttribute("points",
imgfinal.slice(4*2).reduce(function(x,y){
return String(x)+","+y;
})
)
*/
for (var i = 0; i < 4; ++i) {
var line = document.createElementNS("http://www.w3.org/2000/svg", "line");
svg.appendChild(line);
line.setAttribute("x1", imgfinal[(4 + i) * 2]);
line.setAttribute("y1", imgfinal[(4 + i) * 2 + 1]);
line.setAttribute("x2", imgfinal[(4 + ((i + 1) % 4)) * 2]);
line.setAttribute("y2", imgfinal[(4 + ((i + 1) % 4)) * 2 + 1]);
}
for (var i = 0; i < 4; ++i) {
var line = document.createElementNS("http://www.w3.org/2000/svg", "line");
svg.appendChild(line);
line.setAttribute("x1", imgfinal[i * 2]);
line.setAttribute("y1", imgfinal[i * 2 + 1]);
line.setAttribute("x2", imgfinal[(i + 4) * 2]);
line.setAttribute("y2", imgfinal[(i + 4) * 2 + 1]);
}
return svg;
}
boxes_manager = {
display_image: () => {
if (!this.cfg.disableMainImageContext) this.render_2d_image();
},
add_box: (box) => {
var calib = this.getCalib();
if (!calib) {
return;
}
var trans_ratio = this.get_trans_ratio();
if (trans_ratio) {
var imgfinal = box_to_2d_points(box, calib);
if (imgfinal) {
var imgfinal = imgfinal.map(function (x, i) {
if (i % 2 == 0) {
return Math.round(x * trans_ratio.x);
} else {
return Math.round(x * trans_ratio.y);
}
});
var svg_box = this.box_to_svg(box, imgfinal, trans_ratio);
var svg = this.ui.querySelector("#svg-boxes");
svg.appendChild(svg_box);
}
}
},
onBoxSelected: (box_obj_local_id, obj_type) => {
var b = this.ui.querySelector("#svg-box-local-" + box_obj_local_id);
if (b) {
b.setAttribute("class", "box-svg-selected");
}
},
onBoxUnselected: (box_obj_local_id, obj_type) => {
var b = this.ui.querySelector("#svg-box-local-" + box_obj_local_id);
if (b) b.setAttribute("class", obj_type);
},
remove_box: (box_obj_local_id) => {
var b = this.ui.querySelector("#svg-box-local-" + box_obj_local_id);
if (b) b.remove();
},
update_obj_type: (box_obj_local_id, obj_type) => {
this.onBoxSelected(box_obj_local_id, obj_type);
},
update_box: (box) => {
var b = this.ui.querySelector("#svg-box-local-" + box.obj_local_id);
if (!b) {
return;
}
var children = b.childNodes;
var calib = this.getCalib();
if (!calib) {
return;
}
var trans_ratio = this.get_trans_ratio();
var imgfinal = box_to_2d_points(box, calib);
if (!imgfinal) {
//box may go out of image
return;
}
var imgfinal = imgfinal.map(function (x, i) {
if (i % 2 == 0) {
return Math.round(x * trans_ratio.x);
} else {
return Math.round(x * trans_ratio.y);
}
});
if (imgfinal) {
var front_panel = children[0];
front_panel.setAttribute(
"points",
imgfinal.slice(0, 4 * 2).reduce(function (x, y) {
return String(x) + "," + y;
})
);
for (var i = 0; i < 4; ++i) {
var line = children[1 + i];
line.setAttribute("x1", imgfinal[(4 + i) * 2]);
line.setAttribute("y1", imgfinal[(4 + i) * 2 + 1]);
line.setAttribute("x2", imgfinal[(4 + ((i + 1) % 4)) * 2]);
line.setAttribute("y2", imgfinal[(4 + ((i + 1) % 4)) * 2 + 1]);
}
for (var i = 0; i < 4; ++i) {
var line = children[5 + i];
line.setAttribute("x1", imgfinal[i * 2]);
line.setAttribute("y1", imgfinal[i * 2 + 1]);
line.setAttribute("x2", imgfinal[(i + 4) * 2]);
line.setAttribute("y2", imgfinal[(i + 4) * 2 + 1]);
}
}
},
};
}
class ImageContextManager {
constructor(parentUi, selectorUi, cfg, on_img_click) {
this.parentUi = parentUi;
this.selectorUi = selectorUi;
this.cfg = cfg;
this.on_img_click = on_img_click;
this.addImage("", true);
this.selectorUi.onmouseenter = function (event) {
if (this.timerId) {
clearTimeout(this.timerId);
this.timerId = null;
}
event.target.querySelector("#camera-list").style.display = "";
};
this.selectorUi.onmouseleave = function (event) {
let ui = event.target.querySelector("#camera-list");
this.timerId = setTimeout(() => {
ui.style.display = "none";
this.timerId = null;
}, 200);
};
this.selectorUi.querySelector("#camera-list").onclick = (event) => {
let cameraName = event.target.innerText;
if (cameraName == "auto") {
let existed = this.images.find((x) => x.autoSwitch);
if (existed) {
this.removeImage(existed);
} else {
this.addImage("", true);
}
} else {
let existed = this.images.find(
(x) => !x.autoSwitch && x.name == cameraName
);
if (existed) {
this.removeImage(existed);
} else {
this.addImage(cameraName);
}
}
};
}
updateCameraList(cameras) {
let autoCamera =
'<div class="camera-item" id="camera-item-auto">auto</div>';
if (this.images.find((i) => i.autoSwitch)) {
autoCamera =
'<div class="camera-item camera-selected" id="camera-item-auto">auto</div>';
}
let camera_selector_str = cameras
.map((c) => {
let existed = this.images.find((i) => i.name == c && !i.autoSwitch);
let className = existed ? "camera-item camera-selected" : "camera-item";
return `<div class="${className}" id="camera-item-${c}">${c}</div>`;
})
.reduce((x, y) => x + y, autoCamera);
let ui = this.selectorUi.querySelector("#camera-list");
ui.innerHTML = camera_selector_str;
ui.style.display = "none";
this.setDefaultBestCamera(cameras[0]);
}
setDefaultBestCamera(c) {
if (!this.bestCamera) {
let existed = this.images.find((x) => x.autoSwitch);
if (existed) {
existed.setImageName(c);
}
this.bestCamera = c;
}
}
images = [];
addImage(name, autoSwitch) {
if (autoSwitch && this.bestCamera && !name) name = this.bestCamera;
let image = new ImageContext(
this.parentUi,
name,
autoSwitch,
this.cfg,
this.on_img_click
);
this.images.push(image);
if (this.init_image_op_para) {
image.init_image_op(this.init_image_op_para);
}
if (this.world) {
image.attachWorld(this.world);
image.render_2d_image();
}
let selectorName = autoSwitch ? "auto" : name;
let ui = this.selectorUi.querySelector("#camera-item-" + selectorName);
if (ui) ui.className = "camera-item camera-selected";
return image;
}
removeImage(image) {
let selectorName = image.autoSwitch ? "auto" : image.name;
this.selectorUi.querySelector("#camera-item-" + selectorName).className =
"camera-item";
this.images = this.images.filter((x) => x != image);
image.remove();
}
setBestCamera(camera) {
this.images
.filter((i) => i.autoSwitch)
.forEach((i) => {
i.setImageName(camera);
i.boxes_manager.display_image();
});
this.bestCamera = camera;
}
render_2d_image() {
this.images.forEach((i) => i.render_2d_image());
}
attachWorld(world) {
this.world = world;
this.images.forEach((i) => i.attachWorld(world));
}
hide() {
this.images.forEach((i) => i.hide());
}
show() {
this.images.forEach((i) => i.show());
}
clear_main_canvas() {
this.images.forEach((i) => i.clear_main_canvas());
}
init_image_op(op) {
this.init_image_op_para = op;
this.images.forEach((i) => i.init_image_op(op));
}
hidden() {
return false;
}
choose_best_camera_for_point = choose_best_camera_for_point;
self = this;
boxes_manager = {
display_image: () => {
if (!this.cfg.disableMainImageContext) this.render_2d_image();
},
add_box: (box) => {
this.images.forEach((i) => i.boxes_manager.add_box(box));
},
onBoxSelected: (box_obj_local_id, obj_type) => {
this.images.forEach((i) =>
i.boxes_manager.onBoxSelected(box_obj_local_id, obj_type)
);
},
onBoxUnselected: (box_obj_local_id, obj_type) => {
this.images.forEach((i) =>
i.boxes_manager.onBoxUnselected(box_obj_local_id, obj_type)
);
},
remove_box: (box_obj_local_id) => {
this.images.forEach((i) => i.boxes_manager.remove_box(box_obj_local_id));
},
update_obj_type: (box_obj_local_id, obj_type) => {
this.images.forEach((i) =>
i.boxes_manager.update_obj_type(box_obj_local_id, obj_type)
);
},
update_box: (box) => {
this.images.forEach((i) => i.boxes_manager.update_box(box));
},
};
}
function box_to_2d_points(box, calib) {
var scale = box.scale;
var pos = box.position;
var rotation = box.rotation;
var box3d = psr_to_xyz(pos, scale, rotation);
//console.log(box.obj_track_id, box3d.slice(8*4));
box3d = box3d.slice(0, 8 * 4);
return points3d_homo_to_image2d(box3d, calib);
}
// points3d is length 4 row vector, homogeneous coordinates
// returns 2d row vectors
function points3d_homo_to_image2d(
points3d,
calib,
accept_partial = false,
save_map,
img_dx,
img_dy
) {
var imgpos = matmul(calib.extrinsic, points3d, 4);
//rect matrix shall be applied here, for kitti
if (calib.rect) {
imgpos = matmul(calib.rect, imgpos, 4);
}
var imgpos3 = vector4to3(imgpos);
var imgpos2;
if (calib.intrinsic.length > 9) {
imgpos2 = matmul(calib.intrinsic, imgpos, 4);
} else imgpos2 = matmul(calib.intrinsic, imgpos3, 3);
let imgfinal = vector3_nomalize(imgpos2);
let imgfinal_filterd = [];
if (accept_partial) {
let temppos = [];
let p = imgpos3;
for (var i = 0; i < p.length / 3; i++) {
if (p[i * 3 + 2] > 0) {
let x = imgfinal[i * 2];
let y = imgfinal[i * 2 + 1];
x = Math.round(x);
y = Math.round(y);
if (x > 0 && x < img_dx && y > 0 && y < img_dy) {
if (save_map) {
save_map[img_dx * y + x] = [
i,
points3d[i * 4 + 0],
points3d[i * 4 + 1],
points3d[i * 4 + 2],
]; //save index? a little dangerous! //[points3d[i*4+0], points3d[i*4+1], points3d[i*4+2]];
}
imgfinal_filterd.push(x);
imgfinal_filterd.push(y);
} else {
// console.log("points outside of image",x,y);
}
}
}
imgfinal = imgfinal_filterd;
//warning: what if calib.intrinsic.length
//todo: this function need clearance
//imgpos2 = matmul(calib.intrinsic, temppos, 3);
} else if (!accept_partial && !all_points_in_image_range(imgpos3)) {
return null;
}
return imgfinal;
}
function point3d_to_homo(points) {
let homo = [];
for (let i = 0; i < points.length; i += 3) {
homo.push(points[i]);
homo.push(points[i + 1]);
homo.push(points[i + 2]);
homo.push(1);
}
return homo;
}
function points3d_to_image2d(
points,
calib,
accept_partial = false,
save_map,
img_dx,
img_dy
) {
//
return points3d_homo_to_image2d(
point3d_to_homo(points),
calib,
accept_partial,
save_map,
img_dx,
img_dy
);
}
function all_points_in_image_range(p) {
for (var i = 0; i < p.length / 3; i++) {
if (p[i * 3 + 2] < 0) {
return false;
}
}
return true;
}
function choose_best_camera_for_point(scene_meta, center) {
if (!scene_meta.calib) {
return null;
}
var proj_pos = [];
for (var i in scene_meta.calib.camera) {
var imgpos = matmul(
scene_meta.calib.camera[i].extrinsic,
[center.x, center.y, center.z, 1],
4
);
proj_pos.push({ calib: i, pos: vector4to3(imgpos) });
}
var valid_proj_pos = proj_pos.filter(function (p) {
return all_points_in_image_range(p.pos);
});
valid_proj_pos.forEach(function (p) {
p.dist_to_center = p.pos[0] * p.pos[0] + p.pos[1] * p.pos[1];
});
valid_proj_pos.sort(function (x, y) {
return x.dist_to_center - y.dist_to_center;
});
//console.log(valid_proj_pos);
if (valid_proj_pos.length > 0) {
return valid_proj_pos[0].calib;
}
return null;
}
export { ImageContextManager, BoxImageContext };