RegionKit Open Editor →
OpenCV detection zones Python computer vision polygon zones

How to Define Detection Zones in OpenCV Python

Learn how to define polygon detection zones in OpenCV using Python — draw them with RegionKit, export the coordinates as JSON, and use cv2.fillPoly and cv2.pointPolygonTest to filter detections to your zones.

· RegionKit

When you deploy an object detector in a real environment, you rarely want it to watch the entire frame. A camera pointed at a building entrance doesn’t need to detect people walking past on the distant street. A factory camera monitoring a conveyor belt doesn’t need to track movement in the maintenance corridor behind it.

The solution is to define detection zones — polygons that tell your system where detections should count. This article walks through the complete workflow: drawing zones in RegionKit, exporting polygon coordinates, and using OpenCV to apply them in Python.

The basic pattern

The workflow has three steps:

  1. Load a still frame from your camera
  2. Draw zone polygons on that frame using RegionKit
  3. In your inference loop, filter detections to those that fall inside a zone polygon

OpenCV provides two key functions for this:

Drawing zones in RegionKit

Export a still frame from your camera feed (most CV pipelines have a way to save individual frames). Open RegionKit, drag the frame onto the canvas, and use the Polygon tool (P) to draw your zones.

For each zone:

  1. Press P to activate the polygon tool
  2. Click each vertex of the zone boundary
  3. Double-click or press Enter to close the polygon
  4. Open the Properties panel and set a label (e.g. "entrance", "conveyor_section_a")

Use layers to separate zone types — Detection zones on one layer, Exclusion zones on another. This makes the JSON easier to filter in code.

When finished, click Export → Native JSON and save the file.

Loading zone polygons in Python

import json
import numpy as np

with open('scene.json') as f:
    scene = json.load(f)

# Extract all visible polygon annotations
zones = {}
for ann in scene['annotations']:
    if ann['type'] != 'polygon':
        continue
    if not ann.get('visibility', True):
        continue

    label = ann.get('label', 'unlabelled')
    pts = ann['data']['points']  # flat [x0,y0, x1,y1, ...]
    coords = np.array(list(zip(pts[::2], pts[1::2])), dtype=np.int32)
    zones[label] = coords

print(f"Loaded {len(zones)} zone(s): {list(zones.keys())}")

Creating zone masks with cv2.fillPoly

For pixel-level zone checking (useful for segmentation or dense prediction), create a binary mask:

import cv2

frame_h, frame_w = 480, 640  # your frame dimensions

# Build one mask per zone
zone_masks = {}
for label, pts in zones.items():
    mask = np.zeros((frame_h, frame_w), dtype=np.uint8)
    cv2.fillPoly(mask, [pts], 255)
    zone_masks[label] = mask

To check if a pixel (x, y) is inside the zone:

if zone_masks['entrance'][y, x] > 0:
    print("Point is inside the entrance zone")

Filtering detections with cv2.pointPolygonTest

For bounding box detections, test whether the detection centroid falls inside a zone:

def is_in_zone(cx, cy, zone_polygon):
    """Returns True if point (cx, cy) is inside the zone polygon."""
    result = cv2.pointPolygonTest(zone_polygon, (float(cx), float(cy)), False)
    return result >= 0  # 0 = on boundary, >0 = inside, <0 = outside

# In your detection loop:
for det in detections:
    x1, y1, x2, y2 = det['bbox']
    cx = (x1 + x2) / 2
    cy = (y1 + y2) / 2

    for zone_label, zone_pts in zones.items():
        if is_in_zone(cx, cy, zone_pts):
            print(f"Detection in zone: {zone_label}")

Handling exclusion zones

If you have exclusion zones (areas to ignore), apply them as a second filter:

for ann in scene['annotations']:
    if ann.get('label', '').startswith('exclusion'):
        pts = ann['data']['points']
        exclusion_zones.append(np.array(list(zip(pts[::2], pts[1::2])), dtype=np.int32))

def is_excluded(cx, cy):
    return any(
        cv2.pointPolygonTest(zone, (float(cx), float(cy)), False) >= 0
        for zone in exclusion_zones
    )

Scaling zones to different resolutions

Zone coordinates in RegionKit are in image pixels relative to the loaded image. If your inference frame is a different resolution, scale the coordinates before use:

scale_x = inference_w / scene_w
scale_y = inference_h / scene_h

scaled_pts = (zone_pts * [scale_x, scale_y]).astype(np.int32)

The scene image dimensions are available in the RegionKit export under imageWidth and imageHeight — or you can read them from the original image using cv2.imread.

Complete example

import json
import cv2
import numpy as np

# Load zones
with open('scene.json') as f:
    scene = json.load(f)

zones = {}
for ann in scene['annotations']:
    if ann['type'] == 'polygon' and ann.get('visibility', True):
        pts = ann['data']['points']
        zones[ann.get('label', 'zone')] = np.array(
            list(zip(pts[::2], pts[1::2])), dtype=np.int32
        )

# Open camera
cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()
    if not ret:
        break

    # Draw zone overlays
    for label, pts in zones.items():
        cv2.polylines(frame, [pts], isClosed=True, color=(99, 102, 241), thickness=2)
        cv2.putText(frame, label, pts[0], cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 1)

    cv2.imshow('Zones', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

Draw your zones in RegionKit, export the JSON, and drop it into this script. No manual coordinate entry needed.


Related: How to Define Regions of Interest for Computer Vision · COCO Format Guide

Try RegionKit — it's free

Browser-based ROI editor. No install, no account, no data upload.

Open the Editor