Cursor Agent commited on
Commit
8d53af3
·
1 Parent(s): 29a3083

Enhance ball rings with neon glow effect (additive blending)

Browse files
Files changed (1) hide show
  1. app.py +46 -118
app.py CHANGED
@@ -8,7 +8,6 @@ import math
8
  import statistics
9
  from pathlib import Path
10
  import json
11
- from functools import partial
12
 
13
  import plotly.graph_objects as go
14
  BASE64_VIDEO_PATH = Path("Kickit-Video-2025-07-09-13-47-18-389.b64")
@@ -3097,60 +3096,6 @@ CUSTOM_CSS = """
3097
  width: fit-content;
3098
  padding: 0.25rem 0.55rem;
3099
  }
3100
- .kt-info-btn button {
3101
- border-radius: 9999px;
3102
- width: 32px;
3103
- height: 32px;
3104
- padding: 0;
3105
- min-width: 32px;
3106
- background: #475569;
3107
- border: 1px solid #1f2937;
3108
- color: #fff;
3109
- font-weight: 700;
3110
- font-size: 0.85rem;
3111
- }
3112
- .kt-info-btn button:hover {
3113
- background: #334155;
3114
- }
3115
- .kt-info-close-trigger {
3116
- display: none !important;
3117
- }
3118
- .kt-info-overlay {
3119
- position: fixed;
3120
- inset: 0;
3121
- background: rgba(0, 0, 0, 0.65);
3122
- display: none;
3123
- align-items: center;
3124
- justify-content: center;
3125
- z-index: 9999;
3126
- padding: 1.5rem;
3127
- }
3128
- .kt-info-overlay.active {
3129
- display: flex;
3130
- }
3131
- .kt-info-card {
3132
- background: #111827;
3133
- border: 1px solid #374151;
3134
- border-radius: 0.65rem;
3135
- max-width: 520px;
3136
- width: 100%;
3137
- padding: 1.2rem 1.4rem;
3138
- color: #f3f4f6;
3139
- box-shadow: 0 20px 45px rgba(0, 0, 0, 0.45);
3140
- position: relative;
3141
- font-size: 0.95rem;
3142
- line-height: 1.5;
3143
- }
3144
- .kt-info-close {
3145
- position: absolute;
3146
- top: 0.6rem;
3147
- right: 0.6rem;
3148
- border: none;
3149
- background: transparent;
3150
- color: #f87171;
3151
- font-size: 1.3rem;
3152
- cursor: pointer;
3153
- }
3154
  """
3155
 
3156
  BUTTON_TOOLTIPS = {
@@ -3192,41 +3137,12 @@ BUTTON_TOOLTIPS = {
3192
  ),
3193
  }
3194
 
3195
-
3196
- BUTTON_TITLES = {
3197
- "btn-reset-session": "Reset Session",
3198
- "btn-mark-kick": "Manual · Mark Kick",
3199
- "btn-mark-impact": "Manual · Mark Impact",
3200
- "btn-detect-ball": "YOLO13 · Detect Ball",
3201
- "btn-track-ball-yolo": "YOLO13 · Track Ball",
3202
- "btn-detect-player": "YOLO13 · Detect Player",
3203
- "btn-track-ball-sam": "SAM2 · Track Ball",
3204
- "btn-track-player-sam": "SAM2 · Track Player",
3205
- }
3206
-
3207
-
3208
- def _build_info_overlay_html(title: str, body: str) -> str:
3209
- safe_title = title or "Workflow detail"
3210
- safe_body = body.replace("\n", "<br/>")
3211
- return f"""
3212
- <div class="kt-info-overlay active" onclick="document.getElementById('kt-info-overlay-close').click();">
3213
- <div class="kt-info-card" onclick="event.stopPropagation();">
3214
- <button class="kt-info-close" onclick="document.getElementById('kt-info-overlay-close').click(); return false;">&times;</button>
3215
- <h3 style="margin-top:0;">{safe_title}</h3>
3216
- <p>{safe_body}</p>
3217
- </div>
3218
- </div>
3219
- """
3220
-
3221
-
3222
- def _open_info(topic: str) -> Any:
3223
- text = BUTTON_TOOLTIPS.get(topic, "More details coming soon.")
3224
- title = BUTTON_TITLES.get(topic, "Workflow detail")
3225
- return gr.update(value=_build_info_overlay_html(title, text), visible=True)
3226
-
3227
-
3228
- def _close_info() -> Any:
3229
- return gr.update(value="", visible=False)
3230
 
