From 27d57b21d4f8be8284725691eedf7299e5a58614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BA=86=E5=88=9A?= Date: Mon, 29 Jul 2024 18:56:35 +0800 Subject: [PATCH] for bakeup --- .../contrast_analysis.cpython-39.pyc | Bin 9510 -> 9467 bytes tracking/contrast_analysis.py | 13 +- .../__pycache__/dotracks.cpython-39.pyc | Bin 13177 -> 13178 bytes .../__pycache__/dotracks_back.cpython-39.pyc | Bin 5782 -> 5782 bytes .../__pycache__/dotracks_front.cpython-39.pyc | Bin 4675 -> 4675 bytes tracking/dotrack/dotracks.py | 2 +- tracking/dotrack/dotracks_back.py | 6 +- tracking/dotrack/dotracks_front.py | 4 +- tracking/dotrack/track_select.py | 91 ++++ tracking/feat_select.py | 418 ++++++++++++++++++ tracking/module_analysis.py | 183 ++++---- .../utils/__pycache__/plotting.cpython-39.pyc | Bin 12836 -> 12903 bytes .../__pycache__/read_data.cpython-39.pyc | Bin 4848 -> 4952 bytes tracking/utils/plotting.py | 12 +- tracking/utils/read_data.py | 17 +- 15 files changed, 650 insertions(+), 96 deletions(-) create mode 100644 tracking/dotrack/track_select.py create mode 100644 tracking/feat_select.py diff --git a/tracking/__pycache__/contrast_analysis.cpython-39.pyc b/tracking/__pycache__/contrast_analysis.cpython-39.pyc index 8e5b16f310fd294c364ace279d5870e9fa2b241c..b5f51c69fac5fe544678989be4a5af7b20b1ede9 100644 GIT binary patch delta 1682 zcmZ8iO>7%g5Z<@;I%_wZIHj&ajO(O{>Nq7$+!RF>qO=gI{;32KC9qW8Y`mLzqxDZ_ zH=&ghHByl{K;ZBwEsB6bB+?*NqVjq{F~6>m>zbD^ObE0j_^mJ71m$1!UHUQ3@u>@ zL4@X+;$08f!p6zM_+_tDXGQXgAZV-$z&F6OB;YGQ3RQy$D$*B3K#E7_MhU z3JS|{=phnb&h7Tqt@uaEL7C zlqyTUK}ub-0g9%dF9gTh&4apRHt%$V*%kg#;%bCafCc_vBE@ET^58(%A_;&XN#GMK z5iD1YgAZ93bpQ$k^8~wv&Q!-b|75{*WEqrDS#O$Pk4-3fQMXPp+)Q$-t9YYUNukWS zWz!E_;q5)-J6_KRUU(8Q&nY^t366gq==}g{q^weN4@#($^b)~IQpJU8x~}0mp07t7 z&nuMQ6w!PcfR87Y8{zbdPsDNexWQ{=5b*+QTr`#L4fZj+A`>mQF+}L^R7c(nE+iCTs(TxyS}sTn8}ZD4z47h^0tR@wHx zB(lg3nGE;%gWeG~%zy7q<8QapH^`>>NZ-@=Z!pu>`v#E*b6lI~pgRjBTO)XjAZQ!i kH>ebB(r%039)eH}qhuCs!)Ur%y+ObBooP|jm>N;p|Id?y_5c6? delta 1657 zcmZ8hO>7%Q6y8~{*K0R+oRU<*#&!NAvJRnfl2SzxkXE6h1)@MoNH$fht#^~GwDvl0 zH-A;4Mk;~>q*9p(wTjxLN`(}mN`P-5Bu*UYl?!v>*b@@;$dAOlwd=Uv!?*L^yziSg z@6F6Vm%h3j)uYjfz`x?tdkcSj8+{ZYjQ$YliZID4ES8Q0=%r5rngGwI-`^YH$E%+xHroYIUjxh|CN?_($z*}-*q!wExw1)c0MEOD} zPC9EkM9&{M*z?X6Wf?GBJyeK@KdW!=mee2SX^(#OPFXNMXUe zUbr;Q=&fk#B(9-~a1AMW1eN|6eTO*Za4aa2KH3~V*SC!RV^FyHH|d9Y{#Ro#!+$L3 zdSI2npv&=0n~CwYBw!KEA^J_cjcD}e_!W-HmefxOhiOkcxZSyjw01o}HEkz8PJe5hTqGJsqiLj2a zfpEQ?JN1|(umey)un~?6t(M2z|04eBPzktvvf4C8o;#t)!fw4m_+XkEiNcLaC0TI6 zc686D!lw=5&scBzEN-!gYZWY82g}<4yg$Ha1T|Qp`z5@J-U)n=HKESz@$=wvc@Lub#K0w0&*{#aD=CWY{ zlMT~0JyTPvS}uHsX^bJ@1pxm()YVR)za}q|+cf#olM}ZwU>jkUMpLQYS~E1o)mKeC z`tUhU-$K|yP&hF9L2C3wohH4L8YH{r$Ejx0?!^yUjG%XNGjx;e3HQVYgb16>2QSd4 zr*}vz-A=d3D=1{pz4V!cpTTkUhH>UH!VLXA{r2$jy1042L=9Whq>}AbFPoo{O6NMp z$$fgzkxI34l0mivL);QPVN8i_@jTer+W^?{o`6WxPB8H^lc-2jNo?%H|AFb h_HlHG@Q?#ja=D^jFmt)OI#pXx?l~Wlm53rM;{S`pf9?PP diff --git a/tracking/contrast_analysis.py b/tracking/contrast_analysis.py index 058c6fd..c8e620c 100644 --- a/tracking/contrast_analysis.py +++ b/tracking/contrast_analysis.py @@ -397,7 +397,7 @@ def contrast_loop(fpath): plt1 = show_recall_prec(recall, prec, ths) # plt1.show() - plt.xlabel(f'threshold, Num: {len(blist)}') + plt1.xlabel(f'threshold, Num: {len(blist)}') plt1.savefig(os.path.join(savepath, file+'_pr.png')) # plt1.close() @@ -408,13 +408,12 @@ def contrast_loop(fpath): -def main1(): - fpath = r'D:\contrast\dataset\1_to_n\0719' - fpath = r'\\192.168.1.28\share\测试_202406\deletedBarcode\good' +def main(): + fpath = r'\\192.168.1.28\share\测试_202406\deletedBarcode\other' contrast_loop(fpath) -def main(): +def main1(): del_barcode_file = 'D:/contrast/dataset/compairsonResult/deletedBarcode_20240709_pm.txt' basepath = r'D:\contrast\dataset\1_to_n\709' savepath = r'D:\contrast\dataset\result' @@ -431,9 +430,9 @@ def resolve_vidoes(): video2imgs(videopath, savepath) if __name__ == '__main__': - # main() - main1() + main() + # main1() # resolve_vidoes() diff --git a/tracking/dotrack/__pycache__/dotracks.cpython-39.pyc b/tracking/dotrack/__pycache__/dotracks.cpython-39.pyc index 671fcc3a146ecf6945b72279c3ec85cec85a6d6d..d34df3e8b1344ca3572b77512a84f71367ed973b 100644 GIT binary patch delta 1366 zcmZXTO>k3H6vw$Q$xG5SnigJLq-m2DLSEX?CPb_qTfvrKwNz<~GH+T-nwyqLDdoOY zOBtPU#Eys`!<p&4chCKw|NVUD z-kP~R6E1|qH5>SQ%eOjn{@d`+-Udt04-F6R9ju0?%a!NLc4?|GFD>V~*A~K}3H^`A z{p?q*z%Jk+>h*u~fAO||Uf+%U9-0r#_Iai6w6MHVm;TcmET0U>Ah)`#ks)sV(vV?! z4?6;~K}KX9M?qOHH*&5P_iZ$_5jDu7 zDcl`%bBZS8t@j;(aTKtDW#A>?5SLYx7@*7Xs2Fgr#z%z6Q*(P$je7=@Ef)2+_xPSf z(l~!}TVm^aUcHKW+|yPNEi$SeyHw$u?N2n+zJ`(B%2ZjZPCA@u5@+aS;^jS% zl@BN~Ont3X-h|+$UPpw=v3v!T>D{$+mio3|@nJEGyvc;fQAaW=x}2fpO(7@w9A0|OuwhUGQIk{ z+&9DYaKOl(LFz1U9ykYl3Vg+=*4l2J9xGLj9GB`l=s&o%wL&js+rk3H6vw&wc+ICIElGjGDv|81=^j9L8d`S_oA?|JXs z{9S!m^_IL|*9Q76|Nd_E%1!TGThP?9!y_XH518(WTH{PjuM|slZW@2sbjD2iigw@k zB9VeFV( z@+USPLBtAl5={A%Kj%9IcM_Na>N44!W=D;a%{fa9Vbfl#^U9o1wMwjX&qEvmUXl+s z^{|F?1$Ho9_66Q!MdQc7jMe=zs;!fix~R&b&11eK)U&{8VA}X}^F!-%>-~x%qQ?o@ zeB7r_D4s&-834VRw(?|cMjVD;1Jnz7UH%r1(r0(H7sB|6re&^dTF#b53X}TWhvFP5GT%3tP z3etiT)3P96i*9{958+YZ3~&y(0F2X6wXv+c5e>7faX*@4Y*>an+FYuKI7v*I=@_t& z!7|?Hn6ps+uN|@N>v?ez&r#jZ!8!}2Rj)MY&1Paj&s*ddY>i@#i(Rr5Yh#z>eC*9< z5f*l!N{DN#qw)>{Ds=@GCdagwFs6^r&Skl;^Nw9@Chc7@mX_UJVU{!wb^XcMahXYM z>Biffw>4@!B8HS1Iju+LEqfwy@9Io$#~v}DDla4k*o*S(M5}fcfe++^M8Bq{qDKaI zX4#T_b>}B*`#HNq+A>tvaCMD+-5$%r7v!64;?ZN?r0_jP(l5!N3xQ@$>&*0wup!`B zZToFRJyR8NqQdi{R6eDP&k)k6Z}Ln>c~%rBYkI@9PpCzkP>KI`Grr&DXIh$ysFz=Q zyR;iH)9SA!+IMR;bDi968cs4FlPuLDL&+CX-$HnuaE+O6^;G&)dU352bx+a6%D+v_ zcdnJX3_Z7--1L|^rCx1@v(LN$S?v)uwAax0;%fN@g67V^2i(qr_e tzCrx1n#e_YF4e&n<;STwU7sIPA>vAEAn-IK8W04sz#>(&%F*3D{{Ya!Ret~g diff --git a/tracking/dotrack/__pycache__/dotracks_back.cpython-39.pyc b/tracking/dotrack/__pycache__/dotracks_back.cpython-39.pyc index 2c89354099bf5dac86d0446988dcefa94a298da0..d60ba11916606e8017282b0262e3fb6370952d68 100644 GIT binary patch delta 143 zcmbQHJ5852k(ZZ?0SL}~Uzp~;k(ZrCu7hC#dk5n}##**^hIYm@rWB48rWTGGMi+)= zMn;CsMl9=?8SN)OWKU&u0+LFT-?OPr?&nZubep`H;}a`47n2C{=2e^zSQryFck?we tGfv&iE3}4@ao^-!!rhE#C%cK1GG3azN2HwbI*^o|94Oig)OufZI{+h^+iMu( zpN6mG5i~^yJn-bPh+tK`g^uh(6V7BLdjO&fXIcboOU}{;vb2IDK-iZ@&0uAYzoN7l>Edj!_RAE;nD}iVKuZ@=(AZ9wiR0AR&(f_5@WQLo( zE~>j|&U{je^SeH7`koV_TiXa5Is`e~e>{ha|uo@kAl!5=kOPk|>EF+8^k$+|GuaNjA*x35Rz{ zp^()=!D+M!v9l4BYsJF+2X<~_8SE`n_-5VW8mIWo%=^CgzHjEZeq1kkj#DJKKAyY_ z-kkkXI;H!hLtcUpK7BzFxI>=9020!HBie@#03;ztS^{{cn5B(m(OjXKqK_zAu4tKJ zj3|1p=t?;t2N2N5zKIE}pIK*idV zZ2qV+z=`E`^X_?Z27f?IC@=+E!9h&FwJyr9=Bj*e*5sjaNv>NpxUGV(ty-yNZ$@q) zICrwW9Y_{xdbFsmFHx^#|Nz{@aTi59XEe=1iLk(K;zI_3?Wv{|z z`Pu#s_lA*ErmTss4G?qkRe9>%g1S%vxcxQ};s)Y@n3vzmlbsb6SX8))NUdNi^y21B zTHrff^!8#dmXx5k!`)uW0`A3K!6R`?m8@kYp4f;&5sR$%6%`umgqu70%#HDX|8i9> zSDLUSyOllY$v>67u^H8(uJB9_stZ$dY+6`&Z4^_>b^WmIx~YLv?DoW>{84S-Lr<$~ Fe*v6$qZ 1] self.merged_tracks = merged_tracks diff --git a/tracking/dotrack/dotracks_front.py b/tracking/dotrack/dotracks_front.py index 6eedf3c..a4c7f54 100644 --- a/tracking/dotrack/dotracks_front.py +++ b/tracking/dotrack/dotracks_front.py @@ -45,10 +45,12 @@ class doFrontTracks(doTracks): '''剔除静止目标后的 tracks''' tracks = self.sub_tracks(tracks, static_tracks) - [self.associate_with_hand(htrack, gtrack) for htrack in hand_tracks for gtrack in tracks] + # [self.associate_with_hand(htrack, gtrack) for htrack in hand_tracks for gtrack in tracks] '''轨迹循环归并''' merged_tracks = self.merge_tracks_loop(tracks) + [self.associate_with_hand(htrack, gtrack) for htrack in hand_tracks for gtrack in merged_tracks] + tracks = [t for t in merged_tracks if t.frnum > 1] # for gtrack in tracks: diff --git a/tracking/dotrack/track_select.py b/tracking/dotrack/track_select.py new file mode 100644 index 0000000..d27fd1a --- /dev/null +++ b/tracking/dotrack/track_select.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +""" +Created on Mon Jul 29 10:28:21 2024 + 未来需将这一部分和轨迹分析代码集成 + +@author: ym +""" +import numpy as np +import cv2 +from scipy.spatial.distance import cdist + +class TProp: + def __init__(self, boxes): + + self.boxes = boxes + + + + + +class TProp: + '''抽象基类,不能实例化对象''' + def __init__(self, boxes): + ''' + boxes: [x1, y1, x2, y2, track_id, score, cls, frame_index, box_index] + 0 1 2 3 4 5 6 7 8 + ''' + # assert len(set(boxes[:, 4].astype(int))) == 1, "For a Track, track_id more than 1" + # assert len(set(boxes[:, 6].astype(int))) == 1, "For a Track, class number more than 1" + + self.boxes = boxes + + '''5个关键点(中心点、左上点、右上点、左下点、右下点 )坐标''' + self.compute_cornpoints() + + '''5个关键点轨迹特征,可以在子类中实现,降低顺序处理时的计算量 + (中心点、左上点、右上点、左下点、右下点 )轨迹特征''' + self.compute_cornpts_feats() + + self.distmax = max(self.trajdist) + + + def compute_cornpoints(self): + ''' + cornpoints 共10项,分别是个点的坐标值(x, y) + (center, top_left, top_right, bottom_left, bottom_right) + ''' + boxes = self.boxes + cornpoints = np.zeros((self.frnum, 10)) + cornpoints[:,0] = (boxes[:, 0] + boxes[:, 2]) / 2 + cornpoints[:,1] = (boxes[:, 1] + boxes[:, 3]) / 2 + cornpoints[:,2], cornpoints[:,3] = boxes[:, 0], boxes[:, 1] + cornpoints[:,4], cornpoints[:,5] = boxes[:, 2], boxes[:, 1] + cornpoints[:,6], cornpoints[:,7] = boxes[:, 0], boxes[:, 3] + cornpoints[:,8], cornpoints[:,9] = boxes[:, 2], boxes[:, 3] + + self.cornpoints = cornpoints + def compute_cornpts_feats(self): + ''' + ''' + trajectory = [] + trajlens = [] + trajdist = [] + trajrects = [] + for k in range(5): + # diff_xy2 = np.power(np.diff(self.cornpoints[:, 2*k:2*(k+1)], axis = 0), 2) + # trajlen = np.sum(np.sqrt(np.sum(diff_xy2, axis = 1))) + + X = self.cornpoints[:, 2*k:2*(k+1)] + + traj = np.linalg.norm(np.diff(X, axis=0), axis=1) + trajectory.append(traj) + + trajlen = np.sum(traj) + trajlens.append(trajlen) + + ptdist = np.max(cdist(X, X)) + trajdist.append(ptdist) + + '''最小外接矩形: + rect[0]: 中心(x, y) + rect[1]: (w, h) + rect[0]: 旋转角度 (-90°, 0] + ''' + rect = cv2.minAreaRect(X.astype(np.int64)) + trajrects.append(rect) + + self.trajectory = trajectory + self.trajlens = trajlens + self.trajdist = trajdist + self.trajrects = trajrects \ No newline at end of file diff --git a/tracking/feat_select.py b/tracking/feat_select.py new file mode 100644 index 0000000..8430c79 --- /dev/null +++ b/tracking/feat_select.py @@ -0,0 +1,418 @@ +# -*- coding: utf-8 -*- +""" +Created on Sat Jul 27 14:07:25 2024 + +@author: ym +""" +import os.path +import numpy as np +from scipy.spatial.distance import cdist +import matplotlib.pyplot as plt +import sys +sys.path.append(r"D:\DetectTracking") +from tracking.utils.read_data import extract_data, read_deletedBarcode_file, read_tracking_output +from tracking.dotrack.dotracks import Track + +from tracking.contrast_analysis import performance_evaluate, compute_recall_precision, show_recall_prec + +def compute_similar(feat1, feat2): + + if len(feat1)==0 or len(feat2)==0: + return 0 + + similar = 1 - np.maximum(0.0, cdist(feat1, feat2, metric = 'cosine')) + smean = np.mean(similar) + + return smean + + + + + + +def update_event(datapath): + '''一次购物事件,包含 8 个keys''' + event = {} + # event['front_tracking_boxes'] = [] + # event['front_tracking_feats'] = {} + # event['back_tracking_boxes'] = [] + # event['back_tracking_feats'] = {} + + event['back_sole_boxes'] = np.empty((0, 9), dtype=np.float64) + event['front_sole_boxes'] = np.empty((0, 9), dtype=np.float64) + + event['back_sole_feats'] = np.empty((0, 256), dtype=np.float64) + event['front_sole_feats'] = np.empty((0, 256), dtype=np.float64) + + event['feats_compose'] = np.empty((0, 256), dtype=np.float64) + event['feats_select'] = np.empty((0, 256), dtype=np.float64) + + '''读取当前事件的 data 文件''' + for filename in os.listdir(datapath): + # filename = '1_track.data' + fpath = os.path.join(datapath, filename) + CamerType = filename.split('_')[0] + # if os.path.isfile(fpath) and filename.find("track.data")>0: + # bboxes, ffeats, trackerboxes, tracker_feat_dict, tracking_boxes, tracking_feat_dict = extract_data(fpath) + + # if CamerType == '0': + # event['back_tracking_boxes'] = tracking_boxes + # event['back_tracking_feats'] = tracking_feat_dict + # elif CamerType == '1': + # event['front_tracking_boxes'] = tracking_boxes + # event['front_tracking_feats'] = tracking_feat_dict + + + + if os.path.isfile(fpath) and filename.find("tracking_output.data")>0: + tracking_output_boxes, tracking_output_feats = read_tracking_output(fpath) + if CamerType == '0': + event['back_sole_boxes'] = tracking_output_boxes + event['back_sole_feats'] = tracking_output_feats + elif CamerType == '1': + event['front_sole_boxes'] = tracking_output_boxes + event['front_sole_feats'] = tracking_output_feats + + + '''事件的特征表征方式选择''' + + fs_feats = event['front_sole_feats'] + bs_feats = event['back_sole_feats'] + + '''1. 如果前后摄均没有轨迹选择输出,返回''' + condt1 = len(fs_feats) + len(bs_feats) == 0 + if condt1: + return event + + + '''2. 构造综合特征''' + feats_compose = np.empty((0, 256), dtype=np.float64) + if len(fs_feats): + feats_compose = np.concatenate((feats_compose, fs_feats), axis=0) + if len(bs_feats): + feats_compose = np.concatenate((feats_compose, bs_feats), axis=0) + event['feats_compose'] = feats_compose + + '''3. 构造前摄特征''' + if len(fs_feats): + event['feats_select'] = fs_feats + return event + + + '''4. 从前摄输出轨迹中选取特定轨迹对应的特征''' + ftrboxes = event['front_tracking_boxes'] + ftrfeats = event['front_tracking_feats'] + + condt2 = len(ftrboxes) + len(ftrfeats) == 0 + condt3 = len(ftrfeats) != len(ftrboxes) + if condt2 or condt3: + return event + + bprops = [] + for boxes in ftrboxes: + track = Track(boxes) + bprops.append(max(track.trajdist)) + + index = bprops.index(max(bprops)) + box_select = ftrboxes[index] + tid = int(box_select[0, 4]) + + feat_select = ftrfeats[f"track_{tid}"] + feats_select = np.empty((0, 256), dtype=np.float64) + for fid_bid, feat in feat_select['feats'].items(): + feats_select = np.concatenate((feats_select, feat[None, :]), axis=0) + event['feats_select'] = feats_select + + return event + + +def creatd_deletedBarcode_front(filepath): + # filepath = r'\\192.168.1.28\share\测试_202406\0723\0723_1\deletedBarcode.txt' + + basepath, _ = os.path.split(filepath) + + MatchList = [] + + bcdlist = read_deletedBarcode_file(filepath) + + k = 0 + for s_list in bcdlist: + getout_fold = s_list['SeqDir'].strip() + day, hms = getout_fold.strip('_').split('-') + + ''' 生成取出事件字典 ''' + getout_event = {} + getout_event['barcode'] = s_list['Deleted'].strip() + getout_event['path'] = os.path.join(basepath, getout_fold) + + getout_event['feats_compose'] = np.empty((0, 256), dtype=np.float64) + getout_event['feats_select'] = np.empty((0, 256), dtype=np.float64) + + + InputList = [] + barcodes = [s.strip() for s in s_list['barcode']] + similarity = [float(s.strip()) for s in s_list['similarity']] + for i, barcode in enumerate(barcodes): + + ''' 生成放入事件字典 ''' + input_event = {} + + input_folds, times = [], [] + for pathname in os.listdir(basepath): + if pathname.endswith('_'): continue + if os.path.isfile(os.path.join(basepath, pathname)):continue + + infold = pathname.split('_') + if len(infold)!=2: continue + + day1, hms1 = infold[0].split('-') + + if day1==day and infold[1]==barcode and int(hms1)0: enent_name = '' @@ -368,35 +382,56 @@ def main_loop(): enent_name = prefix[i] + name break spath = os.path.join(savepath, enent_name) - do_tracking(fpath, spath) - - k +=1 - if k==1: - break - + + # abimg = do_tracking(fpath, spath) + # imgs.append(abimg) + try: + abimg = do_tracking(fpath, spath) + imgs.append(abimg) + if len(imgs) == 2: + Img = np.concatenate((imgs[0], imgs[1]), axis = 0) + + H, W = Img.shape[:2] + cv2.line(Img, (0, int(H/2)), (int(W), int(H/2)), (128, 255, 128), 2) + else: + Img = imgs[0] + + imgpath = os.path.join(savepath, enent_name + '_alg.png') + cv2.imwrite(imgpath, Img) + + except Exception as e: + print(f'Error! {fpath}, {e}') + + + + # k +=1 + # if k==1: + # break + def main(): ''' - fpath: data文件,包括 Pipeline 各模块输出 + fpath: data文件地址,该 data 文件包括 Pipeline 各模块输出 save_dir:需包含二级目录,其中一级目录为轨迹图像; 二级目录为与data文件对应的序列图像存储地址。 ''' - fpath = r'\\192.168.1.28\share\测试_202406\0719\719_4\20240719-164209_\0_track.data' - save_dir = r'D:\contrast\dataset\result\20240719-164209_6971284204320_6902890247777\getout' + fpath = r'\\192.168.1.28\share\测试_202406\0723\0723_1\20240723-101506_6906839615771\1_track.data' + save_dir = r'D:\contrast\dataset\result\20240723-101506_\images' do_tracking(fpath, save_dir) if __name__ == "__main__": - try: - # main() - main_loop() - - except Exception as e: - print(f'Error: {e}') + + main_loop() + # main() + # try: + # main_loop() + # except Exception as e: + # print(f'Error: {e}') diff --git a/tracking/utils/__pycache__/plotting.cpython-39.pyc b/tracking/utils/__pycache__/plotting.cpython-39.pyc index 2a0d87bdfe994c63759c409f63842e84f0a37299..751d4080ec113aea32cd5d061ced51988b6ba853 100644 GIT binary patch delta 487 zcmXYt!Al!K6vp41-OWxmS(7YM6hv~UE!sl#Pn{J-^}ANN2;y-dEfVd>;9@Q=*eNpkt_ z{*Lnzw5L-#t$i(ZmvZ=Bs)998308hbQChh*`!Jz1wC*ce7U6DWcVd;S2%Y^rL@D;| z@SIF;h38K>4|>kM$W~rQe}fXLluB16c}25Ij*_1o%29^0%HOsSRwgM~Pc%RWfei>ABz9>&b<6{wf?*<3ml3^3*)%L%aM-2uT@kZebPR9?0_kj$zjQh&qok0{& z4o~%8Tcsrxo*ARbxV9p0zniwjh?~P>uV1nNPiCZJV;0lcjV~}SBx^px69ER?b+`IP GBt8NN&w#4{ delta 408 zcmXYty-EW?6ov1do!y=NGn*|G5z#_~D3Z1C1vHh~r4sx>7!oufxU6V#hZGyoCZH?? zAqWXr*h(O!rH#*Eoj0(ua5ixU4(FV27%q1rUuAF}1TN_FHhFFwy$2tg?O&ZFO4b2o zkU^NC;wcc%P%C8EGLp3>)S(H=OtI)|aPoP~l%?#H5sWE)jdzfQ*I>VDc2wU zb2l}mnE88Xpme0$5#-d0QOYDPEhrKA6v&_x-+kFz@&L(OKQqb&be)|LsHY z<+J`ZQ=FAmDqWRlK(nJ?8B0~-Lp&b42{EqF>vt;q>O*^zL{*h=b6*|)0rJ=a65D*z zD<|ZDcqbFd^yhS(TX*^W zsvYMmcAc>vtJ=;K4)eo{B46Ka`+XkvB9ZO0FyhXvpq|U!zI-8aJ3GBye;{%};JbVv zu&4zf@R7DUBTUZR_Jc6$v{J9-g>5dt$M4!{c!kH>-jo6*pm1K&gjLA}g{_TV6s`fh z#2@3_sLD;SISHW#Vb^ChysKY;r?{t|gU0BSzO2mE(iZhU(*3c5#M|^TE)iGohGF5E z(z6A2ITe>AoMLkf|{8C6(*nzRQU^Y6@Zlh delta 373 zcmcbi_Cb|5k(ZZ?0SI%GEH|Fx4>E2-Jwyh^MgyGiXXpe#&u)NmFR@8O};sO^I6^DTyVC1&JjYx7d=B z@+(q{quA2YQWHyxqb8Sdr7=cLzRl$#5+zhpl$e~InU@|9l8aBtOfH#h#;wHIH#w5K zl}~_?gHeM~fKiCifvL!T^CxZ}M#j#`_Piy6WdBxX)75LjY#i_^6tIkli9Ge7SZYe7+FUWq1u6g$YQ z0HBi@(~2yBN~5@n3vx0`;?r^x({D|-6Le&>oZKL&z