cyberai-1 commited on
Commit
aece0e6
·
1 Parent(s): 8b1c56f

improv home

Browse files
__pycache__/app.cpython-311.pyc CHANGED
Binary files a/__pycache__/app.cpython-311.pyc and b/__pycache__/app.cpython-311.pyc differ
 
app.py CHANGED
@@ -86,6 +86,8 @@ _webcam_classes = []
86
  _webcam_frame_count = 0
87
  _webcam_detections = 0
88
  _webcam_detections_by_class = defaultdict(int)
 
 
89
  _webcam_lock = threading.Lock()
90
 
91
  # ── Chargement du modèle en arrière-plan ──────────────────────────────────────
@@ -882,6 +884,7 @@ def api_logs_csv(scene_id):
882
  def api_webcam_start():
883
  global _webcam_active, _webcam_classes, _webcam_frame_count
884
  global _webcam_detections, _webcam_detections_by_class
 
885
 
886
  data = request.json or {}
887
  classes = data.get("classes", DEFAULT_CLASSES)
@@ -896,6 +899,8 @@ def api_webcam_start():
896
  _webcam_frame_count = 0
897
  _webcam_detections = 0
898
  _webcam_detections_by_class = defaultdict(int)
 
 
899
 
900
  print(f"✅ Webcam started with classes: {classes}")
901
  return jsonify({"status": "started"}), 200
@@ -903,6 +908,7 @@ def api_webcam_start():
903
  @app.route("/api/webcam/frame", methods=["POST"])
904
  def api_webcam_frame():
905
  global _webcam_frame_count, _webcam_detections, _webcam_detections_by_class
 
906
 
907
  if not _webcam_active or not _model_ready:
908
  return jsonify({"error": "Webcam not active"}), 503
@@ -918,21 +924,41 @@ def api_webcam_frame():
918
  if frame is None:
919
  return jsonify({"error": "Could not decode image"}), 400
920
 
921
- # Inférence YOLO avec les paramètres corrigés
922
- results = _model(frame, conf=CONF, iou=IOU, imgsz=INFER_SZ, verbose=False)
 
 
 
 
 
 
 
923
 
924
- annotated, detection_count = _draw_detections(frame, results, _webcam_classes)
 
 
925
 
926
  with _webcam_lock:
927
  _webcam_frame_count += 1
928
- _webcam_detections += detection_count
929
 
930
- if results[0].boxes:
931
  for box in results[0].boxes:
932
  cls = int(box.cls[0])
933
  class_name = COCO_TO_LABEL.get(cls)
934
  if class_name and class_name in _webcam_classes:
935
- _webcam_detections_by_class[class_name] += 1
 
 
 
 
 
 
 
 
 
 
 
 
936
 
937
  ret, buffer = cv2.imencode('.jpg', annotated)
938
  return Response(buffer.tobytes(), mimetype='image/jpeg'), 200
@@ -953,12 +979,13 @@ def api_webcam_stop():
953
  def api_webcam_stats():
954
  with _webcam_lock:
955
  by_class = dict(_webcam_detections_by_class)
 
956
  return jsonify({
957
  "active": _webcam_active,
958
  "frame": _webcam_frame_count,
959
  "detections": _webcam_detections,
960
  "detections_by_class": by_class,
961
- "frame_counts": by_class,
962
  "unique_counts": by_class
963
  }), 200
964
 
 
86
  _webcam_frame_count = 0
87
  _webcam_detections = 0
88
  _webcam_detections_by_class = defaultdict(int)
89
+ _webcam_current_counts = defaultdict(int)
90
+ _webcam_seen_track_ids = set()
91
  _webcam_lock = threading.Lock()
92
 
93
  # ── Chargement du modèle en arrière-plan ──────────────────────────────────────
 
884
  def api_webcam_start():
885
  global _webcam_active, _webcam_classes, _webcam_frame_count
886
  global _webcam_detections, _webcam_detections_by_class
887
+ global _webcam_current_counts, _webcam_seen_track_ids
888
 
889
  data = request.json or {}
890
  classes = data.get("classes", DEFAULT_CLASSES)
 
899
  _webcam_frame_count = 0
900
  _webcam_detections = 0
901
  _webcam_detections_by_class = defaultdict(int)
902
+ _webcam_current_counts = defaultdict(int)
903
+ _webcam_seen_track_ids = set()
904
 
905
  print(f"✅ Webcam started with classes: {classes}")
906
  return jsonify({"status": "started"}), 200
 
908
  @app.route("/api/webcam/frame", methods=["POST"])
909
  def api_webcam_frame():
910
  global _webcam_frame_count, _webcam_detections, _webcam_detections_by_class
911
+ global _webcam_current_counts, _webcam_seen_track_ids
912
 
