File size: 23,666 Bytes
8bef16d
43958f9
 
 
 
8bae9ed
 
 
 
5649449
43958f9
3c25cd6
8bae9ed
 
 
 
 
 
 
 
 
 
 
 
 
 
3c25cd6
 
8bae9ed
3c25cd6
 
 
8bae9ed
 
 
 
 
3c25cd6
8bae9ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3c25cd6
8bae9ed
 
 
 
 
 
 
 
 
 
 
 
 
3c25cd6
8bae9ed
 
 
 
 
3c25cd6
8bae9ed
 
 
 
 
3c25cd6
8bae9ed
3c25cd6
8bae9ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3c25cd6
8bae9ed
 
 
3c25cd6
8bae9ed
 
 
3c25cd6
 
 
8bae9ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3c25cd6
8bae9ed
 
 
 
 
 
 
 
 
 
 
 
3c25cd6
 
8bae9ed
 
 
 
 
 
 
 
 
 
 
3c25cd6
8bae9ed
3c25cd6
8bae9ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3c25cd6
8bae9ed
 
3c25cd6
8bae9ed
 
 
 
 
3c25cd6
8bae9ed
 
 
 
3c25cd6
 
8bae9ed
 
3c25cd6
8bae9ed
 
 
 
 
 
 
3c25cd6
8bae9ed
 
 
 
 
3c25cd6
8bae9ed
 
 
 
 
 
 
 
 
 
3c25cd6
 
8bae9ed
 
 
3c25cd6
 
 
 
8bae9ed
 
 
 
3c25cd6
8bae9ed
3c25cd6
 
8bae9ed
 
 
3c25cd6
 
 
 
8bae9ed
 
3c25cd6
8bae9ed
 
 
3c25cd6
8bae9ed
 
 
 
 
 
 
3c25cd6
8bae9ed
 
 
 
 
 
 
 
3c25cd6
8bae9ed
3c25cd6
8bae9ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3c25cd6
8bae9ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3c25cd6
8bae9ed
 
 
 
3c25cd6
8bae9ed
 
 
 
 
 
 
 
 
3c25cd6
43958f9
 
 
8bae9ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66e9000
8bae9ed
 
 
 
 
 
 
 
 
 
 
 
650ec4c
8bae9ed
 
 
 
 
 
 
 
 
 
 
 
6b288f6
 
 
 
8bae9ed
650ec4c
8bae9ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66e9000
8bae9ed
 
 
 
 
 
 
 
66e9000
8bae9ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66e9000
8bae9ed
 
 
 
 
5649449
 
8bae9ed
 
5649449
 
8bae9ed
5649449
 
 
8bae9ed
 
 
5649449
 
8bae9ed
5649449
 
8bae9ed
 
5649449
8bae9ed
 
5649449
8bae9ed
 
 
 
 
 
f327b70
8bae9ed
 
 
5649449
f327b70
 
 
 
 
 
5649449
8bae9ed
5649449
f327b70
 
3c25cd6
f327b70
3c25cd6
 
8bae9ed
 
5649449
f327b70
 
 
5649449
 
 
f327b70
 
 
 
 
 
 
 
 
5649449
8bae9ed
f327b70
8bae9ed
 
 
 
 
 
 
6b288f6
8bae9ed
f327b70
8bae9ed
 
 
 
 
 
 
 
 
 
 
 
3c25cd6
8bae9ed
 
 
 
5649449
 
