XCAICX docs Product Contact

Perimeter & border deployments

Turning a fence line, a checkpoint or a restricted area into events, using the same four calls everything else uses. Includes the things that go wrong at 3am, which is when security deployments are actually judged.

Why this SDK suits the work#

Three properties matter more here than anywhere else, and they are the ones this SDK was built around:

PropertyWhy it decides the deal
Inference on the deviceThe site cannot send footage to a vendor. Often it is not allowed to, and often there is no link to do it with.
A real air-gapped pathLicensing that requires a phone-home is licensing that cannot be deployed at a border post or inside an OT boundary. See Air-gapped deployment.
Counts, not imageryWhat leaves is inferences, frames, stream-seconds and events. That list is the entire answer in a security review.

Note

The SDK contains no facial recognition, no biometric matching and no cross-camera re-identification. It detects people, vehicles and objects, tracks them while they are in frame, and reads number plates. That is a deliberate product boundary. For most buyers it shortens the privacy assessment considerably, and it is worth stating explicitly in your own documentation.

The primitives, mapped#

Most of physical security falls out of four calls:

RequirementImplementation
Virtual fence / border linexcaicx_stream_add_line() — directed, so ingress and egress are different events
Restricted or sterile areaxcaicx_stream_add_zone() polygon
Loiteringdwell_seconds on a zone; fires once per visit
Intruder vs vehicle triageDetection classes, with stable track ids
Checkpoint throughputLane zones for occupancy plus ANPR

1. Perimeter intrusion#

A directed tripwire just inside the fence line, not on it.

c
/* Inside the fence, running parallel to it. */
int32_t line_id = -1;
xcaicx_stream_add_line(stream, "north-fence",
                       (xcaicx_point){0.08f, 0.62f},
                       (xcaicx_point){0.94f, 0.48f}, &line_id);
c
if (e->kind == XCAICX_EVENT_LINE_CROSS && strcmp(e->zone_name, "north-fence") == 0) {
    if (strcmp(e->detail, "a_to_b") == 0) alarm_ingress(e->track_id, e->pts_us);
    else                                   log_egress(e->track_id, e->pts_us);
}

Direction is the difference between an alarm and a log line. A patrol walking out should not raise what a breach raises.

Careful

Place the line inside the frame, not at its edge. A track is only confirmed after min_hits (default 3) detections. Something entering at the very edge of the frame can cross a boundary drawn there before it is confirmed, and the crossing is silently missed. Give the tracker a few frames of run-up.

Tuning for a fence line#

SymptomChange
Vegetation and shadows raising alarmsRaise detect_threshold; the reference backend keys on contrast and will find a moving shadow
Animals triggering the lineClasses are aspect-ratio based; filter on class_name == "person" and accept that a crouching person is a harder case
Fast vehicles crossing unseenLower detect_every_n, or raise the frame rate. Do not lower min_hits — that re-admits the false positives you just removed
One intruder raising many alarmsYou are counting detections, not tracks. Alarm on track_id transitions

2. Restricted areas and loitering#

c
const xcaicx_point sterile[] = {
    {0.30f, 0.40f}, {0.92f, 0.34f}, {0.96f, 0.95f}, {0.26f, 0.98f}
};
int32_t zone_id = -1;
xcaicx_stream_add_zone(stream, "sterile-area", sterile, 4,
                       /*dwell_seconds=*/30, &zone_id);

Zone membership is tested at the midpoint of the bottom edge of a track — the ground contact point. Draw zones on the floor plane as they exist in the world; a zone drawn around where a person's torso appears in the image will never trigger.

DWELL_EXCEEDED fires once per visit. Someone crossing the area produces enter and exit; someone stopping in it produces enter, dwell, and later exit. That distinction is usually the whole alarm policy.

3. Border segment monitoring#

