Home

Awesome

3D-LiDAR and camera extrinsic calibration [paper][arxiv]

<!-- based on reflectance intensity of the laser -->

License

Citation

If you find our codes and method useful to your work, please consider citing this work:

@Article{WANG2017Lidar_camera_cali,
AUTHOR = {Wang, Weimin and Sakurada, Ken and Kawaguchi, Nobuo},
TITLE = {Reflectance Intensity Assisted Automatic and Accurate Extrinsic Calibration of 3D LiDAR and Panoramic Camera Using a Printed Chessboard},
JOURNAL = {Remote Sensing},
VOLUME = {9},
YEAR = {2017},
NUMBER = {8},
ARTICLE-NUMBER = {851},
ISSN = {2072-4292},
DOI = {10.3390/rs9080851}
}

Introduction

<!-- [[paper]](http://www.mdpi.com/journal/remotesensing)-->

This is an python implementation for the fully automatic and accurate extrinsic calibration of an 3D-LiDAR and the camera based on the laser's reflectance intensity. <br> The paper is available here.<br> The main features of this implementations are:<br>

  1. automatic segmentation of the point cloud acquired by Velodyne 3D LiDAR
  2. automatic detection of the chessboard
  3. automatic corners detection from the chessboard's point cloud
  4. optimization for extrinsic calibration parameters
  5. various of visualization for 3D point clouds with VTK python wrapper<br> These features are implemented for VLP-16, HDL-32e and HDL-64e. However, they tested only with HDL-32e. We are appreciated if one could provide data of other types for testing. <img src="readme_files/VLP16_omni60.gif" />

Updates

Dependencies (Tested on macOS sierra and Ubuntu 14.04/16.04)

<!-- * Other python packages: pip install -r [requirements.txt](requirements.txt) -->

Optional

<!-- * [MATLAB engine for Python](https://www.mathworks.com/help/matlab/matlab_external/install-the-matlab-engine-for-python.html): Corner detection from images with MATLAB - for macOS or Linux:<br> ```sh cd "matlabroot/extern/engines/python" python setup.py install ``` -->

Usage

Installation

git clone --recurse-submodules https://github.com/mfxox/ILCC
cd ILCC
python setup.py install

Explanation of files

config.py: parameter settings <br> img_corners_est.py: estimate corners of chessboard from images with OpenCV or MATLAB<br> pcd_corners_est.py: estimate corners of chessboard from the point cloud<br> LM_opt.py: load corresponding 2D-3D corners, calculate initial values with the PnP method, refine the result with LM method<br> utility.py: utility functions for various of visualization

Process data

  1. Make a folder for example named as DATA and make the image and point cloud folders DATA/img and DATA/pcd respectively.

  2. Put panoramic images into DATA/img and point cloud files into DATA/pcd. The files should be named like 00XX.png or 00XX.csv.

  3. cd DATA and copy config.yaml to DATA and modify config.yaml according to your situation.

  4. Corner detection from images.<br>

    from ILCC import img_corners_est
    img_corners_est.detect_img_corners()
    

    Coordinates of corners from images are saved to DATA/output/img_corners with the filename 00XX_img_corners.txt and images with marked corners are saved in the same folder with the file name 00XX_detected_corners.jpg if 'output_img_with_dectected_corners' in config.yaml is set to True, as shown below.

    <div style="text-align: center"> <img src="readme_files/0001_detected_corners.jpg" width = "50%" /> <img src="readme_files/0001_detected_corners_zoom.jpg" width = "24.35%" /> </div>
  5. Corner detection from point clouds.<br>

    from ILCC import pcd_corners_est
    pcd_corners_est.detect_pcd_corners()
    

    Coordinates of corners from point clouds are save to output/pcd_seg with the filename 00XX_pcd_result.pkl. Segments of each point cloud are output to /DATA/output/pcd_seg/00XX.

  6. Non-linear optimization for final extrinsic parameters.<br>

    from ILCC import LM_opt
    LM_opt.cal_ext_paras()
    

    The extrinsic calibration results are output in the end of the process and saved with the filename YYYYMMDD_HHMMSS_calir_result.txt. Images of back-projected 3D corners using the calculated parameters are saved to DATA/output if 'back_proj_corners' is set to True, as shown below.

    <div style="text-align: center"> <img src="readme_files/0001_cal_backproj.jpg" width = "50%" /> <img src="readme_files/0001_cal_backproj_zoom.jpg" width = "24.35%" /><br> <!-- <em>Example of panoramic image. </em> --> </div>
  7. After the aforementioned process, utility module can be imported for visualizing various of results. <br>

    from ILCC import utility
    utility.vis_back_proj(ind=1, img_style="orig", pcd_style="dis", hide_occlussion_by_marker=False)
    utility.vis_back_proj(ind=1, img_style="orig", pcd_style="dis", hide_occlussion_by_marker=True)
    utility.vis_back_proj(ind=1, img_style="edge", pcd_style="intens", hide_occlussion_by_marker=True)
    

    The image (see below) with back-projected point cloud with the calculated extrinsic parameters will be showed and press "s" for saving. img_style can be "edge" (edge extracted) or "orig" (original image) and pcd_style can be "dis" (color by distance) or "intens" (color by intensity).

    <div style="text-align: center"> <p align="center"> <img src="readme_files/0001_orig_dis.jpg" width = "80%" /><br> <em>Project points to the original image with coloring by distance. The occluded part by the chessboard is not hided.</em> <br> <img src="readme_files/0001_orig_dis_hide_occlusion.jpg" width = "80%" /><br> <em>The occluded part by the chessboard is hided. The occluded part by the chessboard is hided by setting the parameter hide_occlussion_by_marker True.</em> <br> Check the upper part of the chessboard in the two images above. </em> <br> <img src="readme_files/0001_edge_intens_hide_occlusion.jpg" width = "80%" /><br> <em>Project points to the edge image with coloring by intensity. Occluded points by the chessboard are hided.</em> </p> </div> <div style="text-align: center"> <p align="center"> <img src="readme_files/0001_orig_dis.png" width = "20%" /> <img src="readme_files/0001_orig_dis_hide_occlusion.png" width = "20%" /> <img src="readme_files/0001_edge_intens.png" width = "20%" /> <img src="readme_files/0001_edge_intens_hide_occlusion.png" width = "20%" /> <br> <em>Results of perspective images. From left to right: [color: distance, original image], [color: distance, original image, hide occlusion], [color: intensity, edge image], [color: intensity, edge image, hide occlusion]. </em> </p> </div>
<!-- <div style="text-align: center"> <p align="center"> <img src="readme_files/0001_orig_dis_hide_occlusion.jpg" width = "49%" /> <img src="readme_files/0001_edge_intens_hide_occlusion.jpg" width = "49%" /> <em>Hide the occluded part by the chessboard by setting __hide_occlussion_by_marker__ True.</em> </p> </div> -->
  1. For 3D visualization, [VTK](https:// clhub.com/Kitware/VTK) >=7.0 is necessary. See the example below for how to use.

Example

Sample Data

The sample data and processing results of detected corners can be downloaded from here (181M) for panoramic image and here (29M) for perspective image. <br> These data are acquired with the chessboard file which contains 6*8 patterns and the length of one grid is 7.5cm if it is printed by A0 size.

Process

wget https://www.dropbox.com/s/m0ogerftqav0fyx/ILCC_sample_data_and_result.zip
unzip ILCC_sample_data_and_result.zip
cd ILCC_sample_data_and_result

copy config.yaml to ILCC_sample_data_and_result folder.

wget https://www.dropbox.com/s/et0o4k2sp485nz1/ILCC_sample_perspective_data.zip
unzip ILCC_sample_perspective_data.zip
cd ILCC_sample_perspective_data

copy config.yaml to ILCC_sample_data_and_result folder.<br/> Set camera_type to 'perpsective' and input the intrinsic parameters to instrinsic_para by modifying config.yaml .

Visualization (VTK >=7.0 is necessary)

    from ILCC import utility
    utility.vis_csv_pcd(ind=1)
<div style="text-align: center"> <img src="readme_files/vis_csv.png" width = "50%" /> </div>
    from ILCC import utility
    utility.vis_segments(ind=1)
<div style="text-align: center"> <img src="readme_files/vis_seg.png" width = "50%" /> </div>
    from ILCC import utility
    utility.vis_segments_only_chessboard_color(ind=1)
<div style="text-align: center"> <img src="readme_files/vis_chessboard_only.png" width = "50%" /> </div>
    from ILCC import utility
    utility.vis_ested_pcd_corners(ind=1)
<div style="text-align: center"> <img src="readme_files/vis_est_marker.png" width = "50%" /> </div>
    import utility
    import numpy as np
    utility.vis_all_markers(utility.vis_all_markers(np.arange(1, 21).tolist()))
<div style="text-align: center"> <img src="readme_files/all_frames_side.png" width = "60%" /> <img src="readme_files/all_frames_top.png" width = "65%" /> </div>

Troubleshooting

  1. The chessboard was not segmented properly.
  1. The chessboard seems to be segmented properly by visualizing the segmentation result with utility.vis_segments, but "no marker is found" or the wrong segment is found.
  1. The corner of the chessboard point cloud is not correctly detected.

For further questions, please discuss in Issues.

Tested conditions

No.LiDAR ModelCamera ModelPattern SizeGrid Length[cm]Distance Range[m]Data sourceAuthor
1Velodyne <br> HDL-32eLadybug3 (panoramic)8*67.51.2 ~ 2.6linkmfxox
2Velodyne <br> HDL-32eOne monocular camera of the Ladybug38*67.51.2 ~ 2.6linkmfxox

Contributing

We are appreciated if you could share the collected data with different sizes or patterns of chessboard or other types of LiDAR sensors. We will acknowledge your contributions in the tested conditions' list.

If you have any question, please discuss in Issues or contact me directly.

To do list

<!-- 1. Uniformity check with chi-square test for chessboard detection -->
  1. Remove the limitation of the constraints of the consistency between the patterns size and board size. Make corners detectable with OpenCV.
  2. Integration for ROS
  3. <del>Add optimization for perspective camera model</del>(20180416)
  4. <del>Add parameters for HDL-64 and VLP-16-PACK</del>(20170614)