⚠ Not validated on camera footage β€” and the 256 px recommendation is withdrawn

This model is trained on Places365 photographs. Tested against 1,684 frames of fixed-camera hospital-room video containing a gowned patient in nearly every frame, with staff in scrubs entering in a minority:

variant patient fires staff fires visitor fires
64Γ—64 0.4% 19.2% 4.1%
256Γ—256 5.6% 1.7% 68.8%

It essentially never detects the patient, and at 256 px labels 68.8% of frames visitor β€” street clothes that appear nowhere in the footage. Neither variant is validated on wall- or ceiling-mounted camera footage, and neither should be relied on for it.

The recommendation to prefer the 256 px variant is withdrawn. It was based on Places365 validation (mask AP 0.401 β†’ 0.587), which is real but did not predict deployment: on camera footage the 256 px model is worse, and its visitor head fails catastrophically.

The numbers further down remain accurate for photographs. Use this model on photographic inputs, or validate on your own footage first.

Test caveat: generated rather than filmed footage, one room, roughly two people β€” so it cannot measure cross-ward generalisation. The ground truth is nonetheless certain.

clinical-attire-nano

47,252 parameters. 189 KB. Two input resolutions β€” 64x64 at 2,800 fps, or 256x256 at 219 fps. Four independent heads: staff Β· patient Β· visitor Β· mask

Answers "who is in this room, and is a mask being worn" from a 64Γ—64 frame β€” fast enough to run on every frame of a video stream on a CPU.

Domain measured / deployment domain tested: measured on Places365 handheld photographs with VL-model labels; deployment domain: TESTED on fixed-camera frames and NOT validated there; see the notice above. (Fifth line of the card standard, added 2026-09-02: a number is only as good as the domain it was measured in.)

Read this first: the labels are machine-generated

No human labelled this data. There is no public dataset for scrubs, hospital gowns or lab coats β€” Fashionpedia has none of the 46 categories, and searches return only face-mask corpora and construction PPE. So the labels were produced by qwen2.5vl:7b on Places365 clinical and domestic scenes:

  • Every image asked twice with different wording; only agreeing answers kept β€” 2,966 of 4,000 (74%).
  • Cleaned against an independent person detector (yolov8n-pose, sharing no failure mode with the VL model): images where the two disagreed on whether a person is present were dropped. 229 removed, 2,737 kept.
  • A 16-image hand audit put teacher accuracy at roughly 78%.

This model therefore cannot exceed a ~78%-accurate teacher, and every number below measures agreement with that teacher rather than with reality. Treat it as a fast approximation of qwen2.5vl:7b at 1/150,000th the parameters, not as a validated classifier.

Results β€” and pick your resolution

Two variants ship, identical in every way except input size. Nano global-average-pools, so the parameter count is 47,252 at both; only the pixels differ.

clinical_attire.onnx (64Γ—64) clinical_attire_256.onnx (256Γ—256)
latency, 1 CPU thread 0.36 ms (2,800 fps) 4.56 ms (219 fps)
staff AP 0.466 0.605
patient AP 0.382 0.479
visitor AP 0.491 0.604
mask AP 0.401 0.587

For photographic input, use 256Γ—256 unless severely compute-bound β€” but see the warning at the top: on camera footage the 256 px variant is worse, and neither variant is validated there. 219 fps is still 7Γ— what a 30 fps camera needs, and the accuracy gain is large β€” mask improves most (+0.186), which is expected, since a surgical mask is a handful of pixels at 64Γ—64 and a recognisable object at 256Γ—256.

The margin roughly doubles, because the baseline cannot use the pixels

Margin over the cheap baseline (best of ten cheap statistics and the three raw channel means β€” colour is included deliberately, since scrubs are teal and lab coats white):

head margin @64 margin @256 cheap AP @64 β†’ @256
staff +0.140 +0.278 0.326 β†’ 0.327
patient +0.193 +0.256 0.189 β†’ 0.223
visitor +0.188 +0.303 0.302 β†’ 0.300
mask +0.121 +0.305 0.280 β†’ 0.282

The cheap baseline is flat with resolution β€” global aggregates wash out detail however many pixels they are given β€” while the model gains steadily. Higher resolution is exactly where a learned model earns its keep over a threshold.

Full sweep, constant parameters

resolution ms fps staff patient visitor mask
64 0.31 3,200 0.476 0.376 0.510 0.439
128 1.16 859 0.540 0.413 0.537 0.506
192 2.62 382 0.574 0.471 0.589 0.542
256 4.51 222 0.610 0.477 0.595 0.596

Still rising at 256, and 256 is the ceiling of the DATA, not of the method β€” Places365-Standard ships at 256Γ—256. A 720p deployment offers more detail than these labels can describe, and whether the trend continues past 256 is unmeasured. Do not extrapolate it.

The cheap baseline is the best of ten cheap image statistics and the three raw channel means, with threshold direction fitted on train β€” colour is included deliberately, because scrubs are solid teal and lab coats are white, and a model that only beat a greyscale baseline would be winning on colour it has no credit for.

Training set: 2,737 images; positives 575 staff, 361 patient, 524 visitor, 276 mask.

Where to put the camera β€” computed, not guessed

Whether a feature is answerable depends on how many pixels it spans, and that follows from physical size. A face mask is ~150 mm on a ~1700 mm person; a patient gown is ~1200 mm. Roughly 8 px on the feature is the threshold for classifiability, 16 px comfortable.

This model's training photos are portraits β€” a person fills a median 81% of frame height (measured with a pose detector over 472 labelled images). A wall camera sees nothing like that, so the table below is what matters for deployment.

Pixels on feature at 720p, by how much of the frame height a person occupies:

feature mm portrait 81% seated 45% bedside 25% corner 13% wide ward 7%
patient gown 1200 412 229 127 66 36
street clothes 700 240 133 74 39 21
lab coat 900 309 172 95 50 27
scrubs top 500 172 95 53 28 15
face mask 150 52 29 16 8 4 βœ—
ID badge 85 29 16 9 5 βœ— 3 βœ—
wristband 60 21 11 6 βœ— 3 βœ— 2 βœ—
nasal cannula 6 2 βœ— 1 βœ— 0.6 βœ— βœ— βœ—

βœ— = under 8 px, not answerable. Bold = marginal.

What follows, without running anything:

  • Role and attire work from any realistic room camera at 720p. Gowns, scrubs and street clothes are large features; even a wide ward view keeps them above threshold.
  • Mask compliance needs the person at β‰₯13% of frame height at 720p. A wide ward view will not support it. A bedside or doorway camera will.
  • Wristbands and ID badges are marginal even at bedside framing β€” 6–9 px. Do not build on them.
  • IV lines and nasal cannulae are hopeless from a room camera at any practical resolution. Putting 8 px on a 6 mm cannula at bedside framing needs a 9,067-pixel-tall sensor. That is not a model problem and no amount of training fixes it; it needs a bedside close-up, a different sensor, or a different approach entirely.

This also explains the resolution result above: between a 64 and 256 px input, face mask is the only feature that crosses the 8 px threshold (4.6 β†’ 18.2 px). It gained most (+0.186). The others were already above it and gained less. The law predicted the ordering before it was measured.

Prior art: this is Johnson's criteria, rediscovered

The ~8 px threshold above was derived empirically from average-precision curves. It then turned out to match Johnson's criteria (John Johnson, 1958), the standard used in surveillance and thermal optics for over half a century:

task Johnson (1958) measured here
detection β€” something is there 2 px β€”
recognition β€” what kind of thing 8 px ~8 px
identification β€” which specific one 12.8 px β€”

The empirical threshold for "can a CNN classify this attribute" lands on Johnson's recognition value. That convergence is worth stating plainly: the principle is not new, and credit belongs to Johnson.

What is offered here is the application rather than the principle β€” Johnson's criteria describe a human observer detecting or recognising a whole object, whereas the numbers above are a CNN classifying fine-grained attributes of an object it is already looking at, validated per-attribute against training support as a confound. The zoom calculation and the a-priori camera spec follow from that, and the fact that a 1958 optics rule predicts modern CNN behaviour this well is arguably the more useful finding.

Scope: operations, never diagnosis

Who is present and whether PPE is worn are staffing, workflow and compliance questions. This model says nothing clinical about any person, and cannot β€” it sees a 64Γ—64 thumbnail. Not a medical device.

The taxonomy came from an audit, and the audit changed it

The first class list said "hospital gown". Inspecting labelled examples by eye showed its only failures were staff in blue surgical gowns labelled as such β€” correct English, operationally backwards, since a clinician's sterile gown and a patient's gown mean opposite things. The heads below separate the evidence and report role:

staff     scrubs, surgical gown, lab coat
patient   patient gown
visitor   street clothes
mask      orthogonal β€” a compliance signal, not a role

Usage

import numpy as np, onnxruntime as ort, cv2

so = ort.SessionOptions(); so.intra_op_num_threads = 1
so.add_session_config_entry("session.intra_op.allow_spinning", "0")   # else it burns cores idling
sess = ort.InferenceSession("clinical_attire_256.onnx", sess_options=so,   # or the 64x64 variant
                            providers=["CPUExecutionProvider"])
RES = 256                                          # must match the file you loaded

HEADS = ["staff", "patient", "visitor", "mask"]
frame = cv2.imread("room.jpg")                    # BGR, any size
x = cv2.resize(frame, (RES, RES), interpolation=cv2.INTER_AREA).astype(np.float32) / 255.0
x = ((x - x.mean()) / (x.std() + 1e-6)).transpose(2, 0, 1)[None]

logits = sess.run(None, {"image": x})[0][0]
probs = 1 / (1 + np.exp(-logits))                 # independent sigmoids, NOT a softmax
print(dict(zip(HEADS, probs.round(3))))

Input is BGR, per-image standardised. Heads are independent β€” a room can contain staff and a patient and a visitor at once, which 180 training images do.

Aggregate over frames. Single-frame AP of 0.34–0.49 is a triage signal, not a decision. On video, average across a second or more.

Known failure modes, measured

  • Hallucinated attire: 3.9% of attire claims had no person detected by the independent detector (patient_gown worst at 7.1% β€” bedding mistaken for a gown; lab_coat 0%). Those were removed from training but the tendency is inherited.
  • Missed people: 12.3% of "nobody visible" labels did contain a detected person.
  • Oxygen masks count as mask. The audit found a child on a nebuliser labelled mask-positive. For PPE-compliance use this is a real confusion: infection control and respiratory support are opposite situations.
  • Places365 contains illustrations. One audited example was a cartoon of nurses. Drawings are in the training set.
  • Trained on photographs, not camera footage. A wall-mounted camera sees wider, higher, emptier scenes; that gap is unmeasured.
  • Resolution matters more than anything else here, for photographs. On camera footage the ordering reverses β€” see the warning at the top. At 64Γ—64 a mask is a few pixels; the 256Γ—256 variant lifts mask AP from 0.401 to 0.587 at the same parameter count. If you can afford 4.56 ms, use it.

The labels are published too

resoajoe/clinical-attire-labels β€” all 4,000 rows including the 1,034 where the two prompts disagreed, with both raw answers retained so you can re-parse or re-adjudicate rather than take my parsing on trust.

Related

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support