System designTroubleshooting

Detection ROI crop out of bounds: clamp before you crop

When a detection ROI runs out of bounds at the frame edge, the crop stage can crash the app. Clamp coordinates to 0.001-0.999 first, with a worked example.

LumaSpec Vision8 min read Share on LinkedIn

On this page 8 sections
  1. 01The symptom: it only crashes at the frame edge
  2. 02Likely causes, most probable first
  3. 03The fix: clamp every rectangle to 0.001-0.999 before the crop
  4. 04Worked example: a face leaving the left edge of a 1920 × 1080 frame
  5. 05After any SDK or firmware update, re-run the edge test
  6. 06Where the clamp lives in your pipeline
  7. 07Checks before you call it fixed
  8. 08Questions

A tracked face or object walks toward the camera, reaches the left or right edge of the frame, and the whole application dies with a critical error instead of reporting a missed detection. The log names the image preprocessing stage and says nothing about coordinates, which makes it look like a camera fault. The real cause is almost always a detection rectangle that ran out of bounds and was handed to the crop stage unchanged. Here is how to confirm that cause and fix it with one clamp.

The symptom: it only crashes at the frame edge

Detections in the middle of the frame run for hours. The crash arrives exactly when a face or part crosses the left or right boundary, and it reproduces on every unit of the same camera model, so the hardware is not the variable. The log reports a critical fatal error from the image preprocessing stage, with a line number and no hint that a rectangle left the image.

The reason is simple: the crop stage receives a rectangle that extends past the sensor's valid pixel area and treats it as a fatal error rather than clipping it to the frame. A detection that is half out of view is still a valid detection; an out-of-range crop is not, and in this pipeline it stops the whole process instead of failing one frame. Because the error text never says "out of bounds", teams chase firmware and cables first. Probing the stages in order, as in the blank image, no pixels checklist, lands you on the crop call quickly. The companion problem, cropping when you do not know where the region sits, is covered in crop an image ROI when the corner coordinates are unknown.

Likely causes, most probable first

  1. The detection rectangle crosses the frame edge. A coordinate goes negative or above 1.0 in normalized terms. Test: log all four coordinates every frame and inspect the frame logged immediately before the fatal error.
  2. Rounding pushes a valid rectangle one pixel outside. A rectangle clamped to exactly 0.0 or 1.0 can be rounded past the boundary when the crop stage converts to pixels, especially after scaling. Test: convert to pixels and compare against width − 1 and height − 1.
  3. A stale rectangle from a previous configuration. Coordinates captured before a resolution or camera ROI change map outside the new frame. Test: change the ROI on a running system and watch the logged boxes.
  4. A crop stage without built-in clipping. Some on-camera image-manipulation stages raise an error on any out-of-range rectangle instead of clipping it. Test: feed a deliberately out-of-range rectangle to the crop stage in a bench script; if it faults, the clamp below is mandatory on every build.

The fix: clamp every rectangle to 0.001-0.999 before the crop

Clamp each normalized coordinate into a window slightly inside the frame before the rectangle reaches the crop stage:

x_clamped = min(max(x, 0.001), 0.999) y_clamped = min(max(y, 0.001), 0.999)

Use 0.001 to 0.999 as the window. The inset is not decoration: on a frame 1920 pixels wide, 0.001 is 1.92 pixels, so the clamped rectangle sits about two pixels inside the boundary and survives integer rounding. Clamping to exactly 0.0 and 1.0 leaves no margin, and one rounding step can push the rectangle out again.

Apply it in one helper that every detection path calls:

def clamp_norm(v: float, lo: float = 0.001, hi: float = 0.999) -> float:
    return min(max(v, lo), hi)

# Example detection rectangle from the network, frame 1920 x 1080
xmin: float = -0.04
ymin: float = 0.32
xmax: float = 0.41
ymax: float = 0.88
box = (clamp_norm(xmin), clamp_norm(ymin), clamp_norm(xmax), clamp_norm(ymax))
assert box == (0.001, 0.32, 0.41, 0.88)  # edge value pulled inside, interior values unchanged

One helper, called always, not a patch at the two call sites where you happened to see the crash. The habit generalizes: anywhere pipeline results index into a fixed-size table, an out-of-range value faults the same way, which is why controls engineers keep an array index out of bounds reference for PLC tables at hand.

Worked example: a face leaving the left edge of a 1920 × 1080 frame

Inputs: the detector reports a normalized rectangle with xmin = −0.04, ymin = 0.32, xmax = 0.41, ymax = 0.88 (example values for a face half out of frame on the left), the preview is 1920 × 1080 pixels, the clamp window is 0.001 to 0.999, and the classifier working on the crop needs at least 64 × 64 pixels, per its input dimensions.

The rule: clamp all four values into the window, then multiply by the frame dimensions to check the pixel rectangle.

The arithmetic:

  • xmin: max(−0.04, 0.001) = 0.001, and 0.001 × 1920 = 1.92, about 2 px
  • xmax: 0.41 × 1920 = 787.2, about 787 px, so the crop width is (0.41 − 0.001) × 1920 = 785 px
  • ymin: 0.32 × 1080 = 345.6, about 346 px
  • ymax: 0.88 × 1080 = 950.4, about 950 px, so the crop height is (0.88 − 0.32) × 1080 = 605 px

