Skip to content
NAMEFRAMEApply for Pilot

How to place objects for rare cases in a synthetic dataset

The strongest argument for a rendered corpus is not that frames are cheap. It is that you can produce the ones nobody can collect: the near miss, the obstruction in the wrong place, the object class that appears twice a year. Getting them requires placing things on purpose, which is a different skill from scattering them randomly and hoping.

The real value
Frames a camera would wait years for
The method
Rules, not hand placement
The trap
A scatter with a signature in it
What to keep
A record of why each object is there

Rare is the point, and rare does not happen by accident

A real corpus contains what the camera happened to see. That is why the interesting cases are missing from it: they are interesting because they are rare, and rare means the collection did not catch them. Waiting is the only way to get more, and waiting is what a rendered scene removes.

But a scene does not produce a rare case because it can. It produces whatever you asked for, and if you asked for uniform random placement over a surface you will get uniform random placement over a surface, forever, in quantity. The frames worth having come from stating the situation you want and letting the rules produce variations of it.

The signature a naive scatter leaves

Uniform random placement is not what the world looks like, and a model notices. Three artefacts show up in almost every first attempt.

Impossible spacing. Real objects have physical extent and do not interpenetrate, and people in particular keep a distance from each other that is cultural rather than physical. A scatter with no minimum spacing produces pairs standing closer than any two strangers ever stand.

Impossible ground. Placing on a surface means placing on the surface actually under the point, not at a fixed height. Objects float above slopes and sink into them, and every one of those frames teaches a detector something false about scale.

Impossible uniformity. Real scenes cluster. People gather at entrances, vehicles queue, animals herd. A perfectly even spread over an area is a distribution a detector can learn to expect, and it will not hold outside your data.

An aerial frame of an airfield with vehicles, containers and crates spread across concrete, positioned on the ground surface rather than at a uniform height
Rendered frameMap_Airbase_Demo, frame 000004Unreal Engine 5.8, 1920×1080

Rules worth having

The useful controls are the ones that encode a physical or social fact rather than a preference.

A surface, not a height

Trace down and place on what is there. An object that finds no ground under it should be refused rather than dropped at a guess, because a floating object is a wrong label rather than a missing one.

A minimum distance

Measured between footprints rather than between pivots. Two pivots a metre apart can be two shapes overlapping, depending entirely on what the shapes are.

A slope limit

Nothing stands on a cliff. A ceiling on the ground angle removes a whole family of frames that look plausible in a thumbnail and are absurd close up.

A distance between classes

The rule that produces rare cases on purpose: a person within two metres of a moving vehicle is the frame a safety model needs and the one no dataset has.

Re-placing between frames, and what it costs

Moving everything before every frame maximises variety per frame captured, and it has a consequence worth understanding: consecutive frames are no longer a sequence. Nothing is tracked, nothing persists, and any temporal model will find the corpus useless.

If you want tracking, place once and move the camera. If you want variety, re-place each frame. Wanting both from one capture is the most common way a corpus ends up serving neither.

There is a subtler cost too. Frames that share a scene tend to look alike, and near-duplicate images split across training and validation make a model look better than it is. Whichever way you go, check for it before you trust a validation score.

Record why each object is there

The question that comes up three weeks later is always the same: why does frame 173 look like that. A manifest per frame answers it. What was asked for, what was accepted, what was rejected and for which rule.

The rejection counts are the part people skip and the part that pays. Asking for forty people and getting nine, silently, produces a sparse dataset with no explanation attached. The same run with a manifest says the minimum spacing rejected thirty-one attempts, and that is a number you can act on in a minute.

Doing it with NameFrame

Placement zones are authored in the level or declared in the job, each with its own rules, its own asset pool and its own class. Every frame writes a manifest of what was requested, what was placed and what was refused, with the reason.

population:
  spawn_zones:
    - name: pavement_north
      shape: rectangle
      center_m: [12, 4, 0]
      size_m: [30, 6]
      asset_pool: pedestrians
      count: 24
      require_ground_hit: true
      min_spacing_m: 0.9
  inter_class_distances:
    - id: person-near-vehicle
      from: person
      to: vehicle
      min_distance_m: 2

What the rules are and what they produced on a real run is set out on the placement page, with the manifests from the reference capture.