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

This model is trained on Places365 photographs. It has now been tested against 1,684 frames of fixed-camera hospital-room video, where every frame is a patient room, so the correct answer is "yes" on all of them:

variant says "patient room"
64Γ—64 17.5%
256Γ—256 11.0%

It calls 83–89% of genuine hospital rooms not a patient room. 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. That advice was based on held-out Places365 validation (0.689 β†’ 0.741 balanced accuracy), which is real but did not predict deployment: on camera footage the 256 px model is worse than the 64 px one it was meant to replace. In-domain improvement and deployment behaviour pointed in opposite directions here.

The numbers further down remain accurate for photographs, which is the domain they were measured in. Use this model on photographic inputs, or validate it on your own footage first.

Test caveat: the footage is generated rather than filmed, and contains one room and roughly two people, so it cannot measure cross-ward generalisation. But the ground truth is certain and a 17.5% score is not rescued by that.

clinical-scene-nano

Two scene rungs, two input resolutions. 47,122 parameters each. 188 KB. 64Γ—64 at ~3,000 fps, or 256Γ—256 at ~220 fps β€” the 256 variant is substantially more accurate.

hospital_room.onnx β€” is this a patient room, as opposed to a bedroom, hotel room, dorm or nursing home? clinical_space.onnx β€” is this a clinical space (hospital / hospital room / operating room / nursing home) rather than a domestic one?

Read this before the numbers

These are trained on Places365, which is handheld photographs, not camera footage. A wall- or ceiling-mounted camera sees wider, higher, emptier and worse-lit scenes than a person with a phone does. That deployment gap is UNMEASURED. If you point this at a real room, you are running an experiment.

Operations, not diagnosis. This answers "what kind of space is the camera looking at" β€” a routing and context question. It says nothing about anyone in the room, and nothing clinical.

Not a medical device. Nothing here is validated for clinical use.

The hard negatives are the whole design

"Clinical space vs the outdoors" is trivial and worth nothing. The question that matters for a camera is whether a room containing a bed is a patient room or somebody's bedroom. So V2b's negatives are bedroom, hotel_room, dorm_room and nursing_home β€” same furniture, same layout, same lighting. "There is a bed in this image" wins nothing here.

Resolution: predicted first, then measured

The discriminating cues here sit at very different physical scales. In a room ~4,000 mm across, a 64Γ—64 input renders them at:

cue mm @64 px @256 px
hospital bed 2000 32.0 128.0
IV pole 1800 28.8 115.2
bed rails 900 14.4 57.6
patient monitor 400 6.4 βœ— 25.6
wall gas outlets 300 4.8 βœ— 19.2
IV bag 250 4.0 βœ— 16.0
call button / cord 150 2.4 βœ— 9.6

βœ— = below the ~8 px classifiability threshold.

The prediction, recorded before testing: at 64Γ—64 this model cannot see monitors, gas outlets, IV bags or call cords β€” the cues that most strongly separate a hospital room from a bedroom β€” so it must be leaning on bed shape and room layout, and should gain substantially at higher resolution.

Measured, on the official val split:

model 64Γ—64 256Γ—256
hospital_room (hard task) 0.689 0.741
clinical_space (broad task) 0.764 0.784

The hard task gains more (+0.052) than the broad one (+0.020), which is what the prediction implies: telling a patient room from a bedroom needs the small clinical cues, while telling a clinical space from a domestic one is separable on large-scale differences that were already visible at 64 px.

The margin over the cheap baseline nearly triples, because global statistics cannot use extra pixels:

resolution nano cheap baseline margin
64 0.6400 0.6122 +0.0278
128 0.6839 0.6161 +0.0678
256 0.6989 0.6200 +0.0789

For photographic input, use the 256 variant unless severely compute-bound β€” but see the warning at the top: on camera footage it is worse than the 64 px model, and neither is validated there. 4.5 ms per frame is ~220 fps, and a scene classification only needs running once a minute β€” room identity changes rarely.

Results β€” official Places365 validation split, untouched by training

Balanced accuracy (mean of per-class recall), because V2b's val set is 100 positives against 400 negatives and plain accuracy would reward a model for always answering "not a hospital room".

model val balanced face-free random-split (3 seeds) cheap baseline majority
hospital_room 0.689 0.682 0.676 Β± 0.008 0.589 0.500
clinical_space 0.764 0.759 0.756 Β± 0.007 0.628 0.500

The cheap baseline is the stronger of a transferred single threshold and a ~66-parameter logistic regression over ten cheap image statistics, both fitted on train and evaluated on test. A single threshold alone is too weak a bar to be honest about.

