Advanced Lane Finding Using OpenCV
In this project, I used OpenCV to write a software pipeline to identify the lane boundaries in a video from a front-facing camera on a car.
Install / Use
npx skills add mohamedameen-io/Advanced-Lane-Finding-Using-OpenCVInstalls into whichever agent you are using.
README
Advanced Lane Finding Using OpenCV
In this project, I used OpenCV to write a software pipeline to identify the lane boundaries in a video from a front-facing camera on a car.
Pipeline architecture:
- Compute Camera Calibration.
- Apply Distortion Correction.
- Apply a Perspective Transform.
- Create a Thresholded Binary Image.
- Define the Image Processing Pipeline.
- Detect Lane Lines.
- Determine the Curvature of the Lane and Vehicle Position.
- Visual display of the Lane Boundaries and Numerical Estimation of Lane Curvature and Vehicle Position.
- Process Project Videos.
I'll explain each step in details below.
Environement:
- Ubuntu 16.04
- Anaconda 5.0.1
- Python 3.6.2
- OpenCV 3.1.0
Step 1: Compute Camera Calibration
The OpenCV functions cv2.findChessboardCorners() and cv2.drawChessboardCorners() are used for image calibration. We have 20 images of a chessboard, located in ./camera_cal, taken from different angles with the same camera, and we'll use them as input for camera calibration routine.
cv2.findChessboardCorners() attempts to determine whether the input image is a view of the chessboard pattern and locate the internal chessboard corners, and then cv2.drawChessboardCorners() draws individual chessboard corners detected.
Arrays of object points, corresponding to the location of internal corners of a chessboard, and image points, the pixel locations of the internal chessboard corners determined by cv2.findChessboardCorners(), are fed to cv2.drawChessboardCorners() which returns camera calibration and distortion coefficients.
These will then be used by the OpenCV cv2.calibrateCamera() to find the camera intrinsic and extrinsic parameters from several views of a calibration pattern. These parameters will be fed to cv2.undistort function to correct for distortion on any image produced by the same camera.
Step 2: Apply Distortion Correction
OpenCV provides cv2.undistort function, which transforms an image to compensate for radial and tangential lens distortion.
The effect of undistort is particularly noticeable, by the change in shape of the car hood at the bottom corners of the image.
Step 3: Apply a Perspective Transform
A common task in autonomous driving is to convert the vehicle’s camera view of the scene into a top-down “bird’s-eye” view. We'll use OpenCV's cv2.getPerspectiveTransform() and cv2.getPerspectiveTransform() to do this task.
(Starting from line #174 in model.py)
Step 4: Create a Thresholded Binary Image
Now, we will use color transform and Sobel differentiation to detect the lane lines in the image.
(Starting from line #247 in model.py)
Exploring different color spaces
RGB color space:
<figure> <img src="./README_imgs/06.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/07.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure>HSV color space:
This type of color model closely emulates models of human color perception. While in other color models, such as RGB, an image is treated as an additive result of three base colors, the three channels of HSV represent hue (H gives a measure of the spectral composition of a color), saturation (S gives the proportion of pure light of the dominant wavelength, which indicates how far a color is from a gray of equal brightness), and value (V gives the brightness relative to the brightness of a similarly illuminated white color) corresponding to the intuitive appeal of tint, shade, and tone.
<figure> <img src="./README_imgs/08.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/09.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure>LAB color space:
The Lab color space describes mathematically all perceivable colors in the three dimensions L for lightness and a and b for the color opponents green–red and blue–yellow.
<figure> <img src="./README_imgs/10.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/11.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure>HLS color space:
This model was developed to specify the values of hue, lightness, and saturation of a color in each channel. The difference with respect to the HSV color model is that the lightness of a pure color defined by HLS is equal to the lightness of a medium gray, while the brightness of a pure color defined by HSV is equal to the brightness of white.
<figure> <img src="./README_imgs/12.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/13.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure>Color Space Thresholding
As you may observe, the white lane lines are clearly highlighted in the L-channel of the of the HLS color space, and the yellow line are clear in the L-channel of the LAP color space as well. We'll apply HLS L-threshold and LAB B-threshold to the image to highlight the lane lines.
<figure> <img src="./README_imgs/14.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/15.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/16.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure>Sobel Differentiation
Now, we'll explore different Sobel differentiation techniques, and try to come up with a combination that produces a better output than color space thresholding.
Absolute Sobel:
<figure> <img src="./README_imgs/17.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/18.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure>Magnitude Sobel:
<figure> <img src="./README_imgs/19.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/20.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure>Direction Sobel:
<figure> <img src="./README_imgs/21.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/22.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure>Absolute+Magnitude Sobel:
<figure> <img src="./README_imgs/23.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/24.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/25.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure>Comparison between Color Thresholding and Sobel Diffrentiation
We'll apply both color thresholding and Sobel diffrentiation to all the test images to explore which of these two techniques will be better to do the task.
<figure> <img src="./README_imgs/25.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/26.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/27.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/28.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/29.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/30.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/31.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/32.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure> <figure> <img src="./README_imgs/33.png" width="1072" alt="Combined Image" /> <figcaption> <p></p> </figcaption> </figure>As you can see, although Sobel diffrentiation was able to capture the lane lines correctly, it captured some noise around it. On the other hand, color thresholding was able to produce clean output highlighting the lane lines.
Step 5: Define the Image Processing Pipeline
Now, we'll define the complete image processing function to read the raw image and apply the following steps:
- Distortion Correction.
- Perspective Transform.
- Color Thresholding.
Related Skills
python-debugpy
385.5kDebug Python with pdb, breakpoint(), post-mortem inspection, and debugpy remote attach.
skill-creator
385.5kCreate, edit, audit, tidy, validate, or restructure AgentSkills and SKILL.md files.
qqbot-channel
385.5kQQ channel management skill. Use qqbot_channel_api for explicit QQ channel-management requests; confirm write, delete, and bulk actions before calling authenticated QQ Open Platform endpoints.
claude-opus-4-5-migration
140.7kMigrate prompts and code from Claude Sonnet 4.0, Sonnet 4.5, or Opus 4.1 to Opus 4.5
