Skip to content

Visualize verified feature matches

CookbookMotion and matching

See which ORB descriptor matches agree with one estimated projective transform.

Try the recipe ↓

The pipeline

VISUAL WALKTHROUGHMotion and matching
Follow the images, then read what passes to the next algorithm.
STARTING IMAGEFirst frame448 × 320
The unchanged source image. All steps use this same example.

The unchanged source image. All steps use this same example.

STEP 01 · 1 / 1Detected ORB features896 × 320
Detected ORB features: Circles mark detected features in each frame. Each feature also has a binary descriptor; correspondence has not been established yet.

Circles mark detected features in each frame. Each feature also has a binary descriptor; correspondence has not been established yet.

STEP 01 / 03

Extract ORB features

Explore the algorithm →
ORB.createdetectAndCompute

Detect and describe both images.

Receives
Two grayscale images.
Passes to the next step
Keypoint vectors and binary descriptor matrices.

Why this step? ORB produces repeatable keypoints and compact binary descriptions. Keeping coordinates beside each descriptor matters: descriptors support appearance matching, while coordinates support the later geometry check.

Actual OpenCV 5.0.0 results on the illustrated sample, using the lab’s default algorithm settings. Masks, overlays and normalized fields are labelled previews; the data contracts above describe what the algorithms really exchange. Try this chain with your images ↓

Why this chain works

A descriptor match says two patches look alike. A verified match also agrees with a shared spatial transformation. Comparing candidate and verified links teaches which kind of evidence each stage contributes.

  1. 01

    Extract ORB features

    ORB.createdetectAndCompute

    ORB produces repeatable keypoints and compact binary descriptions. Keeping coordinates beside each descriptor matters: descriptors support appearance matching, while coordinates support the later geometry check.

    Receives
    Two grayscale images.
    Passes on
    Keypoint vectors and binary descriptor matrices.
  2. 02

    Match descriptors

    BFMatcherNORM_HAMMING

    Mutual best matching reduces one-sided ambiguous matches. Sorting by Hamming distance and retaining up to 200 candidates gives the geometry fit a stronger starting set, but appearance alone can confuse repeated patterns.

    Receives
    Both descriptor matrices.
    Passes on
    Candidate descriptor matches, each linking one first-image point to one second-image point.
  3. 03

    Verify geometry

    findHomographyRANSACdrawMatches

    RANSAC searches for a homography supported by a subset of the pairs. Its inlier mask selects which links to draw, letting you distinguish appearance candidates from geometrically consistent evidence. Unlike the alignment recipe, this recipe stops at correspondence visualization.

    Receives
    Candidate coordinate pairs.
    Passes on
    A side-by-side image with lines connecting inlier keypoints, plus an inlier count.

Tune and diagnose

Choose the parameters

Try a stricter RANSAC tolerance to see weak correspondences disappear, then inspect whether enough well-spread evidence remains. More features can help coverage but can also add repeated or low-quality candidates.

Read the result

Useful inliers span the overlapping scene and follow one coherent mapping. Many nearly coincident points or repeated motifs can support a misleading model. A high inlier count alone does not establish that the images were aligned correctly.

Try it with your images

Choose an input image and a second image. Without uploads, the lab uses a labelled synthetic pair. Run the recipe, then use the stage buttons to inspect intermediate results without rerunning it.

YOUR IMAGE · REAL OPENCV

Experiment at pixel level

Open full lab ↗

See which ORB descriptor matches agree with one estimated projective transform.

The engine loads on your first run. Your images stay in this browser.

Input448 × 320
OutputWaiting for a result

Scroll over either image to zoom at the pointer. Use the scrollbars to pan both views over the same relative area. Zoom is relative to the input; pixel coordinates belong to each image. Warps can change scene correspondence.

Pixel inspector RGBA · native values · matched scale · 9 × 9 output pixels
Hover to inspect. Click to pin a pixel.
Input
Select a pixel

Output
Select a pixel

Sample models and licenses

Assumptions and limits

Geometric consistency is stronger than descriptor similarity, but repeated patterns can still produce a wrong transform.

TypeScript core chain

Initialize the shared engine once with await initOpenCV(), then use these named imports. In a bundled browser app, pass the WASM URL as shown in the quickstart. image is an 8-bit BGR Mat from that same engine; paired recipes receive an equally sized nextImage. Region recipes use an in-bounds pixel rect. Read outputs before the using scope ends. See matrix ownership.

import {
  BFMatcher,
  DMatchVector,
  KeyPointVector,
  Mat,
  NORM_HAMMING,
  ORB_create,
  drawMatches
} from '@banou/opencv-wasm'

// The engine is already initialized; image is an 8-bit BGR Mat.
// nextImage is the equally sized second frame from the same engine.
// "using" releases native handles at scope exit; inspect or copy outputs before then.

// 1. ORB detects up to 800 oriented features and binary descriptors.
// Hamming distance compares descriptor bits; true enables mutual-best cross-checking.
using orb = ORB_create(800), matcher = new BFMatcher(NORM_HAMMING, true)
// Factories can return null, so check before using the detector.
if (!orb) throw new Error('ORB factory failed')
// Store each image's feature coordinates separately from its descriptor rows.
using first = new KeyPointVector(), second = new KeyPointVector()
// a/b will hold descriptors; an empty mask allows features anywhere in the image.
using a = new Mat(), b = new Mat(), mask = new Mat()
// Detect keypoints in the first image and write their descriptors into a.
orb.detectAndCompute(image, mask, first, a)
// Do the same for the second image; descriptor row i belongs to keypoint i.
orb.detectAndCompute(nextImage, mask, second, b)
// 2. Allocate match records and the combined visualization image.
using matches = new DMatchVector(), output = new Mat()
// Find mutual-best matches only when both descriptor sets contain features.
if (!a.empty() && !b.empty()) matcher.match(a, b, matches)
// 3. Place the images side by side and connect the proposed keypoint pairs.
// These lines show descriptor similarity, not yet verified geometric agreement.
drawMatches(image, first, nextImage, second, matches, output)
// This is the candidate view. RANSAC in the full recipe rejects inconsistent matches.

The snippets isolate the core operations. The complete runnable recipes also include validation, filtering, overlays, intermediate previews and resource cleanup.