File size: 13,776 Bytes
a4613d9 14d304f 8a97324 14d304f 8a97324 a4613d9 8a97324 14d304f 5a666d5 a4613d9 3b5f9b3 591c6eb e27345b 591c6eb e27345b dc55ff0 3b5f9b3 a4613d9 e27345b 931da51 591c6eb e27345b 591c6eb e27345b 3429053 e27345b 62f7848 e27345b 591c6eb e27345b 4d1b358 dc55ff0 e27345b dc55ff0 e27345b dc55ff0 e27345b dc55ff0 e27345b 591c6eb e27345b dc55ff0 e27345b dc55ff0 e27345b dc55ff0 e27345b dc55ff0 e27345b dc55ff0 e27345b dc55ff0 e27345b dc55ff0 3b5f9b3 e27345b dc55ff0 |
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 |
import os
# os.environ["HOME"] = "/tmp"
# os.environ["XDG_CONFIG_HOME"] = "/tmp" # This is critical for many config writes
# os.environ["STREAMLIT_HOME"] = "/tmp"
# os.environ["STREAMLIT_CONFIG_DIR"] = "/tmp/.streamlit"
# os.environ["STREAMLIT_CONFIG_FILE"] = "/tmp/.streamlit/config.toml" # << Add this
# os.environ["STREAMLIT_USAGE_STATISTICS"] = "false"
# # Redirect all config/cache paths to /tmp
# # os.environ["HOME"] = "/tmp"
# # os.environ["STREAMLIT_HOME"] = "/tmp"
# # os.environ["STREAMLIT_CONFIG_DIR"] = "/tmp/.streamlit"
# os.environ["ULTRALYTICS_SETTINGS_DIR"] = "/tmp/ultralytics"
# os.environ["MPLCONFIGDIR"] = "/tmp/matplotlib"
# # Create necessary writable directories
# os.makedirs("/tmp/.streamlit", exist_ok=True)
# os.makedirs("/tmp/ultralytics", exist_ok=True)
# os.makedirs("/tmp/matplotlib", exist_ok=True)
# with open("/tmp/.streamlit/config.toml", "w") as f:
# f.write("[server]\nheadless = true\nport = 7860\n")
# Set a minimal config for Streamlit
# with open("/tmp/.streamlit/config.toml", "w") as f:
# f.write("""
# [server]
# headless = true
# enableCORS = false
# port = 7860
# """)
import streamlit as st
from PIL import Image
import time
from ultralytics import YOLO
import io
import matplotlib.pyplot as plt
import pandas as pd
# --- Page Config ---
st.set_page_config(page_title="Smart Traffic Light System", layout="wide")
# --- Heading ---
st.markdown(
"<h1 style='color: #1E88E5;'>π¦ Smart Traffic Light System</h1>",
unsafe_allow_html=True
)
st.markdown("Upload images from each direction of a 4-way intersection. The system will detect vehicles and assign green light duration based on vehicle count.")
# --- YOLOv8 Model ---
model = YOLO("src/yolov8n.pt")
vehicle_ids = [2, 3, 5, 7] # car, motorcycle, bus, truck
# --- Image Upload (4 columns) ---
st.markdown("### π· Upload Traffic Images")
cols = st.columns(4)
directions = ["North", "East", "South", "West"]
uploaded_images = {}
for col, direction in zip(cols, directions):
with col:
uploaded_images[direction] = st.file_uploader(f"{direction}", type=["jpg", "png"], key=direction)
if uploaded_file is not None:
save_path = os.path.join("/tmp", uploaded_file.name)
with open(save_path, "wb") as f:
f.write(uploaded_file.getbuffer())
st.success(f"File uploaded to {save_path}")
# --- Process Once All Images Are Uploaded ---
if all(uploaded_images.values()):
# Initialize session state attributes if not already initialized
if "annotated_images" not in st.session_state:
st.session_state.annotated_images = {}
st.session_state.counts = {}
st.session_state.finished = set() # Initialize the 'finished' attribute
for direction, img_file in uploaded_images.items():
img = Image.open(img_file).convert("RGB")
results = model(img)
# Count vehicles
count = sum(1 for c in results[0].boxes.cls if int(c.item()) in vehicle_ids)
st.session_state.counts[direction] = count
# Save annotated image to memory
annotated_array = results[0].plot()
annotated_img = Image.fromarray(annotated_array[..., ::-1]) # Convert BGR β RGB
st.session_state.annotated_images[direction] = annotated_img
# Sort directions by vehicle count (descending)
st.session_state.sorted_directions = sorted(st.session_state.counts.items(), key=lambda x: x[1], reverse=True)
st.session_state.current_index = 0
st.session_state.phase = "green"
current_direction, current_count = st.session_state.sorted_directions[st.session_state.current_index]
# --- Dynamic Green Time Logic ---
base_time = 5
time_per_vehicle = 1
max_time = 25
green_time = min(base_time + int(current_count/2) * time_per_vehicle, max_time)
yellow_time = 3 # Fixed yellow duration
# --- Enhanced Signal Status Visualization ---
st.markdown("<br>", unsafe_allow_html=True)
st.markdown("### π₯ Current Signal Status")
signal_cols = st.columns(4)
for idx, direction in enumerate(directions):
with signal_cols[idx]:
count = st.session_state.counts[direction]
# Define color and message for current signal
if direction == current_direction:
if st.session_state.phase == "green":
color = "#4CAF50" # Green
status = "π’ GREEN"
else:
color = "#FFC107" # Yellow
status = "π‘ YELLOW"
else:
color = "#D32F2F" # Red
status = "π΄ RED"
# Highlight only if green or yellow
style = f"""
<div style='
background-color:{color};
padding:20px;
border-radius:10px;
color:white;
font-size:24px;
font-weight:bold;
box-shadow:0 0 10px rgba(0,0,0,0.3);'>
{direction}<br>{status}<br>{count} Vehicles
</div>
"""
if direction == current_direction:
st.markdown(style, unsafe_allow_html=True)
else:
st.markdown(f"### {status}\n**{direction}**\n**{count} Vehicles**")
# --- Timer UI ---
st.markdown("<br>", unsafe_allow_html=True)
st.markdown("### β± Signal Timer")
timer_placeholder = st.empty()
# --- Display Annotated Images Below Timer ---
st.markdown("<br>", unsafe_allow_html=True)
st.markdown("### πΌοΈ Detected Vehicles (Annotated Images)")
img_cols = st.columns(4)
for idx, direction in enumerate(directions):
with img_cols[idx]:
st.image(st.session_state.annotated_images[direction], caption=f"{direction} - Vehicles: {st.session_state.counts[direction]}", use_container_width=True)
# --- Countdown Timer ---
duration = green_time if st.session_state.phase == "green" else yellow_time
for remaining in range(duration, 0, -1):
if st.session_state.phase == "green":
timer_placeholder.markdown(f"π’ Green light for **{current_direction}** - {remaining} sec")
else:
timer_placeholder.markdown(f"π‘ Yellow light for **{current_direction}** - {remaining} sec")
time.sleep(1)
# --- Switch Phase or Stop ---
if st.session_state.phase == "green":
st.session_state.phase = "yellow"
st.rerun()
else:
# After yellow, mark direction as finished
st.session_state.finished.add(current_direction)
st.session_state.current_index += 1
st.session_state.phase = "green"
# Stop rerun if all directions are finished
if len(st.session_state.finished) < 4:
st.rerun()
else:
# Show completion message when all directions are done
st.success("### π¦ Simulation Complete! All directions have completed their green and yellow phases.")
counts = st.session_state.counts
sorted_directions = st.session_state.sorted_directions
# st.session_state.clear()
st.markdown("<br>", unsafe_allow_html=True)
st.markdown("## π Traffic Analysis Dashboard")
# 1. Total vehicles
total_vehicles = sum(st.session_state.counts.values())
st.markdown(
f"""
<br>
<h3 style='font-size: 24px; font-weight: bold;'>π Total Vehicles Detected: <span style='color: #4da6ff;'>{total_vehicles}</span></h3>""",unsafe_allow_html=True)
# 2. Bar chart for vehicle count
st.markdown("<br><h3 style='font-size: 24px; font-weight: bold;'>π¦ Vehicle Count per Direction</h3>", unsafe_allow_html=True)
# Create the bar chart
vehicle_counts = st.session_state.counts
fig, ax = plt.subplots(figsize=(4,4))
# Plot the bar char
ax.bar(vehicle_counts.keys(), vehicle_counts.values(), color='teal')
# Add numbers on top of the bars
for i, count in enumerate(vehicle_counts.values()):
ax.text(i, count + 0.5, str(count), ha='center', va='bottom', fontweight='bold', fontsize=8)
# Customize the chart
ax.set_ylabel('Vehicle Count')
ax.set_xlabel('Directions')
ax.set_title('Vehicle Count per Direction')
# Display the chart in Streamlit
# Show in small column
col1, col2, _ = st.columns([.3, .4, .3])
with col2:
st.pyplot(fig)
# 3. Most congested direction
busiest = max(st.session_state.counts.items(), key=lambda x: x[1])
st.markdown(
f"""
<br>
<h3 style='font-size: 24px; font-weight: bold;'>
π₯ Busiest Direction: <span style='color: red;'>{busiest[0]}</span> with {busiest[1]} vehicles
</h3>
""",
unsafe_allow_html=True
)
# 4. Green time per direction
base_time = 5
time_per_vehicle = 1
max_time = 25
# Use the same formula applied earlier
green_times = [
min(base_time + int(st.session_state.counts[d] / 2) * time_per_vehicle, max_time)
for d, _ in st.session_state.sorted_directions
]
green_df = pd.DataFrame({
"Direction": [d for d, _ in sorted_directions],
"Assigned Green Time (sec)": green_times
})
st.markdown("<br><h3 style='font-size: 24px; font-weight: bold;'>β±οΈ Assigned Green Time</h3>" , unsafe_allow_html=True)
col1, col2, _ = st.columns([.3, .4, .3])
with col2:
st.dataframe(green_df.style.set_properties(**{
'background-color': '#e8f5e9',
'color': 'green',
'font-size': '12px',
'font-weight': 'bold',
'text-align' : 'left'
}), use_container_width=True)
# 5. Pie chart (optional)
import pandas as pd
df = pd.DataFrame.from_dict(st.session_state.counts, orient='index', columns=['Vehicles'])
st.markdown("<h4 style='font-size: 20px; font-weight: bold;'>π Traffic Share by Direction</h4>", unsafe_allow_html=True)
fig2, ax2 = plt.subplots(figsize=(4, 4)) # Smaller size
ax2.pie(counts.values(), labels=counts.keys(), autopct='%1.1f%%', textprops={'fontsize': 8})
ax2.set_title("Traffic Distribution", fontsize=10)
col1, col2, _ = st.columns([.2, .4, .2])
with col2:
st.pyplot(fig2)
# 6. Waiting Time Calculation ---
st.markdown("<br>", unsafe_allow_html=True)
st.markdown("### β±οΈ Waiting Time Analysis")
# Use the already computed busiest direction
busiest_direction = busiest[0]
# Define green time per vehicle
time_per_vehicle = 1
# Initialize dictionary to store waiting times
waiting_times = {}
# Calculate waiting times for all directions except the busiest one
for direction in directions:
if direction == busiest_direction:
waiting_times[direction] = 0 # No wait for the first green
else:
# Waiting time is the sum of green times of all directions before this one (excluding busiest and current)
preceding_directions = [d for d, _ in st.session_state.sorted_directions if d != direction and d != busiest_direction]
wait = sum(min(5 + st.session_state.counts[d] * time_per_vehicle, 30) + 3 # green + yellow
for d in preceding_directions)
waiting_times[direction] = wait
# Display waiting times for each direction
waiting_time_data = pd.DataFrame({
"Direction": directions,
"Waiting Time (sec)": [waiting_times[direction] for direction in directions]
})
# Display waiting times in a table
# Show in small column
col1, col2, _ = st.columns([.3, .4, .3])
with col2:
st.dataframe(waiting_time_data.style.set_properties(**{
'background-color': '#f3f4f6',
'color': 'black',
'font-size': '12px',
'font-weight': 'bold'
}))
# Optionally, add a message for the waiting times
st.markdown("<br>", unsafe_allow_html=True)
st.markdown(
"""
The waiting times represent the total waiting time for vehicles at each direction based on the vehicle counts in other directions.
The higher the vehicle count in other directions, the higher the waiting time for the current direction.
"""
)
st.session_state.clear() |