913
  if not _webcam_active or not _model_ready:
914
  return jsonify({"error": "Webcam not active"}), 503
 
924
  if frame is None:
925
  return jsonify({"error": "Could not decode image"}), 400
926
 
927
+ # Tracking YOLO: count unique objects by persistent track_id, not by frame.
928
+ results = _model.track(
929
+ frame,
930
+ conf=CONF,
931
+ iou=IOU,
932
+ imgsz=INFER_SZ,
933
+ persist=True,
934
+ verbose=False
935
+ )
936
 
937
+ annotated, _ = _draw_detections(frame, results, _webcam_classes)
938
+ current_counts = defaultdict(int)
939
+ new_unique_counts = defaultdict(int)
940
 
941
  with _webcam_lock:
942
  _webcam_frame_count += 1
 
943
 
944
+ if results and results[0].boxes:
945
  for box in results[0].boxes:
946
  cls = int(box.cls[0])
947
  class_name = COCO_TO_LABEL.get(cls)
948
  if class_name and class_name in _webcam_classes:
949
+ current_counts[class_name] += 1
950
+ if box.id is None:
951
+ continue
952
+ track_id = int(box.id[0])
953
+ unique_key = (class_name, track_id)
954
+ if unique_key not in _webcam_seen_track_ids:
955
+ _webcam_seen_track_ids.add(unique_key)
956
+ new_unique_counts[class_name] += 1
957
+
958
+ for class_name, count in new_unique_counts.items():
959
+ _webcam_detections_by_class[class_name] += count
960
+ _webcam_current_counts = current_counts
961
+ _webcam_detections = sum(_webcam_detections_by_class.values())
962
 
963
  ret, buffer = cv2.imencode('.jpg', annotated)
964
  return Response(buffer.tobytes(), mimetype='image/jpeg'), 200
 
979
  def api_webcam_stats():
980
  with _webcam_lock:
981
  by_class = dict(_webcam_detections_by_class)
982
+ frame_counts = dict(_webcam_current_counts)
983
  return jsonify({
984
  "active": _webcam_active,
985
  "frame": _webcam_frame_count,
986
  "detections": _webcam_detections,
987
  "detections_by_class": by_class,
988
+ "frame_counts": frame_counts,
989
  "unique_counts": by_class
990
  }), 200
991
 
templates/dashboard.html CHANGED
@@ -265,6 +265,17 @@ window._lastPieColors=[];
265
  window._lastFlowScene=null;
266
  window._lastCounts={};
267
 
 
 
 
 
 
 
 
 
 
 
 
268
  function chartReady(){
269
  return false;
270
  }
@@ -485,6 +496,16 @@ function gc(){
485
  return{grid:dk?'rgba(255,255,255,0.05)':'rgba(0,0,0,0.06)',tick:dk?'#4a5a6a':'#94a3b8'};
486
  }
487
 
 
 
 
 
 
 
 
 
 
 
488
  /* ── Pie chart — Object Type Distribution ── */
489
  window.pch = null;
490
 
