-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2b39788
Showing
61 changed files
with
9,101 additions
and
0 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 |
---|---|---|
@@ -0,0 +1,3 @@ | ||
utils/ | ||
__pycache__ | ||
Log/ |
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,49 @@ | ||
![alt text](https://github.com/daniilidis-group/m3ed/blob/master/M3ED_banner.webp) | ||
|
||
# M3ED Processing Scripts | ||
|
||
This repo contains the scripts used to process the M3ED data. These scripts are | ||
run automatically in Jenkins. | ||
|
||
## Dockerfile | ||
|
||
We provide a `Dockerfile` to run the data conversions. We used this docker | ||
environment to process the bags automatically and generate the bag reports. | ||
|
||
### Jenkins build architecture | ||
|
||
Jenkins was used as our deployment platform. There are three Jenkins pipelines: | ||
|
||
- Dispatcher: this pipeline gathers all the input files, and orchestrates the | ||
execution of the work among the different nodes. The `Jenkinsfile_dispatcher` is used for this | ||
pipeline. | ||
|
||
- Docker-build: this pipeline builds the docker image **in each node**. This | ||
ensures that the processing pipelines have the most up-to-date docker image. | ||
The `Jenkinsfile_docker_build` is used for this pipeline. | ||
|
||
- Processing: Runs the processing scripts. The `Jenkinsfile_processing` is used | ||
for this pipeline. | ||
|
||
### Jenkins Master Setup | ||
|
||
1. Install Jenkins | ||
2. Create three jobs: `M3ED-dispatcher`, `M3ED-docker-build`, `M3ED-processing` | ||
3. Ensure that `M3ED-docker-build` and `M3ED-dispatcher` are executed for all | ||
branches (Branch Specifier). | ||
4. Choose the Branch Specifier that you want for `M3ED-dispatcher`. | ||
|
||
## Scripts | ||
|
||
- `preliminary.sh`: this script is executed in each build node and it verifies that | ||
the docker image is properly built, we have access to the processing folder and | ||
files. | ||
|
||
- `bag_processing/rosbag2verify.py`: verifies bag timestamps and integrity. | ||
|
||
- `bag_processing/rosbag2hdf5.py`: converts the bag data into HDF5. | ||
|
||
- `bag_processing/hdf52media.py`: generates media output from the HDF5 (videos, plots, images). | ||
|
||
## License | ||
M3ED is released under the (Creative Commons Attribution-ShareAlike 4.0 International License)[https://creativecommons.org/licenses/by-sa/4.0/]. |
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,120 @@ | ||
import os | ||
import pdb | ||
import argparse | ||
|
||
import numpy as np | ||
import h5py | ||
import matplotlib.pyplot as plt | ||
|
||
from scipy.interpolate import splev, splrep, barycentric_interpolate | ||
from scipy.spatial.transform import Rotation | ||
from scipy import signal | ||
|
||
def resample_imu(imu, imu_ts, sample_times): | ||
spl = splrep(imu_ts, imu) | ||
return splev( sample_times, spl) | ||
|
||
def filter_imu_sample(imu, numtaps=7, f=0.10): | ||
coeffs = signal.firwin(numtaps, f) | ||
filtered = np.zeros(imu.shape) | ||
filtered[:,0] = signal.lfilter(coeffs, 1.0, imu[:,0]) | ||
filtered[:,1] = signal.lfilter(coeffs, 1.0, imu[:,1]) | ||
filtered[:,2] = signal.lfilter(coeffs, 1.0, imu[:,2]) | ||
return filtered | ||
|
||
def align_imus(ovc_omega, ovc_accel, ouster_omega, ouster_accel): | ||
""" | ||
Solving ouster_R_ovc * ovc_omega = ouster_omega | ||
""" | ||
ovc_measurements = np.concatenate( [ovc_omega] ).T | ||
ouster_measurements = np.concatenate( [ouster_omega] ).T | ||
|
||
ouster_R_ovc = (ouster_measurements @ np.linalg.pinv(ovc_measurements)) | ||
U,S,Vh = np.linalg.svd(ouster_R_ovc) | ||
ouster_R_ovc = U@Vh | ||
ouster_R_ovc[:,0] = -ouster_R_ovc[:,0] | ||
ouster_R_ovc[:,2] = np.cross(ouster_R_ovc[:,0],ouster_R_ovc[:,1]) | ||
|
||
assert np.all(np.isclose( np.linalg.det(ouster_R_ovc), 1.0 )) | ||
|
||
return ouster_R_ovc | ||
|
||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser(description="Creates vids and imgs from h5.") | ||
# input h5 file | ||
parser.add_argument("--h5fn", help="The h5 file to convert.", | ||
required=True) | ||
args = parser.parse_args() | ||
|
||
if not os.path.isfile(args.h5fn): | ||
sys.exit("The input h5 file %s does not exist." % args.h5fn) | ||
|
||
h5f = h5py.File(args.h5fn, 'r') | ||
|
||
ovc_mask = np.isfinite(h5f['/ovc/imu/accel'][:,0]) | ||
ovc_ts = h5f['/ovc/imu/ts'][...][ovc_mask] | ||
ovc_accel = h5f['/ovc/imu/accel'][...][ovc_mask,:] | ||
ovc_omega = h5f['/ovc/imu/omega'][...][ovc_mask,:] | ||
|
||
ouster_mask = np.isfinite(h5f['/ouster/imu/accel'][1000:-1000,0]) | ||
ouster_ts = h5f['/ouster/imu/ts'][1000:-1000][ouster_mask] | ||
ouster_accel = h5f['/ouster/imu/accel'][1000:-1000][ouster_mask,:] | ||
ouster_omega = h5f['/ouster/imu/omega'][1000:-1000][ouster_mask,:] | ||
|
||
ovc_resampled_omega = np.stack( [resample_imu(ovc_omega[:,i], ovc_ts, ouster_ts) for i in range(3)], axis=-1 ) | ||
ovc_resampled_accel = np.stack( [resample_imu(ovc_accel[:,i], ovc_ts, ouster_ts) for i in range(3)], axis=-1 ) | ||
|
||
ouster_accel = filter_imu_sample(ouster_accel) | ||
ouster_omega = filter_imu_sample(ouster_omega) | ||
|
||
ovc_omega = filter_imu_sample(ovc_resampled_omega) | ||
ovc_accel = filter_imu_sample(ovc_resampled_accel) | ||
ovc_ts = ouster_ts | ||
|
||
ouster_R_ovc = align_imus(ovc_omega, ovc_accel, ouster_omega, ouster_accel) | ||
|
||
print(ouster_R_ovc) | ||
print(np.rad2deg(Rotation.from_matrix(ouster_R_ovc).as_euler('xyz'))) | ||
print(np.linalg.det(ouster_R_ovc)) | ||
|
||
transformed_ovc_omega = (ouster_R_ovc @ ovc_omega.T).T | ||
transformed_ovc_accel = (ouster_R_ovc @ ovc_accel.T).T | ||
|
||
fig, axes = plt.subplots(3,2,sharex=True,sharey=True) | ||
|
||
axes[0,0].set_title('OVC gyro') | ||
axes[0,0].plot( ovc_ts, transformed_ovc_omega[:,0] ) | ||
axes[1,0].plot( ovc_ts, transformed_ovc_omega[:,1] ) | ||
axes[2,0].plot( ovc_ts, transformed_ovc_omega[:,2] ) | ||
|
||
axes[0,1].set_title('Ouster gyro') | ||
axes[0,1].plot( ouster_ts[:-1], ouster_omega[:-1,0] ) | ||
axes[1,1].plot( ouster_ts[:-1], ouster_omega[:-1,1] ) | ||
axes[2,1].plot( ouster_ts[:-1], ouster_omega[:-1,2] ) | ||
|
||
fig, axes = plt.subplots(3,2,sharex=True,sharey=True) | ||
|
||
axes[0,0].set_title('OVC accel') | ||
axes[0,0].plot( ovc_ts, transformed_ovc_accel[:,0] ) | ||
axes[1,0].plot( ovc_ts, transformed_ovc_accel[:,1] ) | ||
axes[2,0].plot( ovc_ts, transformed_ovc_accel[:,2] ) | ||
|
||
axes[0,1].set_title('Ouster accel') | ||
axes[0,1].plot( ouster_ts[:-1], ouster_accel[:-1,0] ) | ||
axes[1,1].plot( ouster_ts[:-1], ouster_accel[:-1,1] ) | ||
axes[2,1].plot( ouster_ts[:-1], ouster_accel[:-1,2] ) | ||
|
||
plt.figure() | ||
plt.plot(ovc_ts, transformed_ovc_omega[:,0] ) | ||
plt.plot( ouster_ts, ouster_omega[:,0]) | ||
|
||
plt.figure() | ||
plt.plot(ovc_ts, transformed_ovc_omega[:,1] ) | ||
plt.plot( ouster_ts, ouster_omega[:,1]) | ||
|
||
plt.figure() | ||
plt.plot(ovc_ts, transformed_ovc_omega[:,2] ) | ||
plt.plot( ouster_ts, ouster_omega[:,2]) | ||
|
||
plt.show() |
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,32 @@ | ||
#!/bin/bash | ||
|
||
source ./build_system/preamble.bash | ||
|
||
output_files=("$EVENTS_VIDEO_RAW" "$RGB_VIDEO_RAW") | ||
check_files output_files | ||
check_free_space fixed | ||
|
||
# create tmp variables for videos | ||
EVENTS_VIDEO_RAW_TMP="${EVENTS_VIDEO_RAW%.*}_tmp.${EVENTS_VIDEO_RAW##*.}" | ||
RGB_VIDEO_RAW_TMP="${RGB_VIDEO_RAW%.*}_tmp.${RGB_VIDEO_RAW##*.}" | ||
|
||
# Run bag processing | ||
echo -e "${BLUE}Generating raw videos${NC}" | ||
python3 build_system/bag_processing/hdf52media.py \ | ||
--h5fn "$H5_PATH" \ | ||
--out_events_gray "$EVENTS_VIDEO_RAW_TMP" \ | ||
--out_rgb "$RGB_VIDEO_RAW_TMP" | ||
if [ $? -ne 0 ]; then | ||
echo -e "${RED}Error creating media files for $H5_PATH${NC}" | ||
rm "$EVENTS_VIDEO_RAW_TMP" "$RGB_VIDEO_RAW_TMP" | ||
exit 1 | ||
fi | ||
echo -e "${GREEN}Raw videos finished${NC}" | ||
mv "$EVENTS_VIDEO_RAW_TMP" "$EVENTS_VIDEO_RAW" | ||
mv "$RGB_VIDEO_RAW_TMP" "$RGB_VIDEO_RAW" | ||
|
||
# Compress videos | ||
echo -e "${BLUE}Generating compressed videos${NC}" | ||
compress_with_ffmpeg "$EVENTS_VIDEO_RAW" | ||
compress_with_ffmpeg "$RGB_VIDEO_RAW" | ||
echo -e "${GREEN}Compressed videos finished${NC}" |
Oops, something went wrong.