Skip to content

Commit c4b7fb8

Browse files
authored
Merge pull request #10 from sovrasov/vs/3d_geometry
Add 3d geometry utils
2 parents 33823a5 + cf9ee3f commit c4b7fb8

File tree

16 files changed

+244
-22
lines changed

16 files changed

+244
-22
lines changed

.github/workflows/main.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ jobs:
1414
python-version: [3.7]
1515

1616
steps:
17-
- uses: actions/checkout@v2
17+
- name: Checkout repository and submodules
18+
uses: actions/checkout@v2
19+
with:
20+
submodules: recursive
1821
- name: Set up Python ${{ matrix.python-version }}
1922
uses: actions/setup-python@v2
2023
with:
@@ -33,6 +36,12 @@ jobs:
3336
run: |
3437
python -m pip install --upgrade pip pytest pylint
3538
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
39+
- name: Install torchdet3d
40+
run: |
41+
python setup.py develop
42+
- name: Testing with pytest
43+
run: |
44+
python -m pytest . -s
3645
- name: Linting with pylint
3746
run: |
3847
python tests/run_pylint.py

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Training includes the following stages:
77
- Training a 2d bounding box detection model
88
- Training a 3d bounding box regression model
99

10-
Trained models can be deployed on CPU using [OpenVINO](https://docs.openvinotoolkit.org) framework and then run in [live demo]().
10+
Trained models can be deployed on CPU using [OpenVINO](https://docs.openvinotoolkit.org) framework and then run in [live demo](demo/demo.py).
1111

1212
## Installation guide
1313
```bash

annotation_converters/objectron_2_coco.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ def save_2_coco(output_root, subset_name, data_info, obj_classes, fps_divisor,
8787
ann_folder = osp.join(output_root, 'annotations')
8888
img_folder = osp.join(output_root, 'images')
8989
if not osp.isdir(ann_folder):
90-
os.mkdir(ann_folder)
90+
os.makedirs(ann_folder, exist_ok=True)
9191
if not osp.isdir(img_folder):
92-
os.mkdir(img_folder)
92+
os.makedirs(img_folder, exist_ok=True)
9393

9494
img_id = 0
9595
ann_id = 0
@@ -142,8 +142,9 @@ def save_2_coco(output_root, subset_name, data_info, obj_classes, fps_divisor,
142142
frames[frame_idx] = cv.resize(frames[frame_idx], (w, h))
143143
for kp_pixel in keypoints[0]:
144144
cv.circle(frames[frame_idx], (kp_pixel[0], kp_pixel[1]), 5, (255, 0, 0), -1)
145-
for kp_pixel in keypoints[1]:
146-
cv.circle(frames[frame_idx], (kp_pixel[0], kp_pixel[1]), 5, (0, 0, 255), -1)
145+
if len(keypoints) > 1:
146+
for kp_pixel in keypoints[1]:
147+
cv.circle(frames[frame_idx], (kp_pixel[0], kp_pixel[1]), 5, (0, 0, 255), -1)
147148
for bbox in bboxes:
148149
if bbox is not None:
149150
cv.rectangle(frames[frame_idx], (bbox[0], bbox[1]),

annotation_converters/objectron_helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def grab_frames(video_file, frame_ids, use_opencv=True):
9191
'-pix_fmt', 'rgb24', '-vcodec', 'rawvideo', '-vsync', 'vfr', '-'
9292
]
9393
pipe = subprocess.Popen(
94-
command, stdout=subprocess.PIPE, bufsize=151 * frame_size)
94+
command, stdout=subprocess.PIPE, bufsize=151 * frame_size, stderr=subprocess.DEVNULL)
9595
current_frame = np.frombuffer(
9696
pipe.stdout.read(frame_size), dtype='uint8').reshape(height, width, 3)
9797
pipe.stdout.flush()

demo/demo_tools.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ def load_ie_model(ie, model_xml, device, plugin_dir, cpu_extension='', num_reqs=
5454
log.info("Loading network")
5555
net = ie.read_network(model_xml, os.path.splitext(model_xml)[0] + ".bin")
5656

57-
assert len(net.input_info) == 1 or len(net.input_info) == 2, \
57+
assert len(net.input_info) in [1, 2], \
5858
"Supports topologies with only 1 or 2 inputs"
59-
assert len(net.outputs) == 1 or len(net.outputs) == 4 or len(net.outputs) == 5, \
60-
"Supports topologies with only 1, 4 or 5 outputs"
59+
assert len(net.outputs) in [1, 2, 4, 5], \
60+
"Supports topologies with only 1, 2, 4 or 5 outputs"
6161

6262
log.info("Preparing input blobs")
6363
input_blob = next(iter(net.input_info))

requirements.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
albumentations
2-
attrdict
2+
addict
33
opencv-python
44
numpy
55
sklearn
@@ -15,5 +15,7 @@ icecream
1515
efficientnet_lite_pytorch
1616
efficientnet_lite0_pytorch_model
1717
efficientnet_lite1_pytorch_model
18+
efficientnet_lite2_pytorch_model
1819
pylint
19-
isort
20+
isort
21+
pytest

tests/__init__.py

Whitespace-only changes.

tests/run_pylint.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
'configs/detection',
1313
'torchdet3d/models',
1414
'build',
15-
'deprecated'
16-
'.history/',
17-
'torchdet3d/models'
15+
'deprecated',
16+
'.history',
17+
'torchdet3d/models',
1818
]
1919

2020
to_pylint = []

tests/test_geometry.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import numpy as np
2+
3+
from torchdet3d.utils import (lift_2d, get_default_camera_matrix,
4+
convert_camera_matrix_2_ndc, project_3d_points,
5+
convert_2d_to_ndc)
6+
7+
8+
from objectron.dataset import iou
9+
from objectron.dataset import box
10+
11+
12+
class TestCasesGeometry:
13+
test_kps = np.array([[0.47714591, 0.47491544],
14+
[0.73884577, 0.39749265],
15+
[0.18508956, 0.40002537],
16+
[0.74114597, 0.48664019],
17+
[0.18273196, 0.48833901 ],
18+
[0.64639187, 0.46719882],
19+
[0.32766378, 0.46827659],
20+
[0.64726073, 0.51853681],
21+
[0.32699507, 0.51933688]])
22+
EPS = 1e-5
23+
IOU_THR = 0.5
24+
25+
def test_reprojection_error(self):
26+
kps_3d = lift_2d([self.test_kps], portrait=True)[0]
27+
reprojected_kps = project_3d_points(kps_3d, convert_camera_matrix_2_ndc(get_default_camera_matrix()))
28+
test_kps_ndc = convert_2d_to_ndc(self.test_kps, portrait=True)
29+
assert np.any(np.linalg.norm(test_kps_ndc - reprojected_kps, axis=1) < self.EPS)
30+
31+
def test_3d_iou_stability(self):
32+
np.random.seed(10)
33+
noisy_kps = np.clip(self.test_kps + 0.01*np.random.rand(*self.test_kps.shape), 0, 1)
34+
lifted_3d_sets = lift_2d([self.test_kps, noisy_kps], portrait=True)
35+
36+
b1 = box.Box(vertices=lifted_3d_sets[0])
37+
b2 = box.Box(vertices=lifted_3d_sets[1])
38+
39+
loss = iou.IoU(b1, b2)
40+
assert loss.iou() > self.IOU_THR

torchdet3d/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
import sys
44
import os
55

6-
from torchdet3d import builders, evaluation, dataloaders, trainer, models, utils, losses
7-
from .version import __version__
8-
96
module_path = os.path.abspath(os.path.join(os.path.dirname('__init__.py'), '3rdparty/Objectron'))
107
if module_path not in sys.path:
118
sys.path.append(module_path)
129

10+
#pylint: disable = wrong-import-position
11+
from torchdet3d import builders, evaluation, dataloaders, trainer, models, utils, losses
12+
from .version import __version__
1313

1414
__author__ = 'Sovrasov Vladislav, Prokofiev Kirill'
1515
__description__ = 'A library for deep learning 3D object detection in PyTorch'

0 commit comments

Comments
 (0)