@@ -640,13 +661,27 @@ function drawHm(){
640
  mxR=Math.max(mxR,0.01);mxH=Math.max(mxH,0.01);
641
  pts.forEach(p=>{
642
  const px=(p.x/mxR)*w,py=(p.y/mxH)*h;
643
- const rad=Math.max(10,Math.min(w,h)*0.015);
 
644
  const grd=ctx.createRadialGradient(px,py,0,px,py,rad);
645
- grd.addColorStop(0,'rgba(220,38,38,0.5)');
646
- grd.addColorStop(0.4,'rgba(180,0,0,0.18)');
647
  grd.addColorStop(1,'rgba(0,0,0,0)');
648
  ctx.fillStyle=grd;ctx.fillRect(0,0,w,h);
649
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
650
  ctx.font="9px 'DM Mono',monospace";
651
  ctx.fillStyle=dk?'rgba(255,255,255,0.3)':'rgba(0,0,0,0.25)';
652
  ctx.textAlign='left';ctx.fillText(pts.length+' points',8,13);
@@ -669,7 +704,11 @@ async function loadHeatmap(){
669
  if(!rows.length)return;
670
  const pts=[];let mxX=0,mxY=0;
671
  rows.slice(0,4000).forEach(r=>{
672
- if(r.cx>0&&r.cy>0){pts.push({x:r.cx,y:r.cy,r:0,h:0});if(r.cx>mxX)mxX=r.cx;if(r.cy>mxY)mxY=r.cy;}
 
 
 
 
673
  });
674
  if(!pts.length)return;
675
  pts.forEach(p=>{p.r=mxX;p.h=mxY;});
 
265
  window._lastFlowScene=null;
266
  window._lastCounts={};
267
 
268
+ const CLASS_COLORS = {
269
+ 'Vehicle':'#3b82f6',
270
+ 'Motorcycle':'#10b981',
271
+ 'Truck':'#f59e0b',
272
+ 'Bus':'#8b5cf6',
273
+ 'Human':'#ec4899',
274
+ 'Bicycle':'#06b6d4',
275
+ 'Traffic light':'#ef4444',
276
+ 'Road sign':'#f97316'
277
+ };
278
+
279
  function chartReady(){
280
  return false;
281
  }
 
496
  return{grid:dk?'rgba(255,255,255,0.05)':'rgba(0,0,0,0.06)',tick:dk?'#4a5a6a':'#94a3b8'};
497
  }
498
 
499
+ function hexToRgba(hex,alpha){
500
+ const clean=String(hex||'').replace('#','');
501
+ const value=clean.length===3
502
+ ? clean.split('').map(ch=>ch+ch).join('')
503
+ : clean.padEnd(6,'0').slice(0,6);
504
+ const num=parseInt(value,16);
505
+ const r=(num>>16)&255,g=(num>>8)&255,b=num&255;
506
+ return `rgba(${r},${g},${b},${alpha})`;
507
+ }
508
+
509
  /* ── Pie chart — Object Type Distribution ── */
510
  window.pch = null;
511
 
 
661
  mxR=Math.max(mxR,0.01);mxH=Math.max(mxH,0.01);
662
  pts.forEach(p=>{
663
  const px=(p.x/mxR)*w,py=(p.y/mxH)*h;
664
+ const rad=Math.max(10,Math.min(w,h)*0.018);
665
+ const color=p.color||CLASS_COLORS[p.cls]||'#dc2626';
666
  const grd=ctx.createRadialGradient(px,py,0,px,py,rad);
667
+ grd.addColorStop(0,hexToRgba(color,0.55));
668
+ grd.addColorStop(0.42,hexToRgba(color,0.22));
669
  grd.addColorStop(1,'rgba(0,0,0,0)');
670
  ctx.fillStyle=grd;ctx.fillRect(0,0,w,h);
671
  });
672
+ const classes=[...new Set(pts.map(p=>p.cls).filter(Boolean))].slice(0,8);
673
+ let lx=8,ly=h-12;
674
+ ctx.font="9px 'DM Sans',sans-serif";
675
+ ctx.textAlign='left';
676
+ classes.forEach(cls=>{
677
+ const color=CLASS_COLORS[cls]||'#888';
678
+ ctx.fillStyle=color;
679
+ ctx.fillRect(lx,ly-7,7,7);
680
+ ctx.fillStyle=dk?'rgba(255,255,255,0.55)':'rgba(15,25,35,0.6)';
681
+ ctx.fillText(cls,lx+10,ly);
682
+ lx+=ctx.measureText(cls).width+26;
683
+ if(lx>w-80){lx=8;ly-=14;}
684
+ });
685
  ctx.font="9px 'DM Mono',monospace";
686
  ctx.fillStyle=dk?'rgba(255,255,255,0.3)':'rgba(0,0,0,0.25)';
687
  ctx.textAlign='left';ctx.fillText(pts.length+' points',8,13);
 
704
  if(!rows.length)return;
705
  const pts=[];let mxX=0,mxY=0;
706
  rows.slice(0,4000).forEach(r=>{
707
+ if(r.cx>0&&r.cy>0){
708
+ const cls=r.class_name||r.class||'Unknown';
709
+ pts.push({x:r.cx,y:r.cy,cls,color:CLASS_COLORS[cls]||'#888',r:0,h:0});
710
+ if(r.cx>mxX)mxX=r.cx;if(r.cy>mxY)mxY=r.cy;
711
+ }
712
  });
713
  if(!pts.length)return;
714
  pts.forEach(p=>{p.r=mxX;p.h=mxY;});
templates/home.html CHANGED
@@ -813,12 +813,7 @@ async function _pollWc(){
813
  const fc=d.frame_counts||{};
814
  const uc=d.unique_counts||{};
815
  _showCountsWc(fc,uc);
816
- // Fix: afficher banner SEULEMENT si vraiment zéro détections
817
- if(d.detections!==undefined){
818
- _showBanner(d.detections===0 && d.frame>0);
819
- }else{
820
- _showBanner(!Object.keys(fc).length);
821
- }
822
  }catch(e){}
823
  }
824
 
 
813
  const fc=d.frame_counts||{};
814
  const uc=d.unique_counts||{};
815
  _showCountsWc(fc,uc);
816
+ _showBanner(!Object.keys(fc).length && d.frame>0);
 
 
 
 
 
817
  }catch(e){}
818
  }
819