The shortcut audit β€” corrected, and stronger than the first version

Places365's clinical classes skew heavily toward images containing people. A model could score well by learning "photograph containing a person", and that model would be useless on a camera watching an empty room β€” the actual use. So the models are re-scored on images with no detected person.

This audit was first run with a Haar face cascade and that was too weak. Frontal-face detection fired on 17% of hospital_room; a proper person detector (YOLOv8n-pose) finds a person in 76%. The face-based audit therefore left most people-containing images in the "face-free" set, and the conclusion it supported was much thinner than it appeared. Redone with person detection:

person in positives person in negatives all person-free person-present
hospital_room 76% 38% 0.689 0.670 (n=273, 24 pos) 0.676
clinical_space 64% 27% 0.764 0.798 (n=437, 146 pos) 0.716

The conclusion survives the stronger test. hospital_room loses 0.019 with every detected person removed, and clinical_space gets better (0.764 β†’ 0.798) β€” it performs worse on the people-heavy subset, which is the opposite of a people shortcut.

One honest weakness: the hospital_room person-free figure rests on 24 positive images. That is a thin basis for a headline claim, and it is reported rather than rounded away. clinical_space's 146 positives make its person-free number the more trustworthy of the two.

Prior art

Scene recognition on Places365 is mature and well-studied β€” Zhou et al., Places: A 10 Million Image Database for Scene Recognition (TPAMI 2017), with ResNet-class models reaching roughly 55% top-1 on the full 365-way problem at tens of millions of parameters. This is not that task and the numbers are not comparable: these are binary problems over 5–8 hand-picked classes at ~1/500th the parameters. Binary hospital_room-vs-bedrooms is not a standard benchmark, so there is no published SOTA to hold this against, and the only honest comparison is the cheap baseline on the identical split β€” which is what the table reports.

Nothing about the architecture is novel. What is offered here is the packaging: hard negatives chosen so the task cannot be won on furniture, an explicit shortcut audit, and a stated refusal to claim the deployment transfer has been measured.

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("hospital_room.onnx", sess_options=so,
                            providers=["CPUExecutionProvider"])

im = cv2.imread("room.jpg")                       # BGR, any size
x = cv2.resize(im, (64, 64), interpolation=cv2.INTER_AREA).astype(np.float32) / 255.0
x = (x - x.mean()) / (x.std() + 1e-6)             # per-image standardisation, as trained
x = x.transpose(2, 0, 1)[None]

logits = sess.run(None, {"image": x})[0]
print("patient room" if logits.argmax() == 1 else "not a patient room")

Input is BGR as OpenCV loads it, standardised per image. Feeding RGB will degrade it silently.

Where this sits in a cascade

V0  camera-health-nano     is the frame usable?          (published separately)
V2  clinical_space.onnx    what kind of space is this?
V2b hospital_room.onnx     patient room, or just a bedroom?

A scene rung is a natural always-on tier because a room's identity changes rarely β€” run it once a minute, not once a frame.

Limitations

  • Photographs, not camera views. The single largest unmeasured risk.
  • 0.689 balanced on the hard task is modest. It is well above the 0.589 cheap baseline and well above chance, and it is not close to reliable on a single frame. Aggregate over many frames.
  • waiting_room is absent from the negatives: the Places365 train archive truncated before w/. A medical waiting room may therefore classify unpredictably.
  • Trained at 64x64. Fine detail that distinguishes clinical from domestic furniture at a glance β€” rails, monitors, IV poles β€” is largely destroyed at this resolution.
  • Binary only. A room that is neither clinical nor domestic gets forced into one of two answers.
  • Places365 reflects the geographic and economic distribution of its web-sourced photographs. Wards that do not look like that distribution are not represented.

Known failure modes, measured

  • People skew, not room skew. A person detector finds someone in 76% of hospital_room images against 38% of the bed-room negatives. Re-scoring on images with no detected person costs only 0.019 (0.689 β†’ 0.670), so the model is reading rooms β€” but the person-free subset contains just 24 positives, which is thin for a headline claim.
  • Small clinical cues are invisible at 64Γ—64. Patient monitors land on 6.4 px, wall gas outlets 4.8 px, IV bags 4.0 px β€” all below the ~8 px threshold. The 64 px variant is therefore leaning on bed shape and layout, which is why the 256 px variant gains +0.052.
  • waiting_room is absent from the negatives (the Places365 train archive truncated before w/), so medical waiting rooms may classify unpredictably.
  • Single-frame balanced accuracy of 0.741 is a triage signal. Aggregate over frames.
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