forked from DLR-RM/BlenderProc
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request DLR-RM#462 from apenzko/master
Stereo matching with projector example
- Loading branch information
Showing
11 changed files
with
364 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
from blenderproc.python.utility.Utility import resolve_path, num_frames, resolve_resource, set_keyframe_render_interval, reset_keyframes | ||
from blenderproc.python.utility.LabelIdMapping import LabelIdMapping | ||
from blenderproc.python.utility.LabelIdMapping import LabelIdMapping | ||
from blenderproc.python.utility.PatternUtility import generate_random_pattern_img |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import numpy as np | ||
import random | ||
import cv2 | ||
|
||
|
||
def generate_random_pattern_img(width: int, height: int, n_points: int) -> np.ndarray: | ||
"""Generate transparent image with random pattern. | ||
:param width: width of image to be generated. | ||
:param height: height of image to be generated. | ||
:param n_points: number of white points uniformly placed on image. | ||
""" | ||
pattern_img = np.zeros((height, width, 4), dtype=np.uint8) | ||
|
||
m_width = int(width // np.sqrt(n_points)) | ||
m_height = int(height // np.sqrt(n_points)) | ||
|
||
for i in range(width // m_width): | ||
for j in range(height // m_height): | ||
x_idx = random.randint(i * m_width, (i + 1) * m_width - 1) | ||
y_idx = random.randint(j * m_height, (j + 1) * m_height - 1) | ||
pattern_img = cv2.circle(pattern_img, (x_idx, y_idx), 1, (255, 255, 255, 255), -1) | ||
|
||
return pattern_img |
79 changes: 79 additions & 0 deletions
79
examples/advanced/stereo_matching_with_projector/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# Stereo Matching with Random Pattern Projector | ||
 | ||
|
||
On the left side we can see the rendered RGB image (right) without a pattern and the corresponding stereo depth estimation on the bottom. | ||
On the right side we can see the rendered RGB image (right) with a projected random pattern adding 25600 points to the image and the corresponding stereo depth estimation on the bottom. | ||
Adding a random pattern to the image increases available features for the stereo matching algorithm, making it easier to discern small details, such as the chair's arm rest. | ||
Furthermore, the added random pattern is projected through a SPOT light source in blender, which loses intensity the further away from the source it gets. | ||
|
||
## Usage | ||
|
||
Execute in the BlenderProc main directory: | ||
|
||
``` | ||
blenderproc run examples/advanced/stereo_matching_with_projector/main.py <path to cam_pose file> <path to house.json> examples/advanced/stereo_matching/output <number of points> | ||
``` | ||
|
||
* `examples/advanced/stereo_matching_with_projector/main.py`: path to the main python file to run. | ||
* `<path to cam_pose file>`: Should point to a file which describes one camera pose per line (here the output of `scn2cam` from the `SUNCGToolbox` can be used). | ||
* `<path to house.json>`: Path to the house.json file of the SUNCG scene you want to render. Which should be either located inside the SUNCG directory, or the SUNCG directory path should be added to the config file. | ||
* `<number of points>`: Number of points for random pattern. Default = 2560. | ||
* `examples/advanced/stereo_matching_with_projector/output`: path to the output directory. | ||
|
||
## Visualizaton | ||
Visualize the generated data: | ||
``` | ||
blenderproc vis hdf5 examples/advanced/stereo_matching_with_projector/output/0.hdf5 | ||
``` | ||
|
||
## Implementation | ||
|
||
```python | ||
# Genrate pattern image | ||
pattern_img = bproc.utility.generate_random_pattern_img(WIDTH, HEIGHT, args.points) | ||
|
||
# Define a new light source and set it as projector | ||
light = bproc.types.Light() | ||
light.set_type('SPOT') | ||
light.set_energy(3000) | ||
fov = bproc.camera.get_fov() | ||
ratio = HEIGHT / WIDTH | ||
light.setup_as_projector(fov[0], ratio, pattern_img) | ||
``` | ||
Here we setup the projector: | ||
* Generate a pattern image to be projected onto the scene. | ||
* Set new spot light with custom energy. | ||
* Using the spot light as projector for specified pattern image `pattern_img`: | ||
* Set projector location to camera via `COPY TRANSFORMS` | ||
* Scale image based on field of view `fov` of camera and rendered image size `WIDTH, HEIGHT` | ||
* Link image as texture | ||
> for further details see implementation at [blenderproc/python/types/LightUtility.py](blenderproc/python/types/LightUtility.py) | ||
```python | ||
# Enable stereo mode and set baseline | ||
bproc.camera.set_stereo_parameters(interocular_distance=0.05, convergence_mode="PARALLEL") | ||
``` | ||
|
||
Here we enable stereo rendering and specify the camera parameters, some notable points are: | ||
* Setting the `interocular_distance` which is the stereo baseline. | ||
* Specifying `convergence_mode` to be `"PARALLEL"` (i.e. both cameras lie on the same line and are just shifted by `interocular_distance`, and are trivially coplanar). | ||
* Other options are `OFF-AXIS` where the cameras rotate inwards (converge) up to some plane. | ||
* `convergence_distance` is the distance from the cameras to the aforementioned plane they converge to in case of `OFF-AXIS` convergence mode. In this case, this parameter is ignored by Blender, but it is added here for clarification. | ||
|
||
```python | ||
# Apply stereo matching to each pair of images | ||
data["stereo-depth"], data["disparity"] = bproc.postprocessing.stereo_global_matching(data["colors"], disparity_filter=False) | ||
``` | ||
|
||
Here we apply the stereo matching. | ||
* It is based on OpenCV's [implementation](https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html?highlight=sgbm#stereosgbm-stereosgbm) of [stereo semi global matching](https://elib.dlr.de/73119/1/180Hirschmueller.pdf). | ||
* Its pipeline runs as follows: | ||
* Compute the disparity map between the two images. After specifying the required parameters. | ||
* Optional use of a disparity filter (namely `wls_filter`). Enabled by setting `disparity_filter` (Enabling it could possibly lead to less accurate depth values. One should experiment with this parameter). | ||
* Triangulate the depth values using the focal length and disparity. | ||
* Clip the depth map from 0 to `depth_max`, where this value is retrieved from `renderer.Renderer`. | ||
* Apply an optional [depth completion routine](https://github.com/kujason/ip_basic/blob/master/ip_basic/depth_map_utils.py), based on simple image processing techniques. This is enabled by setting `depth_completion`. | ||
* There are some stereo semi global matching parameters that can be tuned (see fct docs), such as: | ||
* `window_size` | ||
* `num_disparities` | ||
* `min_disparity` |
86 changes: 86 additions & 0 deletions
86
examples/advanced/stereo_matching_with_projector/config.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# Args: <cam_file> <obj_file> <pattern_path> <output_dir> | ||
{ | ||
"version": 3, | ||
"setup": { | ||
"blender_install_path": "/home_local/<env:USER>/blender/", | ||
"pip": [ | ||
"h5py", | ||
"python-dateutil==2.1", | ||
"numpy", | ||
"Pillow", | ||
"opencv-contrib-python", | ||
"scipy" | ||
] | ||
}, | ||
"modules": [ | ||
{ | ||
"module": "main.Initializer", | ||
"config": { | ||
"global": { | ||
"output_dir": "<args:3>" | ||
} | ||
} | ||
}, | ||
{ | ||
"module": "loader.SuncgLoader", | ||
"config": { | ||
"path": "<args:1>" | ||
} | ||
}, | ||
{ | ||
"module": "camera.CameraLoader", | ||
"config": { | ||
"path": "<args:0>", | ||
"file_format": "location rotation/value _ _ _ _ _ _", | ||
"world_frame_change": ["X", "-Z", "Y"], | ||
"default_cam_param": { | ||
"rotation": { | ||
"format": "forward_vec" | ||
} | ||
}, | ||
"intrinsics": { | ||
"interocular_distance": 0.05, | ||
"stereo_convergence_mode": "PARALLEL", | ||
"convergence_distance": 0.00001, | ||
"cam_K": [650.018, 0, 637.962, 0, 650.018, 355.984, 0, 0 ,1], | ||
"resolution_x": 1280, | ||
"resolution_y": 720 | ||
}, | ||
} | ||
}, | ||
{ # Projector Light (needs to be after camera loader) | ||
"module": "lighting.LightLoader", | ||
"config": { | ||
"lights": [ | ||
{ | ||
"type": "SPOT", | ||
"energy": 3000, | ||
"use_projector": True, | ||
"path": "<args:2>" | ||
} | ||
] | ||
} | ||
}, | ||
{ | ||
"module": "lighting.SuncgLighting", | ||
"config": {} | ||
}, | ||
{ | ||
"module": "renderer.RgbRenderer", | ||
"config": { | ||
"render_distance": true, | ||
"stereo": true, | ||
"use_alpha": true, | ||
} | ||
}, | ||
{ | ||
"module": "writer.StereoGlobalMatchingWriter", | ||
"config": { | ||
"disparity_filter": false | ||
} | ||
}, | ||
{ | ||
"module": "writer.Hdf5Writer", | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import blenderproc as bproc | ||
import argparse | ||
import os | ||
import numpy as np | ||
|
||
parser = argparse.ArgumentParser() | ||
parser.add_argument('camera', help="Path to the camera file which describes one camera pose per line, here the output of scn2cam from the SUNCGToolbox can be used") | ||
parser.add_argument('house', help="Path to the house.json file of the SUNCG scene to load") | ||
parser.add_argument('output_dir', nargs='?', default="examples/datasets/suncg_basic/output", help="Path to where the final files, will be saved") | ||
parser.add_argument('points', type=int, default=2560, help="Number of points for random pattern. Not always exact due to rounding errors.") | ||
args = parser.parse_args() | ||
|
||
bproc.init() | ||
|
||
# load the objects into the scene | ||
label_mapping = bproc.utility.LabelIdMapping.from_csv(bproc.utility.resolve_resource(os.path.join('id_mappings', 'nyu_idset.csv'))) | ||
objs = bproc.loader.load_suncg(args.house, label_mapping=label_mapping) | ||
|
||
# define the camera intrinsics | ||
K = np.array([ | ||
[650.018, 0, 637.962], | ||
[0, 650.018, 355.984], | ||
[0, 0, 1] | ||
]) | ||
WIDTH, HEIGHT = 1280, 720 | ||
bproc.camera.set_intrinsics_from_K_matrix(K, WIDTH, HEIGHT) | ||
|
||
# Enable stereo mode and set baseline | ||
bproc.camera.set_stereo_parameters(interocular_distance=0.05, convergence_mode="PARALLEL", convergence_distance=0.00001) | ||
|
||
# Genrate pattern image | ||
pattern_img = bproc.utility.generate_random_pattern_img(WIDTH, HEIGHT, args.points) | ||
|
||
# Define a new light source and set it as projector | ||
light = bproc.types.Light() | ||
light.set_type('SPOT') | ||
light.set_energy(3000) | ||
light.setup_as_projector(pattern_img) | ||
|
||
# read the camera positions file and convert into homogeneous camera-world transformation | ||
with open(args.camera, "r") as f: | ||
for line in f.readlines(): | ||
line = [float(x) for x in line.split()] | ||
position = bproc.math.change_coordinate_frame_of_point(line[:3], ["X", "-Z", "Y"]) | ||
rotation = bproc.math.change_coordinate_frame_of_point(line[3:6], ["X", "-Z", "Y"]) | ||
matrix_world = bproc.math.build_transformation_mat(position, bproc.camera.rotation_from_forward_vec(rotation)) | ||
bproc.camera.add_camera_pose(matrix_world) | ||
|
||
# makes Suncg objects emit light | ||
bproc.lighting.light_suncg_scene() | ||
|
||
# activate normal and depth rendering | ||
bproc.renderer.enable_depth_output(activate_antialiasing=False) | ||
bproc.material.add_alpha_channel_to_textures(blurry_edges=True) | ||
bproc.renderer.toggle_stereo(True) | ||
|
||
# render the whole pipeline | ||
data = bproc.renderer.render() | ||
|
||
# Apply stereo matching to each pair of images | ||
data["stereo-depth"], data["disparity"] = bproc.postprocessing.stereo_global_matching(data["colors"], disparity_filter=False) | ||
|
||
# write the data to a .hdf5 container | ||
bproc.writer.write_hdf5(args.output_dir, data) |
Binary file added
BIN
+171 KB
examples/advanced/stereo_matching_with_projector/patterns/random_pattern_00256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+487 KB
examples/advanced/stereo_matching_with_projector/patterns/random_pattern_02809.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+2.71 MB
examples/advanced/stereo_matching_with_projector/patterns/random_pattern_25600.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.