Marcel0123 commited on
Commit
cec87a1
·
verified ·
1 Parent(s): c81f7d6

Upload 3 files

Browse files
Files changed (3) hide show
  1. README.md +5 -8
  2. app.py +117 -0
  3. requirements.txt +2 -0
README.md CHANGED
@@ -1,13 +1,10 @@
1
  ---
2
- title: Human Behavior
3
- emoji: 🌍
4
- colorFrom: pink
5
- colorTo: gray
6
  sdk: gradio
7
- sdk_version: 5.49.1
8
  app_file: app.py
9
  pinned: false
10
- license: mit
11
  ---
12
-
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Behavioral ML in Virtual Crowds
3
+ emoji: 🧍‍♀️
4
+ colorFrom: blue
5
+ colorTo: red
6
  sdk: gradio
7
+ sdk_version: "5"
8
  app_file: app.py
9
  pinned: false
 
10
  ---
 
 
app.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math, random, time
2
+ from dataclasses import dataclass, field
3
+ from typing import List, Optional, Tuple
4
+ import gradio as gr
5
+ from PIL import Image, ImageDraw
6
+
7
+ W, H = 900, 540
8
+ ROOM = (60, 40, W - 60, H - 40)
9
+ DT = 0.05
10
+ MAX_SPEED_BASE = 65.0
11
+ PERSON_RADIUS = 6
12
+ EXIT_W, EXIT_H = 28, 68
13
+ C_BG = (245, 246, 248, 255)
14
+ C_ROOM = (250, 250, 250, 255)
15
+ C_BORDER = (28, 28, 28, 255)
16
+ C_OBS = (175, 178, 185, 255)
17
+ C_EXIT = (52, 132, 255, 255)
18
+ C_CALM = (44, 184, 78, 255)
19
+ C_ALERT = (250, 191, 35, 255)
20
+ C_PANIC = (233, 68, 68, 255)
21
+ C_INCIDENT = (230, 60, 60, 96)
22
+
23
+ RUNNING = False
24
+
25
+ @dataclass
26
+ class Person:
27
+ x: float; y: float; vx: float; vy: float
28
+ stress: float = 0.0; state: int = 0; evacuated: bool = False
29
+ def color(self): return [C_CALM, C_ALERT, C_PANIC][self.state]
30
+
31
+ @dataclass
32
+ class ExitZone:
33
+ x: int; y: int; w: int = EXIT_W; h: int = EXIT_H
34
+ def rect(self): return (self.x, self.y, self.x + self.w, self.y + self.h)
35
+
36
+ @dataclass
37
+ class World:
38
+ width: int = W; height: int = H; room: Tuple[int,int,int,int] = ROOM
39
+ people: List[Person] = field(default_factory=list)
40
+ exits: List[ExitZone] = field(default_factory=list)
41
+ incident: Optional[Tuple[int,int,int]] = None
42
+ speed_scale: float = 1.0; cohesion: float = 0.3; separation: float = 0.6
43
+ panic_spread: float = 2.0; personal_space: float = 22.0
44
+
45
+ def step(self, dt: float):
46
+ def nearest_exit_vec(px, py):
47
+ best=None; best_d2=1e12
48
+ for ex in self.exits:
49
+ cx, cy = ex.x + ex.w/2, ex.y + ex.h/2
50
+ dx, dy = cx - px, cy - py
51
+ d2 = dx*dx + dy*dy
52
+ if d2 < best_d2: best_d2, best = d2, (dx, dy)
53
+ return best or (0.0, 0.0)
54
+
55
+ for p in self.people:
56
+ if p.evacuated: continue
57
+ gx, gy = nearest_exit_vec(p.x, p.y)
58
+ p.vx += gx*0.002; p.vy += gy*0.002
59
+ v = math.hypot(p.vx, p.vy)
60
+ vmax = MAX_SPEED_BASE*self.speed_scale
61
+ if v > vmax: p.vx, p.vy = p.vx/v*vmax, p.vy/v*vmax
62
+ p.x += p.vx*dt; p.y += p.vy*dt
63
+ for ex in self.exits:
64
+ x0, y0, x1, y1 = ex.rect()
65
+ if x0 <= p.x <= x1 and y0 <= p.y <= y1:
66
+ p.evacuated = True
67
+
68
+ def render(self):
69
+ img = Image.new("RGBA", (self.width, self.height), C_BG)
70
+ d = ImageDraw.Draw(img, "RGBA")
71
+ d.rectangle(self.room, fill=C_ROOM, outline=C_BORDER, width=3)
72
+ for ex in self.exits:
73
+ d.rectangle(ex.rect(), fill=C_EXIT)
74
+ d.text((ex.x+6, ex.y+ex.h/2-7), "Exit", fill=(255,255,255,255))
75
+ for p in self.people:
76
+ if not p.evacuated:
77
+ d.ellipse((p.x-4, p.y-4, p.x+4, p.y+4), fill=p.color())
78
+ return img
79
+
80
+ def make_world(n_people=200):
81
+ w = World()
82
+ ex1 = ExitZone(x=ROOM[2]-8-EXIT_W, y=int(ROOM[1]+70))
83
+ ex2 = ExitZone(x=ROOM[2]-8-EXIT_W, y=int(ROOM[3]-70-EXIT_H))
84
+ w.exits = [ex1, ex2]
85
+ for _ in range(n_people):
86
+ w.people.append(Person(random.randint(100, 700), random.randint(100, 400), 0, 0))
87
+ return w
88
+
89
+ def reset_fn(n_people):
90
+ w = make_world(int(n_people))
91
+ return w.render(), w
92
+
93
+ def start_fn(world):
94
+ global RUNNING; RUNNING = True
95
+ while RUNNING:
96
+ world.step(DT)
97
+ yield world.render(), world
98
+ time.sleep(DT)
99
+
100
+ def pause_fn():
101
+ global RUNNING; RUNNING = False
102
+ return gr.update(), gr.update()
103
+
104
+ with gr.Blocks(title="Behavioral ML in Virtual Crowds") as demo:
105
+ gr.Markdown("## Behavioral ML in Virtual Crowds · eenvoudige simulatie")
106
+ img = gr.Image(label="Simulatie")
107
+ n_people = gr.Slider(10, 500, value=200, step=10, label="Aantal mensen")
108
+ start_btn = gr.Button("▶️ Start")
109
+ pause_btn = gr.Button("⏸️ Pauze")
110
+ reset_btn = gr.Button("🔁 Reset")
111
+ state = gr.State()
112
+ reset_btn.click(reset_fn, [n_people], [img, state])
113
+ start_btn.click(start_fn, [state], [img, state])
114
+ pause_btn.click(pause_fn, outputs=[img, state])
115
+
116
+ if __name__ == "__main__":
117
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ gradio>=5.0.0
2
+ pillow