未验证 提交 538bc937 编写于 作者: M manasars 提交者: GitHub

CVAT 3D - Milestone-4 (#2891)

* CVAT 3D Annotation - Added initial cuboid placement in all views

* Fixed MACOS issue for upload of zip files

* Fixed camera axis centre issue

* Fixed ESLint import issues

* Fixed context image fit issue and resizing possible on entire grey line between views

* Fixed the multiple interection point issue

* Fixed Naming convention as per SOW

* Trigger notification

* Reverted code to test cypress tests

* Fixed review comments

* Included tooltip and added actions for keys and UIOJKL buttons

* Merged dev code, updated changelog and minor fixes

* Fixed camera positioning issue in Top View

* Reverted kubernetes auto-corrected code

* Reverted kubernetes code

Co-authored-by: cdp <cdp123>
上级 4f7b1f91
......@@ -25,6 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [VGGFace2](https://github.com/ox-vgg/vgg_face2) format support (<https://github.com/openvinotoolkit/cvat/pull/2865>)
- [Backup/Restore guide](cvat/apps/documentation/backup_guide.md) (<https://github.com/openvinotoolkit/cvat/pull/2964>)
- Label deletion from tasks and projects (<https://github.com/openvinotoolkit/cvat/pull/2881>)
- CVAT-3D: Implemented initial cuboid placement in 3D View and select cuboid in Top, Side and Front views
(<https://github.com/openvinotoolkit/cvat/pull/2891>)
- [Market-1501](https://www.aitribune.com/dataset/2018051063) format support (<https://github.com/openvinotoolkit/cvat/pull/2869>)
- Annotations filters UI using react-awesome-query-builder (https://github.com/openvinotoolkit/cvat/issues/1418)
......
......@@ -1184,6 +1184,11 @@
"integrity": "sha512-aX+gFgA5GHcDi89KG5keey2zf0WfZk/HAQotEamsK2kbey+8yGKcson0hbK8E+v0NArlCJQCqMP161YhV6ZXLg==",
"dev": true
},
"@types/three": {
"version": "0.125.3",
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.125.3.tgz",
"integrity": "sha512-tUPMzKooKDvMOhqcNVUPwkt+JNnF8ASgWSsrLgleVd0SjLj4boJhteSsF9f6YDjye0mmUjO+BDMWW83F97ehXA=="
},
"@typescript-eslint/eslint-plugin": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.13.0.tgz",
......
......@@ -38,7 +38,8 @@
"webpack-dev-server": "^3.11.0"
},
"dependencies": {
"three": "^0.125.0",
"camera-controls": "^1.25.3"
"@types/three": "^0.125.3",
"camera-controls": "^1.25.3",
"three": "^0.125.0"
}
}
......@@ -4,8 +4,12 @@
import pjson from '../../package.json';
import { Canvas3dController, Canvas3dControllerImpl } from './canvas3dController';
import { Canvas3dModel, Canvas3dModelImpl, Mode } from './canvas3dModel';
import { Canvas3dView, Canvas3dViewImpl, ViewsDOM } from './canvas3dView';
import {
Canvas3dModel, Canvas3dModelImpl, Mode, DrawData, ViewType, MouseInteraction,
} from './canvas3dModel';
import {
Canvas3dView, Canvas3dViewImpl, ViewsDOM, CAMERA_ACTION,
} from './canvas3dView';
import { Master } from './master';
const Canvas3dVersion = pjson.version;
......@@ -17,6 +21,9 @@ interface Canvas3d {
mode(): Mode;
render(): void;
keyControls(keys: KeyboardEvent): void;
mouseControls(type: string, event: MouseEvent): void;
draw(drawData: DrawData): void;
cancel(): void;
}
class Canvas3dImpl implements Canvas3d {
......@@ -38,10 +45,18 @@ class Canvas3dImpl implements Canvas3d {
this.view.keyControls(keys);
}
public mouseControls(type: MouseInteraction, event: MouseEvent): void {
this.view.mouseControls(type, event);
}
public render(): void {
this.view.render();
}
public draw(drawData: DrawData): void {
this.model.draw(drawData);
}
public setup(frameData: any): void {
this.model.setup(frameData);
}
......@@ -53,6 +68,12 @@ class Canvas3dImpl implements Canvas3d {
public isAbleToChangeFrame(): boolean {
return this.model.isAbleToChangeFrame();
}
public cancel(): void {
this.model.cancel();
}
}
export { Canvas3dImpl as Canvas3d, Canvas3dVersion };
export {
Canvas3dImpl as Canvas3d, Canvas3dVersion, ViewType, MouseInteraction, CAMERA_ACTION,
};
......@@ -2,9 +2,10 @@
//
// SPDX-License-Identifier: MIT
import { Canvas3dModel, Mode } from './canvas3dModel';
import { Canvas3dModel, Mode, DrawData } from './canvas3dModel';
export interface Canvas3dController {
readonly drawData: DrawData;
mode: Mode;
}
......@@ -22,4 +23,8 @@ export class Canvas3dControllerImpl implements Canvas3dController {
public get mode(): Mode {
return this.model.mode;
}
public get drawData(): DrawData {
return this.model.data.drawData;
}
}
......@@ -26,6 +26,19 @@ export enum FrameZoom {
MAX = 10,
}
export enum ViewType {
PERSPECTIVE = 'perspective',
TOP = 'top',
SIDE = 'side',
FRONT = 'front',
}
export enum MouseInteraction {
CLICK = 'click',
DOUBLE_CLICK = 'dblclick',
HOVER = 'hover',
}
export enum UpdateReasons {
IMAGE_CHANGED = 'image_changed',
OBJECTS_UPDATED = 'objects_updated',
......@@ -61,6 +74,8 @@ export interface Canvas3dModel {
data: Canvas3dDataModel;
setup(frameData: any): void;
isAbleToChangeFrame(): boolean;
draw(drawData: DrawData): void;
cancel(): void;
}
export class Canvas3dModelImpl extends MasterImpl implements Canvas3dModel {
......@@ -133,4 +148,18 @@ export class Canvas3dModelImpl extends MasterImpl implements Canvas3dModel {
return !isUnable;
}
public draw(drawData: DrawData): void {
if (drawData.enabled && this.data.drawData.enabled) {
throw new Error('Drawing has been already started');
}
this.data.drawData.enabled = drawData.enabled;
this.data.mode = Mode.DRAW;
this.notify(UpdateReasons.DRAW);
}
public cancel(): void {
this.notify(UpdateReasons.CANCEL);
}
}
......@@ -4,20 +4,23 @@
import * as THREE from 'three';
import { PCDLoader } from 'three/examples/jsm/loaders/PCDLoader';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import CameraControls from 'camera-controls';
import { Canvas3dController } from './canvas3dController';
import { Listener, Master } from './master';
import CONST from './consts';
import { Canvas3dModel, UpdateReasons, Mode } from './canvas3dModel';
import {
Canvas3dModel, UpdateReasons, Mode, DrawData, ViewType, MouseInteraction,
} from './canvas3dModel';
import { CuboidModel } from './cuboid';
export interface Canvas3dView {
html(): ViewsDOM;
render(): void;
keyControls(keys: KeyboardEvent): void;
mouseControls(type: MouseInteraction, event: MouseEvent): void;
}
enum CAMERA_ACTION {
export enum CAMERA_ACTION {
ZOOM_IN = 'KeyI',
MOVE_UP = 'KeyU',
MOVE_DOWN = 'KeyO',
......@@ -30,6 +33,11 @@ enum CAMERA_ACTION {
ROTATE_LEFT = 'ArrowLeft',
}
export interface RayCast {
renderer: THREE.Raycaster;
mouseVector: THREE.Vector2;
}
export interface Views {
perspective: RenderView;
top: RenderView;
......@@ -37,11 +45,19 @@ export interface Views {
front: RenderView;
}
export interface CubeObject {
perspective: THREE.Mesh;
top: THREE.Mesh;
side: THREE.Mesh;
front: THREE.Mesh;
}
export interface RenderView {
renderer: THREE.WebGLRenderer;
scene: THREE.Scene;
camera?: THREE.PerspectiveCamera | THREE.OrthographicCamera;
controls?: CameraControls | OrbitControls;
controls?: CameraControls;
rayCaster?: RayCast;
}
export interface ViewsDOM {
......@@ -56,6 +72,9 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
private views: Views;
private clock: THREE.Clock;
private speed: number;
private cube: CuboidModel;
private highlighted: boolean;
private selected: CubeObject;
private set mode(value: Mode) {
this.controller.mode = value;
......@@ -69,10 +88,18 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
this.controller = controller;
this.clock = new THREE.Clock();
this.speed = CONST.MOVEMENT_FACTOR;
this.cube = new CuboidModel();
this.highlighted = false;
this.selected = this.cube;
this.views = {
perspective: {
renderer: new THREE.WebGLRenderer({ antialias: true }),
scene: new THREE.Scene(),
rayCaster: {
renderer: new THREE.Raycaster(),
mouseVector: new THREE.Vector2(),
},
},
top: {
renderer: new THREE.WebGLRenderer({ antialias: true }),
......@@ -139,13 +166,13 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
this.views.front.camera.up.set(0, 0, 1);
this.views.front.camera.lookAt(0, 0, 0);
Object.keys(this.views).forEach((view: string) => {
Object.keys(this.views).forEach((view: string): void => {
const viewType = this.views[view as keyof Views];
viewType.renderer.setSize(width, height);
if (view !== 'perspective') {
viewType.controls = new OrbitControls(viewType.camera, viewType.renderer.domElement);
viewType.controls.enableRotate = false;
viewType.controls.enablePan = false;
if (view !== ViewType.PERSPECTIVE) {
viewType.controls = new CameraControls(viewType.camera, viewType.renderer.domElement);
viewType.controls.mouseButtons.left = CameraControls.ACTION.NONE;
viewType.controls.mouseButtons.right = CameraControls.ACTION.NONE;
} else {
viewType.controls = new CameraControls(viewType.camera, viewType.renderer.domElement);
}
......@@ -165,94 +192,235 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener {
URL.revokeObjectURL(objectURL);
const event: CustomEvent = new CustomEvent('canvas.setup');
this.views.perspective.renderer.domElement.dispatchEvent(event);
} else if (reason === UpdateReasons.DRAW) {
const data: DrawData = this.controller.drawData;
if (data.enabled && this.mode === Mode.IDLE) {
this.mode = Mode.DRAW;
this.cube = new CuboidModel();
} else if (this.mode !== Mode.IDLE) {
this.cube = new CuboidModel();
}
} else if (reason === UpdateReasons.CANCEL) {
if (this.mode === Mode.DRAW) {
this.controller.drawData.enabled = false;
Object.keys(this.views).forEach((view: string): void => {
this.views[view as keyof Views].scene.children[0].remove(this.cube[view as keyof Views]);
});
}
this.mode = Mode.IDLE;
const event: CustomEvent = new CustomEvent('canvas.canceled');
this.views.perspective.renderer.domElement.dispatchEvent(event);
}
}
private clearScene(): void {
for (let i = this.views.perspective.scene.children.length - 1; i >= 0; i--) {
this.views.perspective.scene.remove(this.views.perspective.scene.children[i]);
this.views.top.scene.remove(this.views.top.scene.children[i]);
this.views.side.scene.remove(this.views.side.scene.children[i]);
this.views.front.scene.remove(this.views.front.scene.children[i]);
}
Object.keys(this.views).forEach((view: string): void => {
this.views[view as keyof Views].scene.children = [];
});
}
private addScene(points: any): void {
// eslint-disable-next-line no-param-reassign
points.material.size = 0.03;
points.material.size = 0.08;
// eslint-disable-next-line no-param-reassign
points.material.color = new THREE.Color(0x0000ff);
const sphereCenter = points.geometry.boundingSphere.center;
const { radius } = points.geometry.boundingSphere;
const xRange = -radius / 2 < this.views.perspective.camera.position.x - sphereCenter.x
&& radius / 2 > this.views.perspective.camera.position.x - sphereCenter.x;
const yRange = -radius / 2 < this.views.perspective.camera.position.y - sphereCenter.y
&& radius / 2 > this.views.perspective.camera.position.y - sphereCenter.y;
const zRange = -radius / 2 < this.views.perspective.camera.position.z - sphereCenter.z
&& radius / 2 > this.views.perspective.camera.position.z - sphereCenter.z;
let newX = 0;
let newY = 0;
let newZ = 0;
if (!xRange) {
newX = sphereCenter.x;
}
if (!yRange) {
newY = sphereCenter.y;
}
if (!zRange) {
newZ = sphereCenter.z;
}
if (newX || newY || newZ) {
this.positionAllViews(newX, newY, newZ);
}
this.views.perspective.scene.add(points);
this.views.top.scene.add(points.clone());
this.views.side.scene.add(points.clone());
this.views.front.scene.add(points.clone());
}
private static resizeRendererToDisplaySize(view: RenderView): void {
const canvas = view.renderer.domElement;
private positionAllViews(x: number, y: number, z: number): void {
this.views.perspective.controls.setLookAt(x - 8, y - 8, z + 3, x, y, z, false);
this.views.top.controls.setLookAt(x, y, z + 8, x, y, z, false);
this.views.side.controls.setLookAt(x, y + 8, z, x, y, z, false);
this.views.front.controls.setLookAt(x + 8, y, z, x, y, z, false);
}
private static resizeRendererToDisplaySize(viewName: string, view: RenderView): void {
const { camera, renderer } = view;
const canvas = renderer.domElement;
const width = canvas.parentElement.clientWidth;
const height = canvas.parentElement.clientHeight;
const needResize = canvas.clientWidth !== width || canvas.clientHeight !== height;
if (needResize) {
if (!(view.camera instanceof THREE.OrthographicCamera)) {
// eslint-disable-next-line no-param-reassign
view.camera.aspect = width / height;
if (camera instanceof THREE.PerspectiveCamera) {
camera.aspect = width / height;
} else {
const topViewFactor = 0; // viewName === ViewType.TOP ? 2 : 0;
const viewSize = CONST.ZOOM_FACTOR;
const aspectRatio = width / height;
if (!(camera instanceof THREE.PerspectiveCamera)) {
camera.left = (-aspectRatio * viewSize) / 2 - topViewFactor;
camera.right = (aspectRatio * viewSize) / 2 + topViewFactor;
camera.top = viewSize / 2 + topViewFactor;
camera.bottom = -viewSize / 2 - topViewFactor;
}
camera.near = -10;
camera.far = 10;
}
view.camera.updateProjectionMatrix();
view.renderer.setSize(width, height);
view.camera.updateProjectionMatrix();
}
}
private renderRayCaster = (viewType: RenderView): void => {
viewType.rayCaster.renderer.setFromCamera(viewType.rayCaster.mouseVector, viewType.camera);
if (this.mode === Mode.DRAW) {
const intersects = this.views.perspective.rayCaster.renderer.intersectObjects(
this.views.perspective.scene.children,
false,
);
if (intersects.length > 0) {
this.views.perspective.scene.children[0].add(this.cube.perspective);
const newPoints = intersects[0].point;
this.cube.perspective.position.copy(newPoints);
}
} else if (this.mode === Mode.IDLE) {
const intersects = this.views.perspective.rayCaster.renderer.intersectObjects(
this.views.perspective.scene.children[0].children,
false,
);
if (intersects.length !== 0) {
this.views.perspective.scene.children[0].children.forEach((sceneItem: THREE.Mesh): void => {
if (this.selected.perspective !== sceneItem) {
// eslint-disable-next-line no-param-reassign
sceneItem.material.color = new THREE.Color(0xff0000);
}
});
const selectedObject = intersects[0].object as THREE.Mesh;
if (this.selected.perspective !== selectedObject) {
selectedObject.material.color = new THREE.Color(0xffff00);
this.highlighted = true;
}
} else {
if (this.highlighted) {
this.views.perspective.scene.children[0].children.forEach((sceneItem: THREE.Mesh): void => {
if (this.selected.perspective !== sceneItem) {
// eslint-disable-next-line no-param-reassign
sceneItem.material.color = new THREE.Color(0xff0000);
}
});
}
this.highlighted = false;
}
}
};
public render(): void {
Object.keys(this.views).forEach((view: string) => {
Object.keys(this.views).forEach((view: string): void => {
const viewType = this.views[view as keyof Views];
Canvas3dViewImpl.resizeRendererToDisplaySize(viewType);
Canvas3dViewImpl.resizeRendererToDisplaySize(view, viewType);
viewType.controls.update(this.clock.getDelta());
viewType.renderer.render(viewType.scene, viewType.camera);
if (view === ViewType.PERSPECTIVE && viewType.scene.children.length !== 0) {
this.renderRayCaster(viewType);
}
});
}
public keyControls(key: any): void {
if (!(this.views.perspective.controls instanceof OrbitControls)) {
const { controls } = this.views.perspective;
const { controls } = this.views.perspective;
switch (key.code) {
case CAMERA_ACTION.ROTATE_RIGHT:
controls.rotate(0.1 * THREE.MathUtils.DEG2RAD * this.speed, 0, true);
break;
case CAMERA_ACTION.ROTATE_LEFT:
controls.rotate(-0.1 * THREE.MathUtils.DEG2RAD * this.speed, 0, true);
break;
case CAMERA_ACTION.TILT_UP:
controls.rotate(0, -0.05 * THREE.MathUtils.DEG2RAD * this.speed, true);
break;
case CAMERA_ACTION.TILT_DOWN:
controls.rotate(0, 0.05 * THREE.MathUtils.DEG2RAD * this.speed, true);
break;
default:
break;
}
if (key.altKey === true) {
switch (key.code) {
case CAMERA_ACTION.ROTATE_RIGHT:
controls.rotate(0.1 * THREE.MathUtils.DEG2RAD * this.speed, 0, true);
case CAMERA_ACTION.ZOOM_IN:
controls.dolly(CONST.DOLLY_FACTOR, true);
break;
case CAMERA_ACTION.ZOOM_OUT:
controls.dolly(-CONST.DOLLY_FACTOR, true);
break;
case CAMERA_ACTION.MOVE_LEFT:
controls.truck(-0.01 * this.speed, 0, true);
break;
case CAMERA_ACTION.ROTATE_LEFT:
controls.rotate(-0.1 * THREE.MathUtils.DEG2RAD * this.speed, 0, true);
case CAMERA_ACTION.MOVE_RIGHT:
controls.truck(0.01 * this.speed, 0, true);
break;
case CAMERA_ACTION.TILT_UP:
controls.rotate(0, -0.05 * THREE.MathUtils.DEG2RAD * this.speed, true);
case CAMERA_ACTION.MOVE_DOWN:
controls.truck(0, -0.01 * this.speed, true);
break;
case CAMERA_ACTION.TILT_DOWN:
controls.rotate(0, 0.05 * THREE.MathUtils.DEG2RAD * this.speed, true);
case CAMERA_ACTION.MOVE_UP:
controls.truck(0, 0.01 * this.speed, true);
break;
default:
break;
}
if (key.altKey === true) {
switch (key.code) {
case CAMERA_ACTION.ZOOM_IN:
controls.dolly(CONST.DOLLY_FACTOR, true);
break;
case CAMERA_ACTION.ZOOM_OUT:
controls.dolly(-CONST.DOLLY_FACTOR, true);
break;
case CAMERA_ACTION.MOVE_LEFT:
controls.truck(-0.01 * this.speed, 0, true);
break;
case CAMERA_ACTION.MOVE_RIGHT:
controls.truck(0.01 * this.speed, 0, true);
break;
case CAMERA_ACTION.MOVE_DOWN:
controls.truck(0, -0.01 * this.speed, true);
break;
case CAMERA_ACTION.MOVE_UP:
controls.truck(0, 0.01 * this.speed, true);
break;
default:
break;
}
}
public mouseControls(type: MouseInteraction, event: MouseEvent): void {
event.preventDefault();
if (type === MouseInteraction.DOUBLE_CLICK && this.mode === Mode.DRAW) {
this.controller.drawData.enabled = false;
this.mode = Mode.IDLE;
const cancelEvent: CustomEvent = new CustomEvent('canvas.canceled');
this.views.perspective.renderer.domElement.dispatchEvent(cancelEvent);
} else {
const canvas = this.views.perspective.renderer.domElement;
const rect = canvas.getBoundingClientRect();
const { mouseVector } = this.views.perspective.rayCaster;
mouseVector.x = ((event.clientX - (canvas.offsetLeft + rect.left)) / canvas.clientWidth) * 2 - 1;
mouseVector.y = -((event.clientY - (canvas.offsetTop + rect.top)) / canvas.clientHeight) * 2 + 1;
if (type === MouseInteraction.CLICK && this.mode === Mode.IDLE) {
const intersects = this.views.perspective.rayCaster.renderer.intersectObjects(
this.views.perspective.scene.children[0].children,
false,
);
if (intersects.length !== 0) {
this.views.perspective.scene.children[0].children.forEach((sceneItem: THREE.Mesh): void => {
// eslint-disable-next-line no-param-reassign
sceneItem.material.color = new THREE.Color(0xff0000);
});
const selectedObject = intersects[0].object;
selectedObject.material.color = new THREE.Color(0x00ffff);
Object.keys(this.views).forEach((view: string): void => {
if (view !== ViewType.PERSPECTIVE) {
this.views[view as keyof Views].scene.children[0].children = [selectedObject.clone()];
this.views[view as keyof Views].controls.fitToBox(selectedObject, false);
this.views[view as keyof Views].controls.zoom(view === ViewType.TOP ? -5 : -5, false);
}
this.views[view as keyof Views].scene.background = new THREE.Color(0x000000);
});
this.selected.perspective = selectedObject as THREE.Mesh;
}
}
}
......
// Copyright (C) 2021 Intel Corporation
//
// SPDX-License-Identifier: MIT
import * as THREE from 'three';
export class CuboidModel {
public perspective: THREE.Mesh;
public top: THREE.Mesh;
public side: THREE.Mesh;
public front: THREE.Mesh;
public constructor() {
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true });
this.perspective = new THREE.Mesh(geometry, material);
this.top = new THREE.Mesh(geometry, material);
this.side = new THREE.Mesh(geometry, material);
this.front = new THREE.Mesh(geometry, material);
}
}
......@@ -1318,6 +1318,14 @@
"redux": "^4.0.0"
}
},
"@types/react-resizable": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/@types/react-resizable/-/react-resizable-1.7.2.tgz",
"integrity": "sha512-6c6L94+VOksr9838LDrlYeucic2+0qkGnwolGE77YJztYHCWSucQV0e9+Qyl+uHpJTBRS95A5JESBg5NgCAC3A==",
"requires": {
"@types/react": "*"
}
},
"@types/react-router": {
"version": "5.1.12",
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.12.tgz",
......@@ -12915,10 +12923,16 @@
"cvat-canvas3d": {
"version": "file:../cvat-canvas3d",
"requires": {
"@types/three": "^0.125.3",
"camera-controls": "^1.25.3",
"three": "^0.125.0"
},
"dependencies": {
"@types/three": {
"version": "0.125.3",
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.125.3.tgz",
"integrity": "sha512-tUPMzKooKDvMOhqcNVUPwkt+JNnF8ASgWSsrLgleVd0SjLj4boJhteSsF9f6YDjye0mmUjO+BDMWW83F97ehXA=="
},
"camera-controls": {
"version": "1.25.3",
"resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-1.25.3.tgz",
......@@ -28941,6 +28955,15 @@
"scheduler": "^0.19.1"
}
},
"react-draggable": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.3.tgz",
"integrity": "sha512-jV4TE59MBuWm7gb6Ns3Q1mxX8Azffb7oTtDtBgFkxRvhDp38YAARmRplrj0+XGkhOJB5XziArX+4HUUABtyZ0w==",
"requires": {
"classnames": "^2.2.5",
"prop-types": "^15.6.0"
}
},
"react-is": {
"version": "16.11.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.11.0.tgz",
......@@ -28986,6 +29009,15 @@
}
}
},
"react-resizable": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/react-resizable/-/react-resizable-1.11.0.tgz",
"integrity": "sha512-VoGz2ddxUFvildS8r8/29UZJeyiM3QJnlmRZSuXm+FpTqq/eIrMPc796Y9XQLg291n2hFZJtIoP1xC3hSTw/jg==",
"requires": {
"prop-types": "15.x",
"react-draggable": "^4.0.3"
}
},
"react-router": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.1.2.tgz",
......@@ -78,6 +78,8 @@
"react-cookie": "^4.0.3",
"react-dom": "^16.14.0",
"react-redux": "^7.2.2",
"react-resizable": "^1.11.0",
"@types/react-resizable": "^1.7.2",
"react-router": "^5.1.0",
"react-router-dom": "^5.1.0",
"react-share": "^3.0.1",
......
......@@ -2,14 +2,20 @@
//
// SPDX-License-Identifier: MIT
import React, { ReactElement, useEffect, useRef } from 'react';
import React, {
ReactElement, SyntheticEvent, useEffect, useReducer, useRef,
} from 'react';
import Layout from 'antd/lib/layout/layout';
import {
ArrowUpOutlined, ArrowRightOutlined, ArrowLeftOutlined, ArrowDownOutlined,
ArrowDownOutlined, ArrowLeftOutlined, ArrowRightOutlined, ArrowUpOutlined,
} from '@ant-design/icons';
import { ResizableBox } from 'react-resizable';
import { Workspace } from 'reducers/interfaces';
import { Canvas3d } from 'cvat-canvas3d-wrapper';
import {
CAMERA_ACTION, Canvas3d, MouseInteraction, ViewType,
} from 'cvat-canvas3d-wrapper';
import ContextImage from '../standard3D-workspace/context-image/context-image';
import CVATTooltip from '../../common/cvat-tooltip';
interface Props {
canvasInstance: Canvas3d;
......@@ -22,18 +28,96 @@ interface Props {
annotations: any[];
onSetupCanvas: () => void;
getContextImage(): void;
onResetCanvas(): void;
workspace: Workspace;
animateID: any;
automaticBordering: boolean;
showObjectsTextAlways: boolean;
}
interface ViewSize {
fullHeight: number;
vertical: number;
top: number;
side: number;
front: number;
}
function viewSizeReducer(
state: ViewSize,
action: { type: ViewType | 'set'; e?: SyntheticEvent; data?: ViewSize },
): ViewSize {
const event = (action.e as unknown) as MouseEvent;
const canvas3dContainer = document.getElementById('canvas3d-container');
if (canvas3dContainer) {
switch (action.type) {
case ViewType.TOP: {
const width = event.clientX - canvas3dContainer.getBoundingClientRect().left;
const topWidth = state.top;
if (topWidth < width) {
const top = state.top + (width - topWidth);
const side = state.side - (width - topWidth);
return {
...state,
top,
side,
};
}
const top = state.top - (topWidth - width);
const side = state.side + (topWidth - width);
return {
...state,
top,
side,
};
}
case ViewType.SIDE: {
const width = event.clientX - canvas3dContainer.getBoundingClientRect().left;
const topSideWidth = state.top + state.side;
if (topSideWidth < width) {
const side = state.side + (width - topSideWidth);
const front = state.front - (width - topSideWidth);
return {
...state,
side,
front,
};
}
const side = state.side - (topSideWidth - width);
const front = state.front + (topSideWidth - width);
return {
...state,
side,
front,
};
}
case ViewType.PERSPECTIVE:
return {
...state,
vertical: event.clientY - canvas3dContainer.getBoundingClientRect().top,
};
case 'set':
return action.data as ViewSize;
default:
throw new Error();
}
}
return state;
}
const CanvasWrapperComponent = (props: Props): ReactElement => {
const animateId = useRef(0);
const perspectiveView = useRef<HTMLCanvasElement>(null);
const topView = useRef<HTMLCanvasElement>(null);
const sideView = useRef<HTMLCanvasElement>(null);
const frontView = useRef<HTMLCanvasElement>(null);
const [viewSize, setViewSize] = useReducer(viewSizeReducer, {
fullHeight: 0,
vertical: 0,
top: 0,
side: 0,
front: 0,
});
const perspectiveView = useRef<HTMLDivElement | null>(null);
const topView = useRef<HTMLDivElement | null>(null);
const sideView = useRef<HTMLDivElement | null>(null);
const frontView = useRef<HTMLDivElement | null>(null);
const {
frameData, contextImageHide, getContextImage, loaded, data, annotations, curZLayer,
......@@ -59,12 +143,36 @@ const CanvasWrapperComponent = (props: Props): ReactElement => {
}
};
const onMouseClick = (event: MouseEvent): void => {
const { canvasInstance } = props;
canvasInstance.mouseControls(MouseInteraction.CLICK, event);
};
const onMouseDoubleClick = (event: MouseEvent): void => {
const { canvasInstance } = props;
canvasInstance.mouseControls(MouseInteraction.DOUBLE_CLICK, event);
};
const onMouseHover = (event: MouseEvent): void => {
const { canvasInstance } = props;
canvasInstance.mouseControls(MouseInteraction.HOVER, event);
};
const onCanvasCancel = (): void => {
const { onResetCanvas } = props;
onResetCanvas();
};
const initialSetup = (): void => {
const { canvasInstance } = props;
const canvasInstanceDOM = canvasInstance.html();
// Events
canvasInstanceDOM.perspective.addEventListener('canvas.setup', onCanvasSetup);
canvasInstanceDOM.perspective.addEventListener('mousemove', onMouseHover);
canvasInstanceDOM.perspective.addEventListener('canvas.canceled', onCanvasCancel);
canvasInstanceDOM.perspective.addEventListener(MouseInteraction.DOUBLE_CLICK, onMouseDoubleClick);
canvasInstanceDOM.perspective.addEventListener(MouseInteraction.CLICK, onMouseClick);
};
const keyControls = (key: KeyboardEvent): void => {
......@@ -91,6 +199,20 @@ const CanvasWrapperComponent = (props: Props): ReactElement => {
topView.current.appendChild(canvasInstanceDOM.top);
sideView.current.appendChild(canvasInstanceDOM.side);
frontView.current.appendChild(canvasInstanceDOM.front);
const canvas3dContainer = document.getElementById('canvas3d-container');
if (canvas3dContainer) {
const width = canvas3dContainer.clientWidth / 3;
setViewSize({
type: 'set',
data: {
fullHeight: canvas3dContainer.clientHeight,
vertical: canvas3dContainer.clientHeight / 2,
top: width,
side: width,
front: width,
},
});
}
}
document.addEventListener('keydown', keyControls);
......@@ -101,59 +223,128 @@ const CanvasWrapperComponent = (props: Props): ReactElement => {
return () => {
canvasInstanceDOM.perspective.removeEventListener('canvas.setup', onCanvasSetup);
canvasInstanceDOM.perspective.removeEventListener('mousemove', onMouseHover);
canvasInstanceDOM.perspective.removeEventListener('canvas.canceled', onCanvasCancel);
canvasInstanceDOM.perspective.removeEventListener(MouseInteraction.DOUBLE_CLICK, onMouseDoubleClick);
canvasInstanceDOM.perspective.removeEventListener(MouseInteraction.CLICK, onMouseClick);
document.removeEventListener('keydown', keyControls);
cancelAnimationFrame(animateId.current);
};
});
}, []);
useEffect(() => {
updateCanvas();
}, [frameData, annotations, curZLayer]);
const renderArrowGroup = (): ReactElement => (
const screenKeyControl = (code: CAMERA_ACTION): void => {
const { canvasInstance } = props;
canvasInstance.keyControls(new KeyboardEvent('keydown', { code, altKey: true }));
};
const ArrowGroup = (): ReactElement => (
<span className='cvat-canvas3d-perspective-arrow-directions'>
<button type='button' className='cvat-canvas3d-perspective-arrow-directions-icons-up'>
<ArrowUpOutlined className='cvat-canvas3d-perspective-arrow-directions-icons-color' />
</button>
<CVATTooltip title='Arrow Up' placement='topRight'>
<button
onClick={() => screenKeyControl(CAMERA_ACTION.TILT_UP)}
type='button'
className='cvat-canvas3d-perspective-arrow-directions-icons-up'
>
<ArrowUpOutlined className='cvat-canvas3d-perspective-arrow-directions-icons-color' />
</button>
</CVATTooltip>
<br />
<button type='button' className='cvat-canvas3d-perspective-arrow-directions-icons-bottom'>
<ArrowLeftOutlined className='cvat-canvas3d-perspective-arrow-directions-icons-color' />
</button>
<button type='button' className='cvat-canvas3d-perspective-arrow-directions-icons-bottom'>
<ArrowDownOutlined className='cvat-canvas3d-perspective-arrow-directions-icons-color' />
</button>
<button type='button' className='cvat-canvas3d-perspective-arrow-directions-icons-bottom'>
<ArrowRightOutlined className='cvat-canvas3d-perspective-arrow-directions-icons-color' />
</button>
<CVATTooltip title='Arrow Left' placement='topRight'>
<button
onClick={() => screenKeyControl(CAMERA_ACTION.ROTATE_LEFT)}
type='button'
className='cvat-canvas3d-perspective-arrow-directions-icons-bottom'
>
<ArrowLeftOutlined className='cvat-canvas3d-perspective-arrow-directions-icons-color' />
</button>
</CVATTooltip>
<CVATTooltip title='Arrow Bottom' placement='topRight'>
<button
onClick={() => screenKeyControl(CAMERA_ACTION.TILT_DOWN)}
type='button'
className='cvat-canvas3d-perspective-arrow-directions-icons-bottom'
>
<ArrowDownOutlined className='cvat-canvas3d-perspective-arrow-directions-icons-color' />
</button>
</CVATTooltip>
<CVATTooltip title='Arrow Right' placement='topRight'>
<button
onClick={() => screenKeyControl(CAMERA_ACTION.ROTATE_RIGHT)}
type='button'
className='cvat-canvas3d-perspective-arrow-directions-icons-bottom'
>
<ArrowRightOutlined className='cvat-canvas3d-perspective-arrow-directions-icons-color' />
</button>
</CVATTooltip>
</span>
);
const renderControlGroup = (): ReactElement => (
const ControlGroup = (): ReactElement => (
<span className='cvat-canvas3d-perspective-directions'>
<button type='button' className='cvat-canvas3d-perspective-directions-icon'>
U
</button>
<button type='button' className='cvat-canvas3d-perspective-directions-icon'>
I
</button>
<button type='button' className='cvat-canvas3d-perspective-directions-icon'>
O
</button>
<CVATTooltip title='Alt+U' placement='topLeft'>
<button
onClick={() => screenKeyControl(CAMERA_ACTION.MOVE_UP)}
type='button'
className='cvat-canvas3d-perspective-directions-icon'
>
U
</button>
</CVATTooltip>
<CVATTooltip title='Alt+I' placement='topLeft'>
<button
onClick={() => screenKeyControl(CAMERA_ACTION.ZOOM_IN)}
type='button'
className='cvat-canvas3d-perspective-directions-icon'
>
I
</button>
</CVATTooltip>
<CVATTooltip title='Alt+O' placement='topLeft'>
<button
onClick={() => screenKeyControl(CAMERA_ACTION.MOVE_DOWN)}
type='button'
className='cvat-canvas3d-perspective-directions-icon'
>
O
</button>
</CVATTooltip>
<br />
<button type='button' className='cvat-canvas3d-perspective-directions-icon'>
J
</button>
<button type='button' className='cvat-canvas3d-perspective-directions-icon'>
K
</button>
<button type='button' className='cvat-canvas3d-perspective-directions-icon'>
L
</button>
<CVATTooltip title='Alt+J' placement='topLeft'>
<button
onClick={() => screenKeyControl(CAMERA_ACTION.MOVE_LEFT)}
type='button'
className='cvat-canvas3d-perspective-directions-icon'
>
J
</button>
</CVATTooltip>
<CVATTooltip title='Alt+K' placement='topLeft'>
<button
onClick={() => screenKeyControl(CAMERA_ACTION.ZOOM_OUT)}
type='button'
className='cvat-canvas3d-perspective-directions-icon'
>
K
</button>
</CVATTooltip>
<CVATTooltip title='Alt+L' placement='topLeft'>
<button
onClick={() => screenKeyControl(CAMERA_ACTION.MOVE_RIGHT)}
type='button'
className='cvat-canvas3d-perspective-directions-icon'
>
L
</button>
</CVATTooltip>
</span>
);
return (
<Layout.Content className='cvat-canvas3d-fullsize'>
<Layout.Content className='cvat-canvas3d-fullsize' id='canvas3d-container'>
<ContextImage
frame={frameData}
contextImageHide={contextImageHide}
......@@ -161,26 +352,57 @@ const CanvasWrapperComponent = (props: Props): ReactElement => {
loaded={loaded}
data={data}
/>
<div className='cvat-canvas3d-perspective'>
<div className='cvat-canvas-container cvat-canvas-container-overflow' ref={perspectiveView} />
{renderArrowGroup()}
{renderControlGroup()}
</div>
<div className='cvat-canvas3d-orthographic-views'>
<div className='cvat-canvas3d-orthographic-view cvat-canvas3d-topview'>
<div className='cvat-canvas3d-header'>TOP VIEW</div>
<div className='cvat-canvas3d-fullsize' ref={topView} />
</div>
<div className='cvat-canvas3d-orthographic-view cvat-canvas3d-sideview'>
<div className='cvat-canvas3d-header'>SIDE VIEW</div>
<div className='cvat-canvas3d-fullsize' ref={sideView} />
<ResizableBox
className='cvat-resizable'
width={Infinity}
height={viewSize.vertical}
axis='y'
handle={<span className='cvat-resizable-handle-horizontal' />}
onResize={(e: SyntheticEvent) => setViewSize({ type: ViewType.PERSPECTIVE, e })}
>
<div className='cvat-canvas3d-perspective'>
<div className='cvat-canvas-container cvat-canvas-container-overflow' ref={perspectiveView} />
<ArrowGroup />
<ControlGroup />
</div>
<div className='cvat-canvas3d-orthographic-view cvat-canvas3d-frontview'>
<div className='cvat-canvas3d-header'>FRONT VIEW</div>
</ResizableBox>
<div
className='cvat-canvas3d-orthographic-views'
style={{ height: viewSize.fullHeight - viewSize.vertical }}
>
<ResizableBox
className='cvat-resizable'
width={viewSize.top}
height={viewSize.fullHeight - viewSize.vertical}
axis='x'
handle={<span className='cvat-resizable-handle-vertical-top' />}
onResize={(e: SyntheticEvent) => setViewSize({ type: ViewType.TOP, e })}
>
<div className='cvat-canvas3d-orthographic-view cvat-canvas3d-topview'>
<div className='cvat-canvas3d-header'>TOP</div>
<div className='cvat-canvas3d-fullsize' ref={topView} />
</div>
</ResizableBox>
<ResizableBox
className='cvat-resizable'
width={viewSize.side}
height={viewSize.fullHeight - viewSize.vertical}
axis='x'
handle={<span className='cvat-resizable-handle-vertical-side' />}
onResize={(e: SyntheticEvent) => setViewSize({ type: ViewType.SIDE, e })}
>
<div className='cvat-canvas3d-orthographic-view cvat-canvas3d-sideview'>
<div className='cvat-canvas3d-header'>SIDE</div>
<div className='cvat-canvas3d-fullsize' ref={sideView} />
</div>
</ResizableBox>
<div
className='cvat-canvas3d-orthographic-view cvat-canvas3d-frontview'
style={{ width: viewSize.front, height: viewSize.fullHeight - viewSize.vertical }}
>
<div className='cvat-canvas3d-header'>FRONT</div>
<div className='cvat-canvas3d-fullsize' ref={frontView} />
</div>
<div className='cvat-canvas3d-view-slider' />
</div>
</Layout.Content>
);
......
......@@ -8,14 +8,16 @@ import Button from 'antd/lib/button';
import InputNumber from 'antd/lib/input-number';
import Radio, { RadioChangeEvent } from 'antd/lib/radio';
import Text from 'antd/lib/typography/Text';
import { Canvas, RectDrawingMethod, CuboidDrawingMethod } from 'cvat-canvas-wrapper';
import { Canvas3d } from 'cvat-canvas3d-wrapper';
import { RectDrawingMethod, CuboidDrawingMethod } from 'cvat-canvas-wrapper';
import { ShapeType } from 'reducers/interfaces';
import { clamp } from 'utils/math';
import LabelSelector from 'components/label-selector/label-selector';
import CVATTooltip from 'components/common/cvat-tooltip';
interface Props {
canvasInstance: Canvas | Canvas3d;
shapeType: ShapeType;
labels: any[];
minimumPoints: number;
......@@ -48,8 +50,11 @@ function DrawShapePopoverComponent(props: Props): JSX.Element {
onChangePoints,
onChangeRectDrawingMethod,
onChangeCuboidDrawingMethod,
canvasInstance,
} = props;
const is2D = canvasInstance instanceof Canvas;
return (
<div className='cvat-draw-shape-popover-content'>
<Row justify='start'>
......@@ -72,7 +77,7 @@ function DrawShapePopoverComponent(props: Props): JSX.Element {
/>
</Col>
</Row>
{shapeType === ShapeType.RECTANGLE && (
{is2D && shapeType === ShapeType.RECTANGLE && (
<>
<Row>
<Col>
......@@ -97,7 +102,7 @@ function DrawShapePopoverComponent(props: Props): JSX.Element {
</Row>
</>
)}
{shapeType === ShapeType.CUBOID && (
{is2D && shapeType === ShapeType.CUBOID && (
<>
<Row>
<Col>
......@@ -122,7 +127,7 @@ function DrawShapePopoverComponent(props: Props): JSX.Element {
</Row>
</>
)}
{shapeType !== ShapeType.RECTANGLE && shapeType !== ShapeType.CUBOID && (
{is2D && shapeType !== ShapeType.RECTANGLE && shapeType !== ShapeType.CUBOID && (
<Row justify='space-around' align='middle'>
<Col span={14}>
<Text className='cvat-text-color'> Number of points: </Text>
......@@ -150,11 +155,13 @@ function DrawShapePopoverComponent(props: Props): JSX.Element {
<Button onClick={onDrawShape}>Shape</Button>
</CVATTooltip>
</Col>
<Col span={12}>
<CVATTooltip title={`Press ${repeatShapeShortcut} to draw again`}>
<Button onClick={onDrawTrack}>Track</Button>
</CVATTooltip>
</Col>
{is2D && (
<Col span={12}>
<CVATTooltip title={`Press ${repeatShapeShortcut} to draw again`}>
<Button onClick={onDrawTrack}>Track</Button>
</CVATTooltip>
</Col>
)}
</Row>
</div>
);
......
......@@ -4,15 +4,11 @@
import React from 'react';
import Layout from 'antd/lib/layout';
import { ActiveControl } from 'reducers/interfaces';
import { Canvas3d as Canvas } from 'cvat-canvas3d-wrapper';
import CursorControl from './cursor-control';
import MoveControl from './move-control';
import DrawCuboidControl from './draw-cuboid-control';
import PhotoContextControl from './photo-context';
interface Props {
......@@ -31,7 +27,6 @@ export default function ControlsSideBarComponent(props: Props): JSX.Element {
return (
<Layout.Sider className='cvat-canvas-controls-sidebar' theme='light' width={44}>
<MoveControl canvasInstance={canvasInstance} activeControl={activeControl} />
<CursorControl
cursorShortkey={normalizedKeyMap.CANCEL}
canvasInstance={canvasInstance}
......
......@@ -17,7 +17,7 @@ interface Props {
}
function CursorControl(props: Props): JSX.Element {
const { activeControl, cursorShortkey } = props;
const { activeControl, cursorShortkey, canvasInstance } = props;
return (
<CVATTooltip title={`Cursor ${cursorShortkey}`} placement='right'>
......@@ -27,6 +27,7 @@ function CursorControl(props: Props): JSX.Element {
'cvat-cursor-control',
activeControl === ActiveControl.CURSOR ? 'cvat-active-canvas-control ' : '',
].join(' ')}
onClick={activeControl !== ActiveControl.CURSOR ? (): void => canvasInstance.cancel() : undefined}
/>
</CVATTooltip>
);
......
......@@ -14,7 +14,6 @@
background: $border-color-3;
top: $grid-unit-size;
right: $grid-unit-size;
max-height: $grid-unit-size * 16;
z-index: 100;
border-radius: $grid-unit-size;
border: 1px solid $border-color-3;
......@@ -173,7 +172,7 @@
}
.cvat-canvas3d-perspective {
height: 50%;
height: 100%;
width: 100%;
position: relative;
padding: $grid-unit-size/2;
......@@ -219,7 +218,7 @@
}
.cvat-canvas3d-orthographic-view {
width: 33.333%;
width: 100%;
height: 100%;
padding-top: $grid-unit-size/2;
padding-bottom: $grid-unit-size/2;
......@@ -227,10 +226,10 @@
.cvat-canvas3d-topview {
padding-left: $grid-unit-size/2;
padding-right: $grid-unit-size/2;
}
.cvat-canvas3d-sideview {
padding-left: $grid-unit-size/2;
padding-right: $grid-unit-size/2;
}
......@@ -263,3 +262,44 @@
text-align: center;
vertical-align: middle;
}
.cvat-resizable {
position: relative;
}
.cvat-resizable-handle-horizontal {
position: absolute;
margin-left: auto;
width: 100%;
margin-right: auto;
right: 0;
bottom: 0;
left: 0;
background-color: grey;
height: $grid-unit-size/2;
cursor: ns-resize;
}
.cvat-resizable-handle-vertical-side {
position: absolute;
width: $grid-unit-size/2;
margin-right: auto;
top: $grid-unit-size * 4.5;
right: 0;
bottom: 0;
background-color: grey;
height: 100%;
cursor: ew-resize;
}
.cvat-resizable-handle-vertical-top {
position: absolute;
width: $grid-unit-size/2;
margin-right: auto;
top: $grid-unit-size * 4.5;
right: 0;
bottom: 0;
background-color: grey;
height: 100%;
cursor: ew-resize;
}
......@@ -5,7 +5,7 @@
import { connect } from 'react-redux';
import CanvasWrapperComponent from 'components/annotation-page/canvas/canvas-wrapper3D';
import { confirmCanvasReady, getContextImage } from 'actions/annotation-actions';
import { confirmCanvasReady, getContextImage, resetCanvas } from 'actions/annotation-actions';
import { CombinedState } from 'reducers/interfaces';
......@@ -25,6 +25,7 @@ interface StateToProps {
interface DispatchToProps {
onSetupCanvas(): void;
getContextImage(): void;
onResetCanvas(): void;
}
function mapStateToProps(state: CombinedState): StateToProps {
......@@ -63,6 +64,9 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
getContextImage(): void {
dispatch(getContextImage());
},
onResetCanvas(): void {
dispatch(resetCanvas());
},
};
}
......
......@@ -156,10 +156,13 @@ class DrawShapePopoverContainer extends React.PureComponent<Props, State> {
rectDrawingMethod, cuboidDrawingMethod, selectedLabelID, numberOfPoints,
} = this.state;
const { normalizedKeyMap, labels, shapeType } = this.props;
const {
normalizedKeyMap, labels, shapeType, canvasInstance,
} = this.props;
return (
<DrawShapePopoverComponent
canvasInstance={canvasInstance}
labels={labels}
shapeType={shapeType}
minimumPoints={this.minimumPoints}
......
......@@ -2,6 +2,14 @@
//
// SPDX-License-Identifier: MIT
import { Canvas3d, Canvas3dVersion } from 'cvat-canvas3d/src/typescript/canvas3d';
import {
Canvas3d,
Canvas3dVersion,
MouseInteraction,
ViewType,
CAMERA_ACTION,
} from 'cvat-canvas3d/src/typescript/canvas3d';
export { Canvas3d, Canvas3dVersion };
export {
Canvas3d, Canvas3dVersion, MouseInteraction, ViewType, CAMERA_ACTION,
};
......@@ -40,6 +40,12 @@ def delete_tmp_dir(tmp_dir):
if tmp_dir:
shutil.rmtree(tmp_dir)
def files_to_ignore(directory):
ignore_files = ('__MSOSX', '._.DS_Store', '__MACOSX', '.DS_Store')
if not any(ignore_file in directory for ignore_file in ignore_files):
return True
return False
class IMediaReader(ABC):
def __init__(self, source_path, step, start, stop):
self._source_path = sorted(source_path)
......@@ -186,7 +192,7 @@ class ZipReader(ImageListReader):
self._dimension = DimensionType.DIM_2D
self._zip_source = zipfile.ZipFile(source_path[0], mode='a')
self.extract_dir = source_path[1] if len(source_path) > 1 else None
file_list = [f for f in self._zip_source.namelist() if get_mime(f) == 'image']
file_list = [f for f in self._zip_source.namelist() if files_to_ignore(f) and get_mime(f) == 'image']
super().__init__(file_list, step, start, stop)
def __del__(self):
......@@ -675,7 +681,7 @@ class ValidateDimension:
def validate_pointcloud(self, *args):
root, actual_path, files = args
pointcloud_files = self.process_files(root, actual_path, files)
related_path = root.split("pointcloud")[0]
related_path = root.rsplit("/pointcloud", 1)[0]
related_images_path = os.path.join(related_path, "related_images")
if os.path.isdir(related_images_path):
......@@ -685,7 +691,7 @@ class ValidateDimension:
for k in pointcloud_files:
for path in paths:
if k == path.split("_")[0]:
if k == path.rsplit("_", 1)[0]:
file_path = os.path.abspath(os.path.join(related_images_path, path))
files = [file for file in os.listdir(file_path) if
os.path.isfile(os.path.join(file_path, file))]
......@@ -704,7 +710,7 @@ class ValidateDimension:
current_directory_name = os.path.split(root)
if len(pcd_files.keys()) == 1:
pcd_name = list(pcd_files.keys())[0].split(".")[0]
pcd_name = list(pcd_files.keys())[0].rsplit(".", 1)[0]
if current_directory_name[1] == pcd_name:
for related_image in self.image_files.values():
if root == os.path.split(related_image)[0]:
......@@ -718,6 +724,8 @@ class ValidateDimension:
return
actual_path = self.path
for root, _, files in os.walk(actual_path):
if not files_to_ignore(root):
continue
if root.endswith("data"):
if os.path.split(os.path.split(root)[0])[1] == "velodyne_points":
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册