skills/cv/deepsort-majority-vote-relabel/SKILL.md
Run DeepSort on per-frame detections then overwrite each track cluster's label with the most common mapped label across the track's lifetime
npx skillsauth add wenmin-wu/ds-skills cv-deepsort-majority-vote-relabelInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
DeepSort produces temporally-consistent tracker IDs, but the downstream labels assigned to each detection frame-by-frame are still noisy. The fix: after DeepSort assigns a stable cluster_id, look up all per-frame labels inside that cluster and overwrite every frame in the cluster with the majority-vote label. One wrong frame cannot flip a whole track, and flickering ID assignments collapse into one canonical ID per player/object. Used in the NFL Helmet Assignment competition to lift assignment accuracy by 5-10 points.
from deep_sort_pytorch.deep_sort import DeepSort
import cv2, pandas as pd
deepsort = DeepSort(ckpt, max_dist=0.2, max_iou_distance=0.9,
max_age=15, n_init=1, nn_budget=30, use_cuda=True)
tracked = []
for frame, d in detections.groupby('frame'):
cap.set(cv2.CAP_PROP_POS_FRAMES, frame - 1)
_, image = cap.read()
xywhs = d[['x','y','width','height']].values
out = deepsort.update(xywhs, confs=np.ones(len(d)),
clss=np.zeros(len(d)), ori_img=image)
df_out = pd.DataFrame(out, columns=['l','t','r','b','cluster','cls'])
# Merge cluster ids back onto the original label column
d = pd.merge_asof(d.sort_values('x'), df_out.sort_values('l'),
left_on='x', right_on='l', direction='nearest')
tracked.append(d)
tracked = pd.concat(tracked)
# Majority vote per cluster
vote = (tracked.groupby('cluster')['label']
.agg(lambda s: s.value_counts().idxmax()))
tracked['label'] = tracked['cluster'].map(vote)
# Drop duplicate labels per frame (submission constraint)
tracked = tracked.loc[~tracked[['frame','label']].duplicated()]
cluster_id for every boxcluster_id and compute the modal label of each clustermax_age: too short and tracks fragment; too long and different objects merge. For sports video, 14-30 frames is typical.nn_budget: controls the re-ID feature gallery size per track. 30-100 works; larger slows inference.data-ai
Scaled Pinball Loss (SPL) metric for evaluating quantile forecasts, normalized by mean absolute successive differences of training data
data-ai
Walk backward through a time series and multiplicatively rescale segments when jumps exceed a fraction of the running mean to correct data collection anomalies
testing
Transform forecasting target to next/current ratio minus one so that optimizing MAE or squared error implicitly minimizes SMAPE
tools
Convert point forecasts to prediction intervals by scaling with logit-transformed quantile ratios passed through a Normal CDF