Skip to content
HomeProjectsHighlightsBlogPlaygroundRésuméAbout

VSLAM Drone Navigation

by Michael Rusu

I explored how a moving monocular camera can track visual landmarks and recover scene structure. The project combines feature matching, relative camera motion, and learned-depth experiments as a foundation for drone navigation.

Code

Monocular vision and mapping
OpenCV · MiDaS · Geometric reconstruction

Explore the project ↓
The problemMy contributionArchitectureFeature trackingDepth and geometryEvaluationExperiments

The problem

A moving camera sees the same room from changing viewpoints. To estimate its motion, the system needs to associate visible features across frames and relate their image positions to the camera’s geometry.

With a single camera, scale and motion are intertwined. Feature tracks supply geometric constraints, while learned depth supplies another representation of the visible scene. This project explored both using recorded room imagery and several small computer-vision programs.

My contribution

I built the monocular vision study, feature and geometry experiments, learned-depth integration, pose experiments, and reconstruction visualizations. My work moved between camera calibration, visual correspondences, and different ways of turning an image into a three-dimensional representation.

Architecture

Recorded frames feed feature-tracking and learned-depth experiments, producing match displays, relative rotation, depth views, and point-cloud studies.
Figure 1. Camera frames enter tracking and depth experiments. PNGEditable Excalidraw Download figure

The repository contains separate experimental paths. ORB scripts detect and match image features. A later path uses Lucas–Kanade optical flow, estimates an essential matrix with RANSAC, and calls recoverPose to obtain relative rotation. MiDaS_small supplies depth-like image values for separate visualization and projection studies.

The shared input is recorded imagery. The drone-facing script imports a Tello adapter, while its executable path reads a room video. Map-update and flight-control work remains sketched in the source.

Feature tracking

ORB produces keypoints and binary descriptors. The matching path uses a brute-force matcher with Hamming distance and cross-checking, sorts matches by descriptor distance, and extracts paired image coordinates. Those correspondences are the bridge between two views of the same scene.

Python · paired feature coordinatesSource ↗
def detect_and_match_features(orb, bf, prev_frame, frame):
    kp1, des1 = orb.detectAndCompute(prev_frame, None)
    kp2, des2 = orb.detectAndCompute(frame, None)

    matches = bf.match(des1, des2)
    matches = sorted(matches, key=lambda x: x.distance)

    pts1 = np.float32([kp1[m.queryIdx].pt for m in matches]).reshape(-1, 1, 2)
    pts2 = np.float32([kp2[m.trainIdx].pt for m in matches]).reshape(-1, 1, 2)

    return pts1, pts2
Six synthetic landmarks are projected into two calibrated cameras, with corresponding points connected across the image pair.
Figure 2. Corresponding landmarks connect two camera views. PNGEditable Excalidraw Download figure

The figure projects six fixed points into two synthetic cameras with matching intrinsics. Their horizontal displacement illustrates how camera separation and scene depth affect the image coordinates. The fixture is independent of the recorded room footage.

The optical-flow experiment filters tracks by their status flags before estimating motion. The code also includes SIFT and homography studies. These paths capture different stages of the exploration, with their descriptor choices and failure cases recorded in the local source audit.

Depth and geometry

The depth scripts load MiDaS_small, resize its output back to the working image dimensions, and normalize the values to a range from zero to one. MiDaS supplies relative scene depth; connecting its output to physical distances requires an additional scale model.

One experiment builds a grid of image coordinates, applies the inverse camera matrix, and multiplies those rays by the normalized values. This exposes the back-projection calculation and its dependence on the camera intrinsics.

Python · image-grid back-projectionSource ↗
x, y = np.meshgrid(np.arange(0, width), np.arange(0, height))

image_points = np.vstack((x.flatten(), y.flatten(), np.ones_like(x.flatten())))

normalized_points = np.linalg.inv(K) @ image_points

x_3d = normalized_points[0, :] * depth_map.flatten()
y_3d = normalized_points[1, :] * depth_map.flatten()
z_3d = depth_map.flatten()
A fixed 3-by-4 normalized depth grid passes through camera rays to form twelve coordinates, displayed in an X-Z projection.
Figure 3. Image rays and depth values form point coordinates. PNGEditable Excalidraw Download figure

The figure uses a small fixed depth grid and a camera matrix matched to its dimensions. Its twelve coordinates make the arithmetic inspectable. In the source experiment, resizing the image while retaining the original intrinsics limits the geometric interpretation of the resulting cloud.

Other scripts explore essential-matrix pose recovery, triangulation, and Perspective-n-Point. Their outputs document experiments with camera motion and image geometry. The opening scene uses a repeatable illustrative camera path through fixed landmarks.

Evaluation

The project record supports a visual account of the experiments: paired room frames, feature displays, depth views, and coordinate plots. The repository does not provide a verified trajectory benchmark, calibrated distance result, or autonomous-flight evaluation.

The inspected paths also contain unfinished map updates, inconsistent depth sampling, and a weak-track branch that leaves rotation undefined. The local audit records those details. The article therefore follows the individual experiments and the evidence each produces.

Offline fixtures check match ordering, correspondence indices, two-camera projection, and back-projection consistency. They also preserve the observed weak-track failure. No camera, drone, or external depth model runs in this page.

Experiments

Original paired grayscale room images retained from the early visual-tracking experiment.
Room imagery from the early tracking experiments.

These frames show the indoor visual material used during development. The new diagrams isolate correspondence and projection geometry so those ideas can be inspected alongside the original imagery.

Explore the VSLAM experiments ↗

The linked repository requires GitHub access.

with by michael