The same tripwire, with two differences in practice:

  • Group crossings. Each person is a track with an id, so a group is a countable set of LINE_CROSS events rather than one. Deduplicate on track_id, not on time.
  • Long, shallow fields of view. Objects are small at range. Analysis runs at 320px on the long side, so a person who occupies fewer than roughly ten pixels of height at that scale will not be detected. That is a lens, mounting and camera-count question, not a tuning one — work it out before installation rather than after.

Do not

Do not solve small-object detection by feeding 4K. Frames are downscaled to 320px for analysis regardless, so the extra resolution costs conversion time and buys nothing. Solve it with focal length, camera placement, or more cameras.

4. Vehicle checkpoints#

c
cfg.modules = XCAICX_MODULE_DETECT | XCAICX_MODULE_ANPR;

Plate localisation runs on any build. Reading the characters requires a production build with the text model — the reference backend returns the plate box with empty text and detail = "plate_candidate". Check for that in bring-up so you do not mistake a working pipeline for a working reader.

c
for (size_t i = 0; i < res->detection_count; ++i) {
    const xcaicx_detection *d = &res->detections[i];
    if (d->source != XCAICX_MODULE_ANPR) continue;
    if (d->text && d->text[0]) check_against_list(d->text, d->text_score);
    else                       log_plate_seen_but_unread(d->box);
}

Add a zone per lane for occupancy and dwell, and the same frames produce throughput reporting with no extra hardware.

5. Night, thermal and IR#

Detection is luma-based and runs on XCAICX_PIX_GRAY8 with no special handling — a thermal or IR stream works.

Careful

PPE compliance does not work on a monochrome sensor. Its helmet and hi-vis tests are colour-ratio tests, and on GRAY8 they have nothing to work with; the result is violations reported indiscriminately. If the site is thermal-only, do not license PPE. Detection, defect inspection and plate localisation are unaffected.

6. Unmanned and remote sites#

Substations, pipeline stations, relay huts, remote border posts.

c
cfg.license_path = "/etc/xcaicx/unit.token";   /* minted offline, device-bound */
cfg.state_dir    = "/var/lib/xcaicx";          /* persistent, survives reboot */
cfg.offline      = 1;                          /* never opens a socket */

Build with -DXCAICX_WITH_TLS=OFF and the HTTP client is not linked into the binary at all — a claim the customer's own security team can verify with ldd and strings rather than taking your word for it.

Usage still accrues to state_dir/usage-spool.jsonl for collection on a service visit. See Air-gapped deployment for the provisioning and renewal workflow, and plan the licence term against the site's maintenance schedule rather than the calendar — an annual term on a site reachable once a year gives you a zero-day margin.

7. Sizing and placement, before you install#

The questions that decide whether a deployment works, in the order they bite:

  1. Pixels on target. At 320px analysis, how tall is a person at the far end of the field of view? Under ~10px and the answer is a different lens or another camera.
  2. Where does the tracker get its run-up? Boundaries need a few frames of visible approach.
  3. What is the frame budget? Measure total_ms on the real board with the real model and a busy scene. An empty corridor is cheap and tells you nothing.
  4. Is state_dir genuinely persistent? On a read-only rootfs, confirm it is a real writable overlay and not tmpfs — otherwise every reboot re-activates and consumes a unit.
  5. What happens when analytics stop? The video path must keep recording. A camera that stops recording because a licence lapsed is a warranty claim.

8. What this is not#

Do not

  • Not a safety interlock. If a machine must stop when someone reaches into it, that is a rated safety controller's job. Analytics inform people.
  • Not a targeting or weapons input, and not licensed for use as one.
  • Not an identity system. No faces, no biometrics, no re-identification.
  • Not accurate out of the box. The reference backend is a deterministic heuristic for bring-up and CI. A fence line at night needs real models validated on your own footage, in your own lighting. Anyone quoting an accuracy figure before seeing your site is quoting you someone else's.

Next#

Commercial software. Use requires a valid XCAICX licence token. Questions an integrator cannot answer from this page belong in an email to [email protected] — and, usually, in a fix to this page.

© 2026 AZMX AI · xcaicx.com