Skip to content

Measure contour geometry

CookbookRegions and masks

Threshold a silhouette, simplify its outline, and report each retained shape’s area, perimeter, circularity and centroid.

Try the recipe ↓

The pipeline

VISUAL WALKTHROUGHRegions and masks
Follow the images, then read what passes to the next algorithm.
STARTING IMAGEOriginal sample448 × 320
The unchanged source image. All steps use this same example.

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

STEP 01 · 1 / 1Foreground mask448 × 320
Foreground mask: Foreground pixels used for external contour extraction.

Foreground pixels used for external contour extraction.

STEP 01 / 03

Extract silhouettes

Explore the algorithm →
threshold

Threshold grayscale pixels.

Receives
A grayscale view with a useful foreground intensity separation.
Passes to the next step
A binary silhouette mask.

Why this step? Thresholding defines the silhouette whose geometry you will measure. Moving the threshold moves the boundary, so later precision in area or centroid does not compensate for an inaccurate mask.

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

Geometry should be measured on a chosen silhouette, not on arbitrary image texture. Turn foreground into outlines, simplify those outlines for a readable drawing, then compute measurements from the original contours.

  1. 01

    Extract silhouettes

    threshold

    Thresholding defines the silhouette whose geometry you will measure. Moving the threshold moves the boundary, so later precision in area or centroid does not compensate for an inaccurate mask.

    Receives
    A grayscale view with a useful foreground intensity separation.
    Passes on
    A binary silhouette mask.
  2. 02

    Find and simplify contours

    findContoursapproxPolyDP

    External contours convert the raster boundary into point sequences. Polygon approximation replaces small boundary wiggles with fewer segments for display. The tolerance is a fraction of perimeter so it scales with contour size; tiny contours are filtered by area.

    Receives
    The silhouette mask.
    Passes on
    Original contour point lists and simplified display polygons.
  3. 03

    Measure geometry

    contourAreaarcLengthmoments

    Area and perimeter describe size and boundary length. Moments give the centroid as m10/m00 and m01/m00. Circularity, 4πA/P², combines area and perimeter to indicate how compact the outline is. The lab measures the original contours, not the simplified drawing.

    Receives
    Original contours that pass the area cutoff.
    Passes on
    Pixel area, pixel perimeter, circularity and centroid for each retained shape.

Tune and diagnose

Choose the parameters

Set threshold and minimum area first. Change polygon tolerance to make the outline easier to interpret; it should not change the reported measurements in this recipe. Physical measurements require calibration and a suitable view of the measured plane.

Read the result

A contour around a shadow measures that shadow. External-only retrieval also omits interior holes from the measured shape model. Compare the silhouette and centroid with the intended object before using the numbers.

Try it with your images

Choose your own image or start with the built-in sample. 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 ↗

Threshold a silhouette, simplify its outline, and report each retained shape’s area, perimeter, circularity and centroid.

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

Measurements are in processed-image pixels, not physical units. Perspective and resolution affect them.

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 {
  CHAIN_APPROX_SIMPLE,
  COLOR_BGR2GRAY,
  Mat,
  MatVector,
  RETR_EXTERNAL,
  THRESH_BINARY,
  arcLength,
  contourArea,
  cvtColor,
  findContours,
  threshold
} from '@banou/opencv-wasm'

// The engine is already initialized; image is an 8-bit BGR Mat.
// "using" releases native handles at scope exit; inspect or copy outputs before then.

// 1. Allocate brightness, a binary silhouette and contour hierarchy metadata.
using gray = new Mat(), mask = new Mat(), hierarchy = new Mat()
// A MatVector will hold each extracted contour as its own coordinate matrix.
using contours = new MatVector()
// Define the silhouette through brightness rather than colour.
cvtColor(image, gray, COLOR_BGR2GRAY)
// Select bright foreground above 127; this decision defines the measured boundary.
threshold(gray, mask, 127, 255, THRESH_BINARY)
// 2. RETR_EXTERNAL keeps outer silhouettes and ignores interior holes.
// CHAIN_APPROX_SIMPLE compresses straight boundary runs to their endpoints.
findContours(mask, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE)
// Measure each silhouette independently.
for (let i = 0; i < contours.size(); i++) {
  // get() returns an owned handle; using releases that handle after this iteration.
  using contour = contours.get(i)!
  // Area is enclosed contour area in pixels squared. arcLength(..., true)
  // measures a closed boundary perimeter in pixels.
  const area = contourArea(contour), perimeter = arcLength(contour, true)
  // Ignore contours smaller than 80 px². Circularity 4*pi*area/perimeter²
  // describes compactness (an ideal circle has value 1); these are not physical units.
  if (area >= 80) console.log({ area, perimeter, circularity: 4 * Math.PI * area / perimeter ** 2 })
}

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