Result: the rectangle from (2, 346) to (787, 950) lies inside the valid pixel range of 0 to 1919 by 0 to 1079, so the crop stage accepts it and returns the partially visible face.

Decision: 785 × 605 px clears the 64 × 64 px gate easily, so process the detection. When a face is 90 percent out of frame, the same clamp yields a sliver below the gate, so drop that detection for the frame and let the tracker re-acquire. The pixel side of this conversion is worked through in ROI pixel coordinate extraction, and bounding box area vs object area explains which measure to gate on.

After any SDK or firmware update, re-run the edge test

A newer build that removes the crop limitation is welcome, but treat it as a change to a running machine. In one real case, a build that fixed the out-of-bounds crash stopped attaching depth to detections, and the spatial coordinates of every detection read 0.00: the loud failure was gone and a quiet one had taken its place. Your own clamp costs nothing and protects every build, so keep it in place on the fixed release too, and after each update re-run the edge test and check every output field, not just the one that crashed.

Mounting gets the same check. A camera rotated 90 degrees swaps width and height, so a rectangle clamped against the unrotated dimensions can still fall outside the frame once the crop stage applies its rotation, and the crop can come back without the object in it. Clamp against the dimensions of the frame as the crop stage sees it, then confirm the crop content. Clamping inputs to a valid range before processing is the same pattern as clamping depth range on a 3D camera before the point cloud is built.

Where the clamp lives in your pipeline

Two placements cover every set-up. If detection runs on a PC, clamp in the grab loop immediately after the detections arrive, before any crop call downstream. If detection and crop run on the camera itself, the clamp belongs in the on-camera script, immediately before the crop node, because that is where the fatal error fires. Smart cameras and vision sensors are built for exactly this arrangement, inspecting on the device with no PC in the loop.

Smart cameras & vision sensorsHikrobot MV-SC5060XM-08M-WBN SC5000X series Smart Camera, 6 MP, Mono, 8 mm focal length, M12-mountMV-SC5060XM-08M-WBN
Interface
GigE
Resolution
6-10 MP
$1,629.00View part
Smart cameras & vision sensors1.6 MP smart camera, 60 fps, 16 mm lens, white light (polarized, transparent light) (LS-SMC-0063)LS-SMC-0063
Interface
GigE
Resolution
Up to 3 MP
$1,110.00View part

Both cards above run the inspection on the camera. If you would rather keep detection on a PC and rebuild around an area scan camera, the camera finder filters by interface, resolution and shutter, and the configurator steps through camera, lens, light and controller in order.

Checks before you call it fixed

  • Log the raw coordinates every frame, before clamping, so the evidence survives the fix.
  • Walk a target out of the frame on all four sides at production speed; the pipeline must degrade to a skipped detection, never a crash.
  • Gate on minimum crop size after the clamp, sized to the model's input.
  • Test any rotated mount at its production angle and confirm the crop contains the object.
  • After every SDK or firmware update, repeat all of the above and inspect every detection field, including spatial coordinates.
  • Keep one clamp helper on the only path between detection and crop; delete the per-call patches.

Fixed this way, an object leaving the frame costs one skipped detection, not a dead application. The systems topic page collects the rest of the pipeline-stage guides, and the area scan camera category is the starting point if the hardware side needs a rebuild.

Questions

Why clamp to 0.001-0.999 instead of 0 to 1?

The tiny inset keeps the rectangle inside the valid pixel range after the crop stage rounds to whole pixels. On a 1920 pixel wide frame the inset is 1.92 pixels, so it costs almost nothing. A rectangle clamped to exactly 0 or 1 can be rounded one pixel past the edge again, which recreates the same fatal error.

Should I clamp the box or drop the detection when the object leaves the frame?

Do both, in order. Clamp first so the crop stage always receives a valid rectangle, then apply a minimum-size gate: if the clamped crop is smaller than the model's input, skip that detection for the frame. The tracker re-acquires the object as more of it re-enters the view, and nothing crashes at any position.

How do I confirm the crash is an out-of-bounds crop and not a hardware fault?

Log the four normalized coordinates of every detection. If a value below 0 or above 1 appears in the frame logged just before the fatal error, the crop rectangle is the cause. The failure also reproduces only when the object sits at the edge, which rules out a defective camera unit.

Does the same clamp cover the top and bottom edges?

Yes. Apply the identical clamp to the vertical coordinates against the frame height, and to all four values before any camera-side crop. If the camera is mounted rotated by 90 degrees, width and height swap, so clamp against the dimensions of the frame as the crop stage sees it, then convert to pixels.

Is updating the SDK alone a safe fix?

An update can remove the crop limitation, but it can change behaviour elsewhere: in one real case, a build that fixed the crash stopped attaching depth to detections and the spatial coordinates read 0.00. Keep your own clamp in the pipeline regardless of build, and re-run the edge test plus the output checks after every update.