43958f9
8bef16d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>CVL-PK-001 · Peak-time campus parking occupancy · UD AI Lab</title>
  <link rel="preconnect" href="https://fonts.googleapis.com" />
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
  <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=IBM+Plex+Sans:wght@400;500;600;700&display=swap" rel="stylesheet" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/github-dark.min.css" />
  <style>
    :root {
      --bg: #07090c;
      --panel: #0e1319;
      --panel-2: #121820;
      --line: #243041;
      --line-strong: #3a4d66;
      --ink: #e7edf5;
      --muted: #8b9bb0;
      --accent: #3dd6c6;
      --accent-dim: rgba(61, 214, 198, 0.12);
      --warn: #f0b429;
      --danger: #ff6b6b;
      --ok: #3dd68c;
      --mono: "IBM Plex Mono", ui-monospace, Consolas, monospace;
      --sans: "IBM Plex Sans", system-ui, -apple-system, Segoe UI, sans-serif;
    }
    * { box-sizing: border-box; }
    html { scroll-behavior: smooth; background: var(--bg); }
    body {
      margin: 0;
      color: var(--ink);
      background:
        radial-gradient(1200px 500px at 10% -10%, rgba(61, 214, 198, 0.07), transparent 55%),
        radial-gradient(900px 400px at 90% 0%, rgba(240, 180, 41, 0.04), transparent 50%),
        var(--bg);
      font: 15px/1.55 var(--sans);
    }
    a { color: var(--accent); text-decoration: none; }
    a:hover { text-decoration: underline; }
    .frame { max-width: 1080px; margin: 0 auto; padding: 1rem 1rem 3.5rem; }

    /* Top classification bar */
    .ribbon {
      display: flex; flex-wrap: wrap; gap: .45rem .7rem; align-items: center;
      padding: .55rem .75rem;
      border: 1px solid var(--line);
      background: var(--panel);
      font-family: var(--mono);
      font-size: .68rem;
      letter-spacing: .04em;
      color: var(--muted);
      text-transform: uppercase;
    }
    .ribbon .sep { opacity: .35; }
    .pill {
      display: inline-flex; align-items: center; gap: .35rem;
      padding: .18rem .45rem;
      border: 1px solid var(--line-strong);
      background: var(--panel-2);
      color: var(--ink);
      border-radius: 2px;
    }
    .pill.live { border-color: rgba(61, 214, 198, .45); color: var(--accent); background: var(--accent-dim); }
    .pill.warn { border-color: rgba(240, 180, 41, .45); color: var(--warn); }

    /* Masthead */
    header.mast {
      margin-top: .75rem;
      padding: 1.15rem 1rem 1.25rem;
      border: 1px solid var(--line);
      border-top: none;
      background: linear-gradient(180deg, #10161e 0%, var(--panel) 100%);
    }
    .kicker {
      margin: 0 0 .55rem;
      font-family: var(--mono);
      font-size: .72rem;
      letter-spacing: .12em;
      text-transform: uppercase;
      color: var(--accent);
    }
    .doc-id {
      float: right;
      margin: 0 0 .6rem .8rem;
      padding: .35rem .55rem;
      border: 1px solid var(--line);
      background: var(--bg);
      font-family: var(--mono);
      font-size: .72rem;
      color: var(--muted);
      text-align: right;
      line-height: 1.35;
    }
    h1 {
      margin: 0 0 .45rem;
      font-size: clamp(1.45rem, 2.4vw, 1.85rem);
      font-weight: 600;
      letter-spacing: -0.02em;
      line-height: 1.2;
      color: #f4f7fb;
    }
    .lede {
      margin: 0;
      max-width: 48rem;
      color: var(--muted);
      font-size: .98rem;
    }
    .lede strong { color: var(--ink); font-weight: 500; }

    /* KPI strip */
    .kpis {
      display: grid;
      grid-template-columns: repeat(4, minmax(0, 1fr));
      gap: 1px;
      margin-top: .9rem;
      border: 1px solid var(--line);
      background: var(--line);
    }
    .kpi {
      background: var(--panel-2);
      padding: .65rem .75rem;
    }
    .kpi .l {
      font-family: var(--mono);
      font-size: .65rem;
      letter-spacing: .08em;
      text-transform: uppercase;
      color: var(--muted);
      margin-bottom: .25rem;
    }
    .kpi .v { font-size: .95rem; font-weight: 600; color: var(--ink); }
    .kpi .v em { font-style: normal; color: var(--accent); }

    /* Layout: toc + content */
    .layout {
      display: grid;
      grid-template-columns: 200px minmax(0, 1fr);
      gap: 1rem;
      margin-top: 1rem;
      align-items: start;
    }
    nav.toc {
      position: sticky;
      top: .75rem;
      padding: .75rem;
      border: 1px solid var(--line);
      background: var(--panel);
    }
    nav.toc .t {
      font-family: var(--mono);
      font-size: .65rem;
      letter-spacing: .1em;
      text-transform: uppercase;
      color: var(--muted);
      margin: 0 0 .55rem;
    }
    nav.toc a {
      display: block;
      padding: .28rem 0;
      color: var(--muted);
      font-size: .84rem;
      border-bottom: 1px solid transparent;
    }
    nav.toc a:hover { color: var(--accent); text-decoration: none; }
    nav.toc a span { color: var(--accent); font-family: var(--mono); font-size: .72rem; margin-right: .35rem; }

    article {
      border: 1px solid var(--line);
      background: var(--panel);
      padding: 0;
      min-width: 0;
    }
    section {
      padding: 1.15rem 1.1rem 1.25rem;
      border-bottom: 1px solid var(--line);
    }
    section:last-child { border-bottom: none; }
    h2 {
      margin: 0 0 .7rem;
      font-size: 1.02rem;
      font-weight: 600;
      letter-spacing: -0.01em;
      display: flex;
      align-items: baseline;
      gap: .5rem;
      color: #f4f7fb;
    }
    h2 .n {
      font-family: var(--mono);
      font-size: .78rem;
      color: var(--accent);
      letter-spacing: .04em;
    }
    p { margin: 0 0 .7rem; }
    ul, ol { margin: 0 0 .8rem; padding-left: 1.15rem; }
    li { margin: .28rem 0; }
    ol.proc > li { margin: .65rem 0; }

    figure { margin: .85rem 0 1rem; }
    figure img {
      width: 100%; height: auto; display: block;
      border: 1px solid var(--line);
      background: #000;
    }
    figcaption {
      margin-top: .4rem;
      font-size: .82rem;
      color: var(--muted);
      line-height: 1.4;
    }
    figcaption strong {
      font-family: var(--mono);
      font-size: .72rem;
      letter-spacing: .04em;
      text-transform: uppercase;
      color: var(--accent);
      font-weight: 500;
      margin-right: .35rem;
    }

    table {
      width: 100%;
      border-collapse: collapse;
      font-size: .88rem;
      margin: .45rem 0 .9rem;
    }
    caption {
      caption-side: top;
      text-align: left;
      font-family: var(--mono);
      font-size: .68rem;
      letter-spacing: .06em;
      text-transform: uppercase;
      color: var(--muted);
      margin-bottom: .4rem;
    }
    th, td {
      border-top: 1px solid var(--line);
      border-bottom: 1px solid var(--line);
      padding: .42rem .5rem;
      text-align: left;
      vertical-align: top;
    }
    th {
      background: var(--panel-2);
      color: var(--ink);
      font-weight: 600;
      font-size: .78rem;
      letter-spacing: .03em;
      text-transform: uppercase;
    }
    td.mono, .mono { font-family: var(--mono); font-size: .8rem; }

    .bands {
      display: grid;
      grid-template-columns: repeat(4, minmax(0, 1fr));
      gap: .45rem;
      margin: .55rem 0 1rem;
    }
    .band {
      border: 1px solid var(--line);
      background: var(--panel-2);
      padding: .55rem .6rem;
    }
    .band .r {
      font-family: var(--mono);
      font-size: .68rem;
      color: var(--muted);
      margin-bottom: .15rem;
    }
    .band .n { font-weight: 600; font-size: .92rem; }
    .band.quiet .n { color: var(--ok); }
    .band.mixed .n { color: #8ec8ff; }
    .band.peak .n { color: var(--warn); }
    .band.stress .n { color: var(--danger); }

    .callout {
      margin: .85rem 0 0;
      padding: .7rem .8rem;
      border-left: 3px solid var(--warn);
      background: rgba(240, 180, 41, 0.07);
      border-top: 1px solid var(--line);
      border-right: 1px solid var(--line);
      border-bottom: 1px solid var(--line);
      font-size: .9rem;
    }
    .callout strong { color: var(--warn); }

    code, pre, .hljs { font-family: var(--mono); font-size: .78rem; }
    :not(pre) > code {
      background: #18212c;
      color: #9fe8de;
      padding: .08rem .3rem;
      border-radius: 2px;
      border: 1px solid var(--line);
    }
    pre { margin: .45rem 0 .75rem; }
    pre code {
      border-radius: 2px;
      border: 1px solid var(--line);
      background: #06080b !important;
    }

    .file-row {
      display: flex; flex-wrap: wrap; gap: .45rem;
      margin: .4rem 0 .8rem;
    }
    .file-row a {
      display: inline-block;
      padding: .35rem .55rem;
      border: 1px solid var(--line-strong);
      background: var(--panel-2);
      color: var(--ink);
      font-family: var(--mono);
      font-size: .74rem;
      text-decoration: none;
    }
    .file-row a:hover { border-color: var(--accent); color: var(--accent); }

    footer.colophon {
      margin-top: 1rem;
      padding: .75rem .85rem;
      border: 1px solid var(--line);
      background: var(--panel);
      color: var(--muted);
      font-size: .78rem;
      font-family: var(--mono);
    }

    @media (max-width: 860px) {
      .layout { grid-template-columns: 1fr; }
      nav.toc { position: static; }
      .kpis, .bands { grid-template-columns: 1fr 1fr; }
      .doc-id { float: none; display: block; margin: 0 0 .7rem; text-align: left; }
    }
  </style>
</head>
<body>
<div class="frame">
  <div class="ribbon">
    <span class="pill live">UD AI Lab</span>
    <span class="sep">/</span>
    <span>Campus Vision</span>
    <span class="sep">/</span>
    <span>Parking occupancy</span>
    <span class="sep">·</span>
    <span class="pill">Internal teaching stack</span>
    <span class="pill warn">No enforcement</span>
    <span class="pill">Local inference only</span>
  </div>

  <header class="mast">
    <div class="doc-id">Doc ID CVL-PK-001<br>Rev B · 2026-09-15<br>Static protocol</div>
    <p class="kicker">University of Dubai · Artificial Intelligence Lab · Computer Vision</p>
    <h1>Peak-time campus parking occupancy</h1>
    <p class="lede">
      Measurement brief for a <strong>still-photo occupancy estimate</strong> on an 8&nbsp;GB teaching GPU.
      Counts vehicles with YOLO; optional lot caption with SmolVLM.
      This Space is the <strong>canonical protocol and source tree</strong> — models do not run in the browser.
    </p>
    <div class="kpis">
      <div class="kpi"><div class="l">Sensing</div><div class="v">Still photo / webcam</div></div>
      <div class="kpi"><div class="l">Detector</div><div class="v"><em>YOLOv8s</em> · 1280 px</div></div>
      <div class="kpi"><div class="l">Caption</div><div class="v">SmolVLM-500M</div></div>
      <div class="kpi"><div class="l">Hardware</div><div class="v">≥ 8 GB NVIDIA · local</div></div>
    </div>
  </header>

  <div class="layout">
    <nav class="toc" aria-label="Contents">
      <p class="t">Contents</p>
      <a href="#s0"><span>00</span> Run look</a>
      <a href="#s1"><span>01</span> Concept</a>
      <a href="#s2"><span>02</span> Scope</a>
      <a href="#s3"><span>03</span> Materials</a>
      <a href="#s4"><span>04</span> Procedure</a>
      <a href="#s5"><span>05</span> Code</a>
      <a href="#s6"><span>06</span> Files</a>
      <a href="#s7"><span>07</span> Report</a>
    </nav>

    <article>
      <section id="s0">
        <h2><span class="n">00</span> How a run looks</h2>
        <p>Illustrative figures (not a live capture of a UD lot). Prefer the captions below if burned-in text in the images is imperfect.</p>
        <figure>
          <img src="figures/fig1-experiment-window.png" alt="Figure 1. Local experiment window." />
          <figcaption><strong>Fig 1</strong> Local Gradio window after <code>app.py</code>. Left: lot photo. Right: vehicle boxes. Bottom: count, occupancy, Quiet / Mixed / Peak / Stress.</figcaption>
        </figure>
        <figure>
          <img src="figures/fig2-sample-occupancy.png" alt="Figure 2. Sample occupancy overlay." />
          <figcaption><strong>Fig 2</strong> Example walkway view with boxes and a one-line readout. Your capture will match your campus geometry, not this drawing.</figcaption>
        </figure>
        <figure>
          <img src="figures/fig3-campus-masked-detections.png" alt="Figure 3. Real UD lot capture with vehicle boxes and plate zones masked." />
          <figcaption><strong>Fig 3</strong> Real University of Dubai lot still (field capture). Vehicle boxes only. Plate zones and people are blacked out in the publishable frame — no plate OCR. Safe to host on this Space.</figcaption>
        </figure>
      </section>

      <section id="s1">
        <h2><span class="n">01</span> Concept</h2>
        <p>Peak arrival and class-change windows fill University of Dubai lots. From one still photograph: how many vehicles are visible, and what fraction is that of the stall capacity you assign?</p>
        <pre><code class="language-python">occupancy_pct = min(100, 100 * vehicle_count / stall_capacity)</code></pre>
        <p><code>vehicle_count</code> is YOLO boxes whose COCO class is <code>car</code>, <code>truck</code>, <code>bus</code>, or <code>motorcycle</code>. <code>stall_capacity</code> is typed by the experimenter (whole lot or a counted subsection).</p>
        <div class="bands">
          <div class="band quiet"><div class="r">&lt; 40%</div><div class="n">Quiet</div></div>
          <div class="band mixed"><div class="r">40–74%</div><div class="n">Mixed</div></div>
          <div class="band peak"><div class="r">75–89%</div><div class="n">Peak</div></div>
          <div class="band stress"><div class="r">≥ 90%</div><div class="n">Stress</div></div>
        </div>
        <table>
          <caption>Table 1 · Occupancy flags (lab heuristics, not facilities policy)</caption>
          <tr><th>occupancy_pct</th><th>flag</th><th>ops reading</th></tr>
          <tr><td class="mono">&lt; 40</td><td>Quiet</td><td>Spare capacity</td></tr>
          <tr><td class="mono">40–74</td><td>Mixed</td><td>Normal load</td></tr>
          <tr><td class="mono">75–89</td><td>Peak</td><td>Few stalls left</td></tr>
          <tr><td class="mono">≥ 90</td><td>Stress</td><td>Treat as full / send overflow</td></tr>
        </table>
        <p>Occlusion is part of the write-up. SmolVLM-500M adds two sentences on how full the lot looks. If caption and count disagree, record both.</p>
      </section>

      <section id="s2">
        <h2><span class="n">02</span> What this experiment is not</h2>
        <ul>
          <li>Not a live camera network or cloud fleet.</li>
          <li>Not plate read, face ID, or enforcement.</li>
          <li>Not a model running inside this web page.</li>
        </ul>
      </section>

      <section id="s3">
        <h2><span class="n">03</span> Materials</h2>
        <p>Download experiment files from this Space first. Do not depend on a private disk path on one lab PC.</p>
        <table>
          <caption>Table 2 · Bill of materials</caption>
          <tr><th>Item</th><th>Source</th></tr>
          <tr>
            <td>Experiment files (<code>app.py</code>, <code>requirements.txt</code>, this page)</td>
            <td><a href="https://huggingface.co/spaces/BuildingTHEITGUY/Campus-Vision-Lab/tree/main">Space tree/main</a> ·
                <a href="https://huggingface.co/spaces/BuildingTHEITGUY/Campus-Vision-Lab/resolve/main/app.py">app.py</a> ·
                <a href="https://huggingface.co/spaces/BuildingTHEITGUY/Campus-Vision-Lab/resolve/main/requirements.txt">requirements.txt</a></td>
          </tr>
          <tr><td>Python 3.11+</td><td><a href="https://www.python.org/downloads/windows/">python.org</a> or Microsoft Store Python 3.13</td></tr>
          <tr><td>Git</td><td><a href="https://git-scm.com/download/win">git-scm.com/download/win</a></td></tr>
          <tr><td>huggingface_hub / <code>hf</code> CLI</td><td><a href="https://huggingface.co/docs/huggingface_hub/en/guides/cli">HF Hub CLI</a></td></tr>
          <tr><td>PyTorch CUDA 12.8</td><td><a href="https://pytorch.org/get-started/locally/">pytorch.org</a> · <a href="https://download.pytorch.org/whl/cu128">cu128 wheels</a></td></tr>
          <tr><td>YOLOv8 small</td><td><a href="https://github.com/ultralytics/ultralytics">ultralytics</a> · <code>yolov8s.pt</code> auto-downloads</td></tr>
          <tr><td>SmolVLM-500M-Instruct</td><td><a href="https://huggingface.co/HuggingFaceTB/SmolVLM-500M-Instruct">HuggingFaceTB/SmolVLM-500M-Instruct</a></td></tr>
          <tr><td>Gradio / Transformers</td><td><a href="https://www.gradio.app/">gradio.app</a> · <a href="https://huggingface.co/docs/transformers">transformers</a></td></tr>
          <tr><td>COCO classes</td><td><a href="https://docs.ultralytics.com/datasets/detect/coco/">Ultralytics COCO detect</a></td></tr>
          <tr><td>Photos</td><td>Your own UD lot stills or webcam. No gated third-party driving sets.</td></tr>
        </table>
      </section>

      <section id="s4">
        <h2><span class="n">04</span> Procedure</h2>
        <p>Clone or download this Space into any working directory, then run there.</p>
        <ol class="proc">
          <li><strong>Confirm Python and GPU</strong>
<pre><code class="language-powershell">python --version
nvidia-smi</code></pre>
            Need Python 3.11+ and an NVIDIA GPU. Reference machine: RTX 5070 8&nbsp;GB with CUDA 12.8 wheels.</li>
          <li><strong>Get the experiment from Hugging Face (pick one)</strong>
<pre><code class="language-powershell">git clone https://huggingface.co/spaces/BuildingTHEITGUY/Campus-Vision-Lab
cd Campus-Vision-Lab</code></pre>
            or without git:
<pre><code class="language-powershell">python -m pip install -U huggingface_hub
hf download BuildingTHEITGUY/Campus-Vision-Lab --repo-type space --local-dir Campus-Vision-Lab
cd Campus-Vision-Lab</code></pre>
            Direct: <a href="https://huggingface.co/spaces/BuildingTHEITGUY/Campus-Vision-Lab/resolve/main/app.py">resolve/main/app.py</a>,
            <a href="https://huggingface.co/spaces/BuildingTHEITGUY/Campus-Vision-Lab/resolve/main/requirements.txt">requirements.txt</a>.</li>
          <li><strong>Virtual environment</strong>
<pre><code class="language-powershell">python -m venv .venv
.venv\Scripts\python.exe -m pip install --upgrade pip</code></pre></li>
          <li><strong>Install GPU PyTorch, then requirements</strong>
<pre><code class="language-powershell">.venv\Scripts\python.exe -m pip install torch torchvision --index-url https://download.pytorch.org/whl/cu128
.venv\Scripts\python.exe -m pip install -r requirements.txt</code></pre>
            Plain <code>pip install torch</code> from PyPI may give a CPU wheel.</li>
          <li><strong>Check CUDA</strong>
<pre><code class="language-powershell">.venv\Scripts\python.exe -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'cpu')"</code></pre>
            On the lab 5070 you should see <code>True NVIDIA GeForce RTX 5070 Laptop GPU</code>.</li>
          <li><strong>Start the app</strong>
<pre><code class="language-powershell">.venv\Scripts\python.exe -u app.py</code></pre>
            Open the printed local URL (usually <code>http://127.0.0.1:7860</code>). First click downloads <code>yolov8s.pt</code> and SmolVLM into the machine cache.</li>
          <li><strong>Field capture.</strong> Set lot and window (morning 07:30–09:00, class change, lunch, evening, weekend). Photograph so stalls and empty bays are both visible. Record the capacity you will type.</li>
          <li><strong>UI path:</strong> lot → window → capacity → photo / webcam → Estimate occupancy.</li>
          <li><strong>Notebook:</strong> datetime, lot, window, capacity, counts, occupancy_pct, flag, caption, occlusion note. Repeat the same lot at a second window.</li>
        </ol>
      </section>

      <section id="s5">
        <h2><span class="n">05</span> Code you should understand</h2>
        <p>Measurement in <code>app.py</code>:</p>
<pre><code class="language-python">VEHICLE = {"car", "truck", "bus", "motorcycle"}

for b in result.boxes:
    name = result.names[int(b.cls.item())]
    if name in VEHICLE:
        counts[name] = counts.get(name, 0) + 1
total = sum(counts.values())
occupancy_pct = min(100.0, 100.0 * total / max(1, stall_capacity))</code></pre>
        <p>Detector without Gradio:</p>
<pre><code class="language-python">from ultralytics import YOLO
from PIL import Image

model = YOLO("yolov8s.pt")
im = Image.open("lot.jpg")
r = model.predict(im, verbose=False, conf=0.12, imgsz=1280, classes=[2, 3, 5, 7])[0]
print("vehicles", len(r.boxes), "occupancy%", 100 * len(r.boxes) / 40)</code></pre>
        <p>Default nano at 640&nbsp;px often misses a far or pale car and will box a shade as a table. The app uses small weights, a larger image, and vehicle classes only.</p>
        <p>Optional caption:</p>
<pre><code class="language-python">from transformers import AutoProcessor, AutoModelForVision2Seq
import torch
from PIL import Image

mid = "HuggingFaceTB/SmolVLM-500M-Instruct"
proc = AutoProcessor.from_pretrained(mid)
model = AutoModelForVision2Seq.from_pretrained(mid, torch_dtype=torch.float16).cuda()
im = Image.open("lot.jpg")
messages = [{"role": "user", "content": [
    {"type": "image"},
    {"type": "text", "text": "In two sentences: empty, mixed, or packed? No plates. No faces."},
]}]
text = proc.apply_chat_template(messages, add_generation_prompt=True)
inp = proc(text=text, images=[im], return_tensors="pt")
inp = {k: v.cuda() if hasattr(v, "to") else v for k, v in inp.items()}
out = model.generate(**inp, max_new_tokens=80)
print(proc.batch_decode(out, skip_special_tokens=True)[0])</code></pre>
      </section>

      <section id="s6">
        <h2><span class="n">06</span> Files on this Space</h2>
        <div class="file-row">
          <a href="https://huggingface.co/spaces/BuildingTHEITGUY/Campus-Vision-Lab/resolve/main/app.py">app.py</a>
          <a href="https://huggingface.co/spaces/BuildingTHEITGUY/Campus-Vision-Lab/resolve/main/requirements.txt">requirements.txt</a>
          <a href="https://huggingface.co/spaces/BuildingTHEITGUY/Campus-Vision-Lab/tree/main">tree/main</a>
        </div>
        <div class="callout"><strong>Ethics / ops bound.</strong> Use photos you took of UD lots. Before any public figure: run the app (or the redaction script) so plate zones and people are masked. No plate OCR. No person ID. Not an enforcement decision. Treat Stress as a teaching flag only.</div>
      </section>

      <section id="s7">
        <h2><span class="n">07</span> Report checklist</h2>
        <ol>
          <li>Two photos, same lot, two windows.</li>
          <li>Capacity, and how you got it.</li>
          <li>Counts, occupancy_pct, flag, caption.</li>
          <li>One limitation (occlusion, night, cropped aisle, …).</li>
          <li>One follow-up change.</li>
        </ol>
      </section>
    </article>
  </div>

  <footer class="colophon">
    University of Dubai AI Lab · CVL-PK-001 · MIT for our app code · Ultralytics, SmolVLM, and PyTorch keep their own licenses · Not Waymo / Tesla / RTA affiliated
  </footer>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"></script>
<script>hljs.highlightAll();</script>
</body>
</html>