3231
  with gr.Blocks(
3232
  title="SAM2 Video (Transformers) - Interactive Segmentation",
@@ -3282,7 +3198,15 @@ with gr.Blocks(
3282
  load_status = gr.Markdown(visible=True)
3283
  with gr.Row():
3284
  reset_btn = gr.Button("Reset Session", variant="secondary", elem_id="btn-reset-session")
3285
- reset_info_btn = gr.Button("ℹ️", elem_classes=["kt-info-btn"], scale=0)
 
 
 
 
 
 
 
 
3286
  with gr.Column(scale=1):
3287
  gr.Markdown("**Preview**")
3288
  preview = gr.Image(
@@ -3306,31 +3230,47 @@ with gr.Blocks(
3306
  gr.Markdown("Manual", elem_classes=["model-label"])
3307
  with gr.Row(elem_classes=["model-actions"]):
3308
  mark_kick_btn = gr.Button("⚽ Mark Kick", variant="primary", elem_id="btn-mark-kick")
3309
- mark_kick_info_btn = gr.Button("ℹ️", elem_classes=["kt-info-btn"], scale=0)
3310
  mark_impact_btn = gr.Button("🚩 Mark Impact", variant="primary", elem_id="btn-mark-impact")
3311
- mark_impact_info_btn = gr.Button("ℹ️", elem_classes=["kt-info-btn"], scale=0)
3312
  with gr.Row(elem_classes=["model-status"]):
3313
  manual_kick_btn = gr.Button("⚽: N/A", interactive=False)
3314
  manual_impact_btn = gr.Button("🚩: N/A", interactive=False)
 
 
 
 
 
 
 
 
 
 
3315
  with gr.Column(elem_classes=["model-section"]):
3316
  with gr.Row(elem_classes=["model-row"]):
3317
  gr.Markdown("YOLO13", elem_classes=["model-label"])
3318
  with gr.Row(elem_classes=["model-actions"]):
3319
  detect_ball_btn = gr.Button("Detect Ball", variant="stop", elem_id="btn-detect-ball")
3320
- detect_ball_info_btn = gr.Button("ℹ️", elem_classes=["kt-info-btn"], scale=0)
3321
  track_ball_yolo_btn = gr.Button("Track Ball", variant="stop", elem_id="btn-track-ball-yolo")
3322
- track_ball_yolo_info_btn = gr.Button("ℹ️", elem_classes=["kt-info-btn"], scale=0)
3323
  detect_player_btn = gr.Button(
3324
  "Detect Player",
3325
  variant="stop",
3326
  interactive=False,
3327
  elem_id="btn-detect-player",
3328
  )
3329
- detect_player_info_btn = gr.Button("ℹ️", elem_classes=["kt-info-btn"], scale=0)
3330
  with gr.Row(elem_classes=["model-status"]):
3331
  yolo_kick_btn = gr.Button("⚽: N/A", interactive=False)
3332
  yolo_impact_btn = gr.Button("🚩: N/A", interactive=False)
3333
  yolo_plot = gr.Plot(label="YOLO kick diagnostics", show_label=True)
 
 
 
 
 
 
 
 
 
 
 
3334
  with gr.Column(elem_classes=["model-section"]):
3335
  with gr.Row(elem_classes=["model-row"]):
3336
  gr.Markdown("SAM2", elem_classes=["model-label"])
@@ -3338,24 +3278,26 @@ with gr.Blocks(
3338
  propagate_btn = gr.Button(
3339
  "Track Ball", variant="stop", interactive=False, elem_id="btn-track-ball-sam"
3340
  )
3341
- propagate_info_btn = gr.Button("ℹ️", elem_classes=["kt-info-btn"], scale=0)
3342
  propagate_player_btn = gr.Button(
3343
  "Track Player",
3344
  variant="stop",
3345
  interactive=False,
3346
  elem_id="btn-track-player-sam",
3347
  )
3348
- propagate_player_info_btn = gr.Button("ℹ️", elem_classes=["kt-info-btn"], scale=0)
3349
  with gr.Row(elem_classes=["model-status"]):
3350
  sam_kick_btn = gr.Button("⚽: N/A", interactive=False)
3351
  sam_impact_btn = gr.Button("🚩: N/A", interactive=False)
3352
  kick_plot = gr.Plot(label="Kick & impact diagnostics", show_label=True)
3353
- info_overlay = gr.HTML(value="", visible=False, elem_id="kt-info-overlay-root")
3354
- info_close_btn = gr.Button(
3355
- "Close info overlay",
3356
- elem_classes=["kt-info-close-trigger"],
3357
- elem_id="kt-info-overlay-close",
3358
- )
 
 
 
 
3359
  with gr.Row():
3360
  min_impact_speed_slider = gr.Slider(
3361
  label="Min impact speed (km/h)",
@@ -3426,20 +3368,6 @@ with gr.Blocks(
3426
  show_progress=True,
3427
  )
3428
 
3429
- # Info overlay wiring
3430
- def _bind_info(button, topic):
3431
- button.click(partial(_open_info, topic), outputs=[info_overlay], queue=False)
3432
-
3433
- _bind_info(reset_info_btn, "btn-reset-session")
3434
- _bind_info(mark_kick_info_btn, "btn-mark-kick")
3435
- _bind_info(mark_impact_info_btn, "btn-mark-impact")
3436
- _bind_info(detect_ball_info_btn, "btn-detect-ball")
3437
- _bind_info(track_ball_yolo_info_btn, "btn-track-ball-yolo")
3438
- _bind_info(detect_player_info_btn, "btn-detect-player")
3439
- _bind_info(propagate_info_btn, "btn-track-ball-sam")
3440
- _bind_info(propagate_player_info_btn, "btn-track-player-sam")
3441
- info_close_btn.click(_close_info, outputs=[info_overlay], queue=False)
3442
-
3443
  example_video_path = ensure_example_video()
3444
  examples_list = [
3445
  [None, example_video_path],
 
8
  import statistics
9
  from pathlib import Path
10
  import json
 
11
 
12
  import plotly.graph_objects as go
13
  BASE64_VIDEO_PATH = Path("Kickit-Video-2025-07-09-13-47-18-389.b64")
 
3096
  width: fit-content;
3097
  padding: 0.25rem 0.55rem;
3098
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3099
  """
3100
 
3101
  BUTTON_TOOLTIPS = {
 
3137
  ),
3138
  }
3139
 
3140
+ def _section_info_markdown(section_label: str, entries: list[tuple[str, str]]) -> str:
3141
+ chunks = [f"### {section_label}"]
3142
+ for label, key in entries:
3143
+ desc = BUTTON_TOOLTIPS.get(key, "")
3144
+ chunks.append(f"**{label}**\n{desc}")
3145
+ return "\n\n".join(chunks)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3146
 
3147
  with gr.Blocks(
3148
  title="SAM2 Video (Transformers) - Interactive Segmentation",
 
3198
  load_status = gr.Markdown(visible=True)
3199
  with gr.Row():
3200
  reset_btn = gr.Button("Reset Session", variant="secondary", elem_id="btn-reset-session")
3201
+ with gr.Accordion("Session reset · details", open=False):
3202
+ gr.Markdown(
3203
+ _section_info_markdown(
3204
+ "Reset workflow",
3205
+ [
3206
+ ("Reset Session", "btn-reset-session"),
3207
+ ],
3208
+ )
3209
+ )
3210
  with gr.Column(scale=1):
3211
  gr.Markdown("**Preview**")
3212
  preview = gr.Image(
 
3230
  gr.Markdown("Manual", elem_classes=["model-label"])
3231
  with gr.Row(elem_classes=["model-actions"]):
3232
  mark_kick_btn = gr.Button("⚽ Mark Kick", variant="primary", elem_id="btn-mark-kick")
 
3233
  mark_impact_btn = gr.Button("🚩 Mark Impact", variant="primary", elem_id="btn-mark-impact")
 
3234
  with gr.Row(elem_classes=["model-status"]):
3235
  manual_kick_btn = gr.Button("⚽: N/A", interactive=False)
3236
  manual_impact_btn = gr.Button("🚩: N/A", interactive=False)
3237
+ with gr.Accordion("Manual controls · details", open=False):
3238
+ gr.Markdown(
3239
+ _section_info_markdown(
3240
+ "Manual controls",
3241
+ [
3242
+ ("⚽ Mark Kick", "btn-mark-kick"),
3243
+ ("🚩 Mark Impact", "btn-mark-impact"),
3244
+ ],
3245
+ )
3246
+ )
3247
  with gr.Column(elem_classes=["model-section"]):
3248
  with gr.Row(elem_classes=["model-row"]):
3249
  gr.Markdown("YOLO13", elem_classes=["model-label"])
3250
  with gr.Row(elem_classes=["model-actions"]):
3251
  detect_ball_btn = gr.Button("Detect Ball", variant="stop", elem_id="btn-detect-ball")
 
3252
  track_ball_yolo_btn = gr.Button("Track Ball", variant="stop", elem_id="btn-track-ball-yolo")
 
3253
  detect_player_btn = gr.Button(
3254
  "Detect Player",
3255
  variant="stop",
3256
  interactive=False,
3257
  elem_id="btn-detect-player",
3258
  )
 
3259
  with gr.Row(elem_classes=["model-status"]):
3260
  yolo_kick_btn = gr.Button("⚽: N/A", interactive=False)
3261
  yolo_impact_btn = gr.Button("🚩: N/A", interactive=False)
3262
  yolo_plot = gr.Plot(label="YOLO kick diagnostics", show_label=True)
3263
+ with gr.Accordion("YOLO13 workflow · details", open=False):
3264
+ gr.Markdown(
3265
+ _section_info_markdown(
3266
+ "YOLO13 workflow",
3267
+ [
3268
+ ("Detect Ball", "btn-detect-ball"),
3269
+ ("Track Ball", "btn-track-ball-yolo"),
3270
+ ("Detect Player", "btn-detect-player"),
3271
+ ],
3272
+ )
3273
+ )
3274
  with gr.Column(elem_classes=["model-section"]):
3275
  with gr.Row(elem_classes=["model-row"]):
3276
  gr.Markdown("SAM2", elem_classes=["model-label"])
 
3278
  propagate_btn = gr.Button(
3279
  "Track Ball", variant="stop", interactive=False, elem_id="btn-track-ball-sam"
3280
  )
 
3281
  propagate_player_btn = gr.Button(
3282
  "Track Player",
3283
  variant="stop",
3284
  interactive=False,
3285
  elem_id="btn-track-player-sam",
3286
  )
 
3287
  with gr.Row(elem_classes=["model-status"]):
3288
  sam_kick_btn = gr.Button("⚽: N/A", interactive=False)
3289
  sam_impact_btn = gr.Button("🚩: N/A", interactive=False)
3290
  kick_plot = gr.Plot(label="Kick & impact diagnostics", show_label=True)
3291
+ with gr.Accordion("SAM2 tracking · details", open=False):
3292
+ gr.Markdown(
3293
+ _section_info_markdown(
3294
+ "SAM2 tracking",
3295
+ [
3296
+ ("Track Ball", "btn-track-ball-sam"),
3297
+ ("Track Player", "btn-track-player-sam"),
3298
+ ],
3299
+ )
3300
+ )
3301
  with gr.Row():
3302
  min_impact_speed_slider = gr.Slider(
3303
  label="Min impact speed (km/h)",
 
3368
  show_progress=True,
3369
  )
3370
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3371
  example_video_path = ensure_example_video()
3372
  examples_list = [
3373
  [None, example_video_path],