Keep a subject sharp
Select the subject, separate it with GrabCut, then blend it over a blurred version of the image.
The pipeline

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

Inside the orange rectangle is possible foreground. Outside supplies known background to initialize GrabCut.

Definite and probable foreground become white.

A smoothed layer is used only outside the foreground mask.

This feathered boundary controls compositing; it does not recover mixed foreground colours.

Foreground is blended over the blurred background using the soft mask.
Separate the subject
Explore the algorithm →grabCutGrabCut creates a foreground mask from the rectangle.
- Receives
- The image and a rectangle around the subject.
- Passes to the next step
- A binary subject mask.
Why this step? GrabCut estimates a subject mask from foreground/background colour models and the rectangle constraint. Retaining definite and probable foreground yields a binary selection that controls where sharp pixels survive.
Blur the surroundings
Explore the algorithm →GaussianBlurGaussian filtering produces the background layer.
- Receives
- The full colour image.
- Passes to the next step
- A blurred colour layer with the same dimensions as the original.
Why this step? Gaussian blur creates a smooth alternative layer. Computing the blur over the whole image gives each background pixel a complete neighbourhood, but it also means subject colours can spread into that layer near boundaries.
Blend with the mask
Explore the algorithm →GaussianBlurAlpha-weighted compositingA softened mask keeps foreground details sharp.
- Receives
- The original, blurred layer and subject mask.
- Produces
- A composite with the selected foreground sharp and its surroundings blurred.
Why this step? A small blur of the mask creates a gradual transition. For each channel the lab computes alpha × original + (1 - alpha) × blurred. The mask, not the blur algorithm, determines which regions stay sharp.
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
Separating where an effect applies from how the effect is computed makes many image edits composable. Compute a subject mask, create a blurred alternative image, then use the mask to choose between the two.
- 01
Separate the subject
grabCutGrabCut estimates a subject mask from foreground/background colour models and the rectangle constraint. Retaining definite and probable foreground yields a binary selection that controls where sharp pixels survive.
- Receives
- The image and a rectangle around the subject.
- Passes on
- A binary subject mask.
- 02
Blur the surroundings
GaussianBlurGaussian blur creates a smooth alternative layer. Computing the blur over the whole image gives each background pixel a complete neighbourhood, but it also means subject colours can spread into that layer near boundaries.
- Receives
- The full colour image.
- Passes on
- A blurred colour layer with the same dimensions as the original.
- 03
Blend with the mask
GaussianBlurAlpha-weighted compositingA small blur of the mask creates a gradual transition. For each channel the lab computes alpha × original + (1 - alpha) × blurred. The mask, not the blur algorithm, determines which regions stay sharp.
- Receives
- The original, blurred layer and subject mask.
- Passes on
- A composite with the selected foreground sharp and its surroundings blurred.
Tune and diagnose
Choose the parameters
Tune the rectangle and GrabCut mask before the blur strength. Sigma sets the spatial blur scale in processed pixels. Strong blur makes segmentation mistakes more visible, especially around thin structures.
Read the result
Use the mask and blurred-layer stages to distinguish segmentation errors from blur behaviour. Subject-colour spill and mask mistakes can produce halos; this simple composite is not a depth-aware lens simulation.
Try it with your images
Choose your own image or start with the built-in sample. 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.
Experiment at pixel level
Select the subject, separate it with GrabCut, then blend it over a blurred version of the image.
The engine loads on your first run. Your images stay in this browser.
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
Select a pixel
Select a pixel
Assumptions and limits
Imperfect masks can blur subject edges or retain background patches. This is mask-based blur, not an optical depth-of-field simulation.
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 {
GC_FGD,
GC_INIT_WITH_RECT,
GC_PR_FGD,
GaussianBlur,
Mat,
grabCut
} from '@banou/opencv-wasm'
// The engine is already initialized; image is an 8-bit BGR Mat.
// 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 GrabCut labels and its background/foreground colour-model buffers.
// Those model Mats hold learned statistics, not preview images.
using mask = new Mat(), background = new Mat(), foreground = new Mat()
// Initialize from rect: outside is background, inside is possible foreground.
// Run three refinement iterations. Keep the entire subject inside the rectangle.
grabCut(image, mask, rect, background, foreground, 3, GC_INIT_WITH_RECT)
// 2. Reuse the label Mat as a binary mask for compositing.
for (let i = 0; i < mask.data.length; i++) {
// Read this pixel's four-state GrabCut label before replacing it.
const label = mask.data[i]
// White (255) retains definite/probable foreground; black (0) means background.
mask.data[i] = label === GC_FGD || label === GC_PR_FGD ? 255 : 0
}
// 3. Allocate a replacement layer with blurred surroundings.
using output = new Mat()
// Use sigma 8 pixels. A zero kernel size lets OpenCV choose it from sigma.
// Blur the whole image first so neighbourhoods extend beyond the subject boundary.
GaussianBlur(image, output, { width: 0, height: 0 }, 8)
// Restore original sharp pixels wherever the foreground mask is nonzero.
// This is a hard selection; the full lab uses a softened alpha-weighted transition.
image.copyTo(output, mask)The snippets isolate the core operations. The complete runnable recipes also include validation, filtering, overlays, intermediate previews and resource cleanup.