Skip to content

Find a patch in another image

CookbookMotion and matching

Draw a patch on the first image and locate its best matching position in the second image.

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 / 1Selected patch170 × 240
Selected patch: The first-image selection is the template searched for in the second frame.

The first-image selection is the template searched for in the second frame.

STEP 01 / 03

Crop the selected patch

Explore the algorithm →
Mat.roimeanStdDev

Extract the first-image rectangle as the template.

Receives
Your rectangle in the first grayscale frame.
Passes to the next step
A textured grayscale template with a fixed width and height.

Why this step? Cropping preserves the exact texture to search for. The standard-deviation check rejects almost uniform patches: normalized correlation needs variation, and a flat patch has little distinctive information.

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

If a patch keeps its appearance and size, finding it is a search over translations. Compare the patch with every same-sized window in the next image, then interpret the resulting score map.

  1. 01

    Crop the selected patch

    Mat.roimeanStdDev

    Cropping preserves the exact texture to search for. The standard-deviation check rejects almost uniform patches: normalized correlation needs variation, and a flat patch has little distinctive information.

    Receives
    Your rectangle in the first grayscale frame.
    Passes on
    A textured grayscale template with a fixed width and height.
  2. 02

    Search the next image

    matchTemplateTM_CCOEFF_NORMED

    Normalized, mean-centred correlation compares spatial patterns with less sensitivity to a uniform brightness offset or scale. It evaluates every valid top-left placement. The score map is smaller than the image because the whole template must fit inside each candidate window.

    Receives
    The template and second grayscale frame.
    Passes on
    A floating score map indexed by candidate template top-left positions.
  3. 03

    Mark the strongest response

    minMaxLocrectangle

    The maximum identifies the best candidate, but even unrelated images have a maximum. The acceptance threshold decides whether to draw a rectangle; preserving the score lets you assess how convincing that candidate is.

    Receives
    The correlation map and original template dimensions.
    Passes on
    An accepted rectangle in the second frame, or a below-threshold result without a box.

Tune and diagnose

Choose the parameters

Choose a distinctive patch that includes texture but little independently moving background. Raise the minimum score when false matches are common. If the object rotates or changes scale, use feature matching or region tracking instead of expecting the threshold to compensate.

Read the result

Inspect the correlation map. One isolated peak is more useful than several similar peaks from repeated windows, tiles or text. Map coordinates refer to the patch top-left, not its centre.

Try it with your images

Choose an input image and a second image. Without uploads, the lab uses a labelled synthetic pair. Use “Draw a region” and drag a rectangle on the input, or enter its coordinates. 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 ↗

Draw a patch on the first image and locate its best matching position in the second image.

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

Works best without rotation, scale changes or substantial appearance changes. A low score still has a maximum and is not proof of a match.

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 {
  COLOR_BGR2GRAY,
  Mat,
  TM_CCOEFF_NORMED,
  cvtColor,
  matchTemplate,
  meanStdDev,
  minMaxLoc
} 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.
// rect is an in-bounds { x, y, width, height } rectangle in processed pixels.
// "using" releases native handles at scope exit; inspect or copy outputs before then.

// 1. Allocate grayscale views of the two frames; matching uses brightness patterns.
using beforeGray = new Mat(), afterGray = new Mat()
// Convert the image containing your selected template to grayscale.
cvtColor(image, beforeGray, COLOR_BGR2GRAY)
// Convert the image we will search to the same representation.
cvtColor(nextImage, afterGray, COLOR_BGR2GRAY)
// roi selects the exact patch without resizing it; it shares the source storage.
// The scores destination will hold one float per possible top-left placement.
using template = beforeGray.roi(rect), scores = new Mat()
// Allocate outputs for the patch mean and standard deviation.
using mean = new Mat(), deviation = new Mat()
// Measure variation: a nearly uniform patch has no distinctive pattern to locate.
meanStdDev(template, mean, deviation)
// Reject a patch varying by less than one grayscale level (8-bit range 0..255).
if (deviation.data64F[0] < 1) throw new Error('Select a textured patch')
// 2. Slide the patch across the second image and compare mean-centred patterns.
// TM_CCOEFF_NORMED gives normalized correlation, with higher scores more similar.
matchTemplate(afterGray, template, scores, TM_CCOEFF_NORMED)
// 3. Find the strongest score and its template top-left position, not its centre.
const { maxLoc, maxVal } = minMaxLoc(scores)
// Accept only a score of at least 0.6. This cutoff is a choice, not a probability;
// even unrelated images have a maximum, and repeated patterns can have many peaks.
if (maxVal >= 0.6) {
  // The patch width/height plus this position define its candidate rectangle.
  console.log('Template top-left:', maxLoc, 'score:', maxVal)
}

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