The goals / steps of this project are the following:
My project includes the following files:
The code for this step is contained in the method
calibrateCameraFromDir the file called camera_calibration.py.
I start by preparing “object points”, which will be the (x, y, z) coordinates of the chessboard corners in the world. Here I am assuming the chessboard is fixed on the (x, y) plane at z=0, such that the object points are the same for each calibration image. Thus,
objp is just a replicated array of coordinates, and
objpoints will be appended with a copy of it every time I successfully detect all chessboard corners in a test image.
imgpoints will be appended with the (x, y) pixel position of each of the corners in the image plane with each successful chessboard detection.
I then used the output
imgpoints to compute the camera calibration and distortion coefficients using the
cv2.calibrateCamera() function. I applied this distortion correction to the test image using the
cv2.undistort() function and obtained this result:
The pipeline for single images is implemented in pipeline.py
The following image demonstrates the distortion corextion to a road image:
I used a combination of color and gradient thresholds to generate a binary image ( threshold.py ). Here’s an example of my output for this step.
The code for my perspective transform includes a function called
warp(), which appears in file perspective_trafo.py. The
warp() function takes as inputs an image (
img), and runs
cv2.warpPerspective() using the follwing source (
src) and destination (
dst) points. I chose the hardcode the source and destination points in the following manner:
src = np.float32( [[(img_size / 2) - 62, img_size / 2 + 100], [((img_size / 6) - 10), img_size], [(img_size * 5 / 6) + 60, img_size], [(img_size / 2 + 62), img_size / 2 + 100]]) dst = np.float32( [[(img_size / 4), 0], [(img_size / 4), img_size], [(img_size * 3 / 4), img_size], [(img_size * 3 / 4), 0]])
This resulted in the following source and destination points:
|578, 460||320, 0|
|203, 720||320, 720|
|1127, 720||960, 720|
|702, 460||960, 0|
I verified that my perspective transform was working as expected by drawing the
dst points onto a test image and its warped counterpart to verify that the lines appear parallel in the warped image.
The detection of lane-lines starts with searching for peaks in the histogramm in the bottom part of the thresholded and warped images. The identified peaks are used as the starting point for following the line using the sliding window approach. (lanefinder.py, function
After the initial line is detected, we can continue searching for the new location of the lane line starting in the area where the current line was detected. (lanefinder.py, function
I did this in functions
lanepos() in curvature.py
The creation of the final video is implemented in videoprocess.py
During the implementation of this project I found it very useful to make use of python unittests in order to test the code and in order to calculate and evaluate differnt parameters, e.g. in the context of thresholding. The chosen approach worked pretty well for all three test videos. However, it had some problems in case the surface of the street changes, there is much shadow on the road, lane lines are missing, etc.
Improvements could be:
Please, the links below can be of great help for more information on camera calibration: