From e044c85a0451f1b0a98906c1964a1c834a7f8cba Mon Sep 17 00:00:00 2001 From: 18262620154 <12819888+ygest0201@user.noreply.gitee.com> Date: Fri, 11 Apr 2025 17:02:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E5=8D=95=E5=B8=A7?= =?UTF-8?q?=E5=85=A5=E4=BE=B5=E5=88=A4=E6=96=AD=E5=8F=8AyoloV10?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __pycache__/export.cpython-312.pyc | Bin 54366 -> 54366 bytes __pycache__/move_detect.cpython-312.pyc | Bin 0 -> 10296 bytes __pycache__/pipeline_01.cpython-312.pyc | Bin 0 -> 14678 bytes __pycache__/track_reid.cpython-312.pyc | Bin 29709 -> 36817 bytes pipeline_01.py => bakeup/pipeline.py | 328 ++++++------- contrast/__pycache__/__init__.cpython-312.pyc | Bin 209 -> 209 bytes .../__pycache__/event_test.cpython-312.pyc | Bin 0 -> 11508 bytes contrast/__pycache__/genfeats.cpython-312.pyc | Bin 0 -> 8337 bytes .../one2n_contrast.cpython-312.pyc | Bin 0 -> 13024 bytes contrast/event_test.py | 249 +++++----- .../__pycache__/config.cpython-312.pyc | Bin 2407 -> 2407 bytes .../__pycache__/inference.cpython-312.pyc | Bin 23532 -> 23414 bytes .../model/__pycache__/CBAM.cpython-312.pyc | Bin 5360 -> 5360 bytes .../model/__pycache__/Tool.cpython-312.pyc | Bin 3344 -> 3344 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 881 -> 881 bytes .../__pycache__/fmobilenet.cpython-312.pyc | Bin 7615 -> 7615 bytes .../model/__pycache__/lcnet.cpython-312.pyc | Bin 11835 -> 11835 bytes .../model/__pycache__/loss.cpython-312.pyc | Bin 1190 -> 1190 bytes .../model/__pycache__/metric.cpython-312.pyc | Bin 4840 -> 4840 bytes .../__pycache__/mobilenet_v2.cpython-312.pyc | Bin 9222 -> 9222 bytes .../__pycache__/mobilenet_v3.cpython-312.pyc | Bin 14026 -> 14026 bytes .../__pycache__/mobilevit.cpython-312.pyc | Bin 15320 -> 15320 bytes .../model/__pycache__/resbam.cpython-312.pyc | Bin 8217 -> 8217 bytes .../__pycache__/resnet_face.cpython-312.pyc | Bin 6929 -> 6929 bytes .../__pycache__/resnet_pre.cpython-312.pyc | Bin 21975 -> 21975 bytes .../model/__pycache__/utils.cpython-312.pyc | Bin 346 -> 346 bytes contrast/genfeats.py | 4 +- contrast/one2n_contrast.py | 48 +- contrast/one2one_contrast.py | 437 +++--------------- contrast/onsite_contrast_pr.py | 26 +- contrast/trail2trail.py | 172 +++++++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 215 bytes .../utils/__pycache__/calsimi.cpython-312.pyc | Bin 0 -> 5739 bytes .../__pycache__/databits.cpython-312.pyc | Bin 0 -> 6890 bytes .../utils/__pycache__/event.cpython-312.pyc | Bin 0 -> 24367 bytes .../utils/__pycache__/tools.cpython-312.pyc | Bin 0 -> 6509 bytes contrast/utils/calsimi.py | 216 +++++++++ contrast/utils/databits.py | 127 +++++ contrast/utils/event.py | 10 +- contrast/utils/tools.py | 73 +++ execute_pipeline.py | 52 ++- .../hand_inference.cpython-312.pyc | Bin 5554 -> 5554 bytes models/__pycache__/__init__.cpython-312.pyc | Bin 140 -> 140 bytes models/__pycache__/common.cpython-312.pyc | Bin 66172 -> 66172 bytes .../__pycache__/experimental.cpython-312.pyc | Bin 7811 -> 7976 bytes models/__pycache__/yolo.cpython-312.pyc | Bin 29596 -> 29596 bytes pipeline.py | 313 +++++++------ .../event_time_specify.cpython-312.pyc | Bin 0 -> 13250 bytes .../intrude_detect.cpython-312.pyc | Bin 0 -> 3294 bytes realtime/event_time_specify.py | 13 +- realtime/intrude_detect.py | 420 +++++++++++++++++ realtime/time_devide.py | 13 +- track_reid.py | 14 +- tracking/__pycache__/__init__.cpython-312.pyc | Bin 142 -> 142 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 150 -> 150 bytes .../__pycache__/dotracks.cpython-312.pyc | Bin 32967 -> 32967 bytes .../__pycache__/dotracks_back.cpython-312.pyc | Bin 11414 -> 11712 bytes .../dotracks_front.cpython-312.pyc | Bin 9318 -> 9318 bytes .../__pycache__/track_back.cpython-312.pyc | Bin 11736 -> 11736 bytes .../__pycache__/track_front.cpython-312.pyc | Bin 8240 -> 8240 bytes tracking/dotrack/dotracks_back.py | 14 +- .../__pycache__/__init__.cpython-312.pyc | Bin 329 -> 329 bytes .../__pycache__/basetrack.cpython-312.pyc | Bin 2894 -> 2894 bytes .../__pycache__/bot_sort.cpython-312.pyc | Bin 10785 -> 10673 bytes .../__pycache__/byte_tracker.cpython-312.pyc | Bin 25184 -> 25184 bytes .../__pycache__/track.cpython-312.pyc | Bin 3520 -> 3520 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 157 -> 157 bytes .../__pycache__/kalman_filter.cpython-312.pyc | Bin 17874 -> 17874 bytes .../__pycache__/matching.cpython-312.pyc | Bin 11466 -> 11466 bytes tracking/tracking_pipeline.py | 270 ++++++----- .../__pycache__/__init__.cpython-312.pyc | Bin 405 -> 405 bytes .../__pycache__/annotator.cpython-312.pyc | Bin 3079 -> 3079 bytes .../__pycache__/drawtracks.cpython-312.pyc | Bin 17034 -> 17034 bytes .../__pycache__/iterYaml.cpython-312.pyc | Bin 3807 -> 3807 bytes .../__pycache__/mergetrack.cpython-312.pyc | Bin 7095 -> 7095 bytes .../__pycache__/plotting.cpython-312.pyc | Bin 21283 -> 21283 bytes .../__pycache__/proBoxes.cpython-312.pyc | Bin 3667 -> 3667 bytes .../__pycache__/read_data.cpython-312.pyc | Bin 30036 -> 30036 bytes .../__pycache__/showtrack.cpython-312.pyc | Bin 12743 -> 12743 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 772 -> 771 bytes .../cfg/__pycache__/__init__.cpython-312.pyc | Bin 26679 -> 26678 bytes .../data/__pycache__/__init__.cpython-312.pyc | Bin 469 -> 468 bytes .../data/__pycache__/augment.cpython-312.pyc | Bin 68488 -> 68487 bytes .../data/__pycache__/base.cpython-312.pyc | Bin 18861 -> 18860 bytes .../data/__pycache__/build.cpython-312.pyc | Bin 8729 -> 8728 bytes .../__pycache__/converter.cpython-312.pyc | Bin 19267 -> 19266 bytes .../data/__pycache__/dataset.cpython-312.pyc | Bin 22631 -> 22630 bytes .../data/__pycache__/loaders.cpython-312.pyc | Bin 32556 -> 33683 bytes .../data/__pycache__/utils.cpython-312.pyc | Bin 41893 -> 41892 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 240 -> 239 bytes .../__pycache__/explorer.cpython-312.pyc | Bin 24259 -> 24258 bytes .../__pycache__/utils.cpython-312.pyc | Bin 10472 -> 10471 bytes ultralytics/data/loaders.py | 26 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 153 -> 152 bytes .../__pycache__/exporter.cpython-312.pyc | Bin 0 -> 71382 bytes .../engine/__pycache__/model.cpython-312.pyc | Bin 45491 -> 45490 bytes .../__pycache__/predictor.cpython-312.pyc | Bin 24360 -> 24359 bytes .../__pycache__/results.cpython-312.pyc | Bin 43421 -> 43420 bytes .../__pycache__/trainer.cpython-312.pyc | Bin 48117 -> 48116 bytes .../__pycache__/validator.cpython-312.pyc | Bin 21120 -> 21119 bytes .../hub/__pycache__/__init__.cpython-312.pyc | Bin 6856 -> 6855 bytes .../hub/__pycache__/auth.cpython-312.pyc | Bin 6061 -> 6060 bytes .../hub/__pycache__/utils.cpython-312.pyc | Bin 11407 -> 11406 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 366 -> 365 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 382 -> 381 bytes .../fastsam/__pycache__/model.cpython-312.pyc | Bin 1688 -> 1687 bytes .../__pycache__/predict.cpython-312.pyc | Bin 5754 -> 5753 bytes .../__pycache__/prompt.cpython-312.pyc | Bin 22669 -> 22668 bytes .../fastsam/__pycache__/utils.cpython-312.pyc | Bin 2725 -> 2724 bytes .../fastsam/__pycache__/val.cpython-312.pyc | Bin 2434 -> 2433 bytes .../nas/__pycache__/__init__.cpython-312.pyc | Bin 316 -> 315 bytes .../nas/__pycache__/model.cpython-312.pyc | Bin 4318 -> 4317 bytes .../nas/__pycache__/predict.cpython-312.pyc | Bin 3083 -> 3082 bytes .../nas/__pycache__/val.cpython-312.pyc | Bin 2365 -> 2364 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 328 -> 327 bytes .../rtdetr/__pycache__/model.cpython-312.pyc | Bin 2513 -> 2512 bytes .../__pycache__/predict.cpython-312.pyc | Bin 4760 -> 4759 bytes .../rtdetr/__pycache__/train.cpython-312.pyc | Bin 4899 -> 4898 bytes .../rtdetr/__pycache__/val.cpython-312.pyc | Bin 7135 -> 7134 bytes .../sam/__pycache__/__init__.cpython-312.pyc | Bin 267 -> 266 bytes .../sam/__pycache__/amg.cpython-312.pyc | Bin 12232 -> 12231 bytes .../sam/__pycache__/build.cpython-312.pyc | Bin 4561 -> 4560 bytes .../sam/__pycache__/model.cpython-312.pyc | Bin 5727 -> 5726 bytes .../sam/__pycache__/predict.cpython-312.pyc | Bin 27492 -> 27491 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 165 -> 164 bytes .../__pycache__/decoders.cpython-312.pyc | Bin 10109 -> 10108 bytes .../__pycache__/encoders.cpython-312.pyc | Bin 33059 -> 33058 bytes .../modules/__pycache__/sam.cpython-312.pyc | Bin 3369 -> 3368 bytes .../__pycache__/tiny_encoder.cpython-312.pyc | Bin 38129 -> 38128 bytes .../__pycache__/transformer.cpython-312.pyc | Bin 13066 -> 13065 bytes .../yolo/__pycache__/__init__.cpython-312.pyc | Bin 402 -> 401 bytes .../yolo/__pycache__/model.cpython-312.pyc | Bin 5373 -> 5372 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 466 -> 465 bytes .../__pycache__/predict.cpython-312.pyc | Bin 4128 -> 4127 bytes .../__pycache__/train.cpython-312.pyc | Bin 10300 -> 10299 bytes .../classify/__pycache__/val.cpython-312.pyc | Bin 7972 -> 7971 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 349 -> 348 bytes .../__pycache__/predict.cpython-312.pyc | Bin 2354 -> 2353 bytes .../detect/__pycache__/train.cpython-312.pyc | Bin 9081 -> 9080 bytes .../detect/__pycache__/val.cpython-312.pyc | Bin 20856 -> 20855 bytes .../obb/__pycache__/__init__.cpython-312.pyc | Bin 328 -> 327 bytes .../obb/__pycache__/predict.cpython-312.pyc | Bin 3250 -> 3249 bytes .../obb/__pycache__/train.cpython-312.pyc | Bin 2350 -> 2349 bytes .../yolo/obb/__pycache__/val.cpython-312.pyc | Bin 13076 -> 13075 bytes .../pose/__pycache__/__init__.cpython-312.pyc | Bin 332 -> 331 bytes .../pose/__pycache__/predict.cpython-312.pyc | Bin 3883 -> 3882 bytes .../pose/__pycache__/train.cpython-312.pyc | Bin 4372 -> 4371 bytes .../yolo/pose/__pycache__/val.cpython-312.pyc | Bin 14800 -> 14799 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 359 -> 358 bytes .../__pycache__/predict.cpython-312.pyc | Bin 3886 -> 3885 bytes .../segment/__pycache__/train.cpython-312.pyc | Bin 3489 -> 3488 bytes .../segment/__pycache__/val.cpython-312.pyc | Bin 16724 -> 16723 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 348 -> 347 bytes .../yolov10/__pycache__/card.cpython-312.pyc | Bin 1735 -> 1734 bytes .../yolov10/__pycache__/model.cpython-312.pyc | Bin 2046 -> 2045 bytes .../__pycache__/predict.cpython-312.pyc | Bin 2878 -> 2877 bytes .../yolov10/__pycache__/train.cpython-312.pyc | Bin 1548 -> 1547 bytes .../yolov10/__pycache__/val.cpython-312.pyc | Bin 1837 -> 1836 bytes .../nn/__pycache__/__init__.cpython-312.pyc | Bin 562 -> 561 bytes .../__pycache__/autobackend.cpython-312.pyc | Bin 35820 -> 35819 bytes .../nn/__pycache__/tasks.cpython-312.pyc | Bin 61116 -> 61277 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 2292 -> 2291 bytes .../modules/__pycache__/block.cpython-312.pyc | Bin 60949 -> 60948 bytes .../modules/__pycache__/conv.cpython-312.pyc | Bin 22432 -> 22431 bytes .../modules/__pycache__/head.cpython-312.pyc | Bin 38289 -> 38288 bytes .../__pycache__/transformer.cpython-312.pyc | Bin 28571 -> 28570 bytes .../modules/__pycache__/utils.cpython-312.pyc | Bin 4412 -> 4411 bytes ultralytics/nn/tasks.py | 7 +- .../__pycache__/__init__.cpython-312.pyc | Bin 50371 -> 50370 bytes .../__pycache__/autobatch.cpython-312.pyc | Bin 5324 -> 5323 bytes .../utils/__pycache__/checks.cpython-312.pyc | Bin 36740 -> 36739 bytes .../utils/__pycache__/dist.cpython-312.pyc | Bin 3501 -> 3500 bytes .../__pycache__/downloads.cpython-312.pyc | Bin 26967 -> 26966 bytes .../utils/__pycache__/files.cpython-312.pyc | Bin 9245 -> 9244 bytes .../__pycache__/instance.cpython-312.pyc | Bin 21531 -> 21530 bytes .../utils/__pycache__/loss.cpython-312.pyc | Bin 44134 -> 44133 bytes .../utils/__pycache__/metrics.cpython-312.pyc | Bin 71188 -> 71187 bytes .../utils/__pycache__/ops.cpython-312.pyc | Bin 44038 -> 44037 bytes .../utils/__pycache__/patches.cpython-312.pyc | Bin 3469 -> 3468 bytes .../__pycache__/plotting.cpython-312.pyc | Bin 61485 -> 61484 bytes .../utils/__pycache__/tal.cpython-312.pyc | Bin 20417 -> 20416 bytes .../__pycache__/torch_utils.cpython-312.pyc | Bin 37739 -> 37738 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 303 -> 302 bytes .../__pycache__/base.cpython-312.pyc | Bin 6307 -> 6306 bytes .../callbacks/__pycache__/hub.cpython-312.pyc | Bin 0 -> 4638 bytes utils/__pycache__/__init__.cpython-312.pyc | Bin 3874 -> 3874 bytes .../__pycache__/augmentations.cpython-312.pyc | Bin 25186 -> 25186 bytes utils/__pycache__/autoanchor.cpython-312.pyc | Bin 11754 -> 11754 bytes utils/__pycache__/dataloaders.cpython-312.pyc | Bin 78497 -> 79841 bytes utils/__pycache__/downloads.cpython-312.pyc | Bin 7183 -> 7183 bytes utils/__pycache__/general.cpython-312.pyc | Bin 65711 -> 65711 bytes utils/__pycache__/getsource.cpython-312.pyc | Bin 2746 -> 2746 bytes utils/__pycache__/metrics.cpython-312.pyc | Bin 20569 -> 20569 bytes utils/__pycache__/plots.cpython-312.pyc | Bin 31613 -> 31613 bytes utils/__pycache__/torch_utils.cpython-312.pyc | Bin 30339 -> 30339 bytes utils/__pycache__/triton.cpython-312.pyc | Bin 0 -> 5645 bytes utils/dataloaders.py | 28 +- 197 files changed, 1863 insertions(+), 997 deletions(-) create mode 100644 __pycache__/move_detect.cpython-312.pyc create mode 100644 __pycache__/pipeline_01.cpython-312.pyc rename pipeline_01.py => bakeup/pipeline.py (72%) create mode 100644 contrast/__pycache__/event_test.cpython-312.pyc create mode 100644 contrast/__pycache__/genfeats.cpython-312.pyc create mode 100644 contrast/__pycache__/one2n_contrast.cpython-312.pyc create mode 100644 contrast/trail2trail.py create mode 100644 contrast/utils/__pycache__/__init__.cpython-312.pyc create mode 100644 contrast/utils/__pycache__/calsimi.cpython-312.pyc create mode 100644 contrast/utils/__pycache__/databits.cpython-312.pyc create mode 100644 contrast/utils/__pycache__/event.cpython-312.pyc create mode 100644 contrast/utils/__pycache__/tools.cpython-312.pyc create mode 100644 contrast/utils/calsimi.py create mode 100644 contrast/utils/databits.py create mode 100644 realtime/__pycache__/event_time_specify.cpython-312.pyc create mode 100644 realtime/__pycache__/intrude_detect.cpython-312.pyc create mode 100644 realtime/intrude_detect.py create mode 100644 ultralytics/engine/__pycache__/exporter.cpython-312.pyc create mode 100644 ultralytics/utils/callbacks/__pycache__/hub.cpython-312.pyc create mode 100644 utils/__pycache__/triton.cpython-312.pyc diff --git a/__pycache__/export.cpython-312.pyc b/__pycache__/export.cpython-312.pyc index 653e078d8685189a85336d65b34e5715808cb3eb..2bfe2157db15d2715e78e30a465c55a80e211da2 100644 GIT binary patch delta 23 dcmcb&g8AMGW}ef$yj%=GU>5u=eIrlM6#!rH2gd*a delta 23 dcmcb&g8AMGW}ef$yj%=GQ0ulRZ6i<66#!r{2fP3P diff --git a/__pycache__/move_detect.cpython-312.pyc b/__pycache__/move_detect.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..65fb932187abfe112eaf829abf70d6feb5565f2a GIT binary patch literal 10296 zcmd5iZEO=~nltuzVmnS8f5ZVoh!Y6K5CRT?77BC&fu$7aQBqwuS?V($CpaHYGUL!B zI4iVQx|40H*ubt0+uL<0QXSY8X|JbESNv%EYo*gk7?;JJ<)oaB(B)TCsBVw@bN4*& zc*c%#Kh)Dn_ey@h=6Rp@nRlM=*Z*8rW~88OJ9fYO$_k45cN{2%$#xzcf=-O$s1Ayw zIZYqkp&_ldLkq38kLlNS=x9nq{gC3A*C|eSO(U=DV96W{b0z9r$*9JqA8R)5<^A4} zpK}fbormG~qA%ohw>aIKcWid=Xl`*fZ*Fce8h_v&4xJp}cQ{A;jSmp%5f?4#d|W^X z`Q$z1I=dnDXg7>wl%MLLfm{t|;ON(BAk)Zcpk+Ai>r{u1D+My?4wlowsDuOZI`o{0 zD}gz~sNPj38QOWTuXjK1?e=N&b}4~Ajvvj^xJj4}Qy%qkNQDg39K9UouK^SmfKte# zmOyC=pmG>Autqt3%0PumWlR*+V^Vs#7WRX0b5_G?yOvkSLSkUA-0~X+%u&YQcpoSnZmXkPgH%wFx6A7tj)C?qpSj0^}PVLHV32hu4Owk zHA=a3M_d{nNqE3QrS$QXAK-_5fO6ofkaQ;oM*M=L4Fp4y*4GEUP=J&4f&Omcq<7FS zX@Y~2wm%Sr$~z*l+%O*qc1v2pAClPNU|?w2FR@-BGzy?>H$N~uC`hJ&;PDOc!NCDU zS{e}csspQUpnq^UFlf`O37GiFs;xk;JBLlb79IzweDSBT7{@vhAg8IHF{ zPp56GVXQA4XO=l(x@?i93@_1ltCq)3MNh^3ms=A8ka=-E)2a%>LP}f3VE8 z&e`94Hr@E#O~(&lP3gU=6>m5HX8XnMiI=aslip;@bmyIhr&A42-_WKTcBZR$rK@(| zbUcTkfPSU(PIY6dx-t1ux_Yz7e5zlT(VOn*Yg78#+xogkKr`i2xd;Y2_z{WhAQBnM zN*u~uPd*$jgp!pLda0a*>0W>x*L=s-nxd<m z9&)Rzgh#QJ7(dqyG7u2@{9PeQ2O4`|P$~%se4zVe2n0$vF%Sw3^z*0$1(ZPGa4h^v z=<~~<8gt~BH(!KM(uE{cXQ+D?d!#+q5$(84C)^1pRoRfXtWDZemW?8Nx55@_iye#} zyfl=ki-%J7HR+0mB$KLW6m@s4l@Tu16YaTdNwg;HDaYEh^{M2V>lswRSRnj$N)x98IiARXvrqtxL9C-!-#q&XU^j>>QWcuqS2PBkJcJt8O`V zCK{khZi8y}Z^hD#dBsir3Vsz3>r5pqbEo(SU&NQgwETfFUYK|ELO%nz<1#&0Ms*pOFrPMJikBh7X$R#VY ztgf!iV)AL!y?_d`LfIQ|FTs$d@*6Oe6kyO7U?`*^OMM;!+Nk41q;sbbX2w8ya7>utba<{fI-6B9V}!WYFYshH5bL zo}wU<5(eQ`TrY(JrKPFK{R{|w4@z-C$r=8zR)JSqPzu^Gi*gGln7EI)IE;>iN+~#b zWy8OQX`?LFa;;iH!MSkuJ@@7Z(;t3uV{$=!V?n%jKYsn*+||#2`r+r7USIf!$o<66 z7S7!G;)XcV=p6mx#>5glh;5zE9}M~VMknYM59%1XN7PHBQ&uk7`Rsr^axFo`Bl)s& z12Ts_mr2%o70{P-V}5=B9ECoAP}1?-6e` zH)%<_XKd5mi4F0er0h-bv|?Gz95r9jyvt6rSB8^EXX$rNr=44FSF|kZD95TrJ!Pwo zHAS1Q*b=Y2Qrkc#Ebz<9FFUkf24XaX+=ZJx*0LA~c211il z1L2(7&+|o!c^AdjEHN95s+tt_sVL~I=R}l0P0R*UU^Wy;MQtkMtnx3iGHV2Ksxl0U zP*GXqx?B`U6IR({5Md;(*;4kUJ`Y?Nn;^|4llk3L~pcM5o-Lf$o zH|G4S9yO*=@PleI%08l^068rxzwy$%lPp!AF}>?RU91V06jQ5V{YlkSgMY>LsPR?a zZmOvO1s%wb{=(`m4o#wh7I3_{oD7?dqb1@hT7hz;SHyOf+A6#@|DKR z;FQY>PFXb%-{-uQ{m0A0`7N{8oY-4Pmpy z_IvqWKS!4EE#v`t8%e{3_-$k?`2Cz9X$C_WAVU|O9OVeIEeRf^GI@KCd>ms{Im5W* z!2wt={86!qmdcnhYJ||hY>jMvb4+CJnaZaQOdPo2i#MF_Nz_F=X;XtpXRKA1=(s!1 zL^mXKm%$<=xarcAbwhF}W!Ws!Kd%#8#nlt+cLcjvQ5o^ZE$2%`-B&ENqUKkX2~C8B z*u{cTN440RF;_(PPn-rjbJt#VexJB+9-a(cs*8l8)#9GJR(ot+bX~kT!Crh8BN#em zT`%sv2d}W@&5^kK=i`|QN31Mb79WcHKCP(75xivFeW466W=ySsG_E~=K-`xxS*8w6 z9Ew{eUz~^T^ApcUypxAAChOF}iGz`$$-@{i`OmM951ng*tU>HY(I1`fjA)=6Z@x4X z-x~dKL?g%g&s=;au_x)6egQ)GSxc&VOS-Bh!elD!vC?R1e9r~*e1-i^#oAQG+Qg|( zE1EJDl`&J)6mJLe=Amzh8shaxo=j=;h4QbeD2Tzx-shVZS5RfPslyY8;|+f@ITxR! ztTl^!XsW74WZo)$GR{K(jhN9lpcA9ObU=!!SgZwJIj}cGOhpq1IdzpYvvM*aYe2MN zx<`%1V5@A&nI=%>ZV+Vp7&Sv5fxsChBP$Ah!2d+HV46ruN%tU0Lh*Y5NYX-Iz~~QI zT;^|M&v5^shro>4bIhHa4FkALfMoU8dR36qrZ5!Fep+M+*rl*=+9gn00|ZiG4Q6a0 zTcdh%#lrTYjKXAdJ`Bg;JLLuOy6=Tehgcw>EX2lsFKi^A4cJJ~mq%O4_rj*oR)|dx z9s|k6jnKRey(4vGf>DV&g1ZLr@8qnV0lp4KWd%hr!#u`z1%)fYTpz4AKvqkiwT2|B z`)??6^he^rdRX{i1S%IRTSyY=v3-G{x33$_*8nePu6Q@X7zy+8C~*=4a_J^@GuX!v zCoxdL1k}x>-a_gYiS-QxxsY2xGEuhWB1<^(z7X<;0=@#?mnYwXCBlC~1@djSO^r>A z#p~iP#l7%rNSPs7tIXENPk`z_5nr1!*NM!$eqW~C8fl;C6}5NGmZ{N+(W#$I{3I?U z+!s$Jgrs}=)Xh~*Y4awL`9FP}u~bI7qSd!7hZ6Qg*EDu!?Xz9)Vdo?JM_nIRi|oAF zcE?JfC2^SqDeIGq90(?4Gjj+ zE+ZzxgWi6>$0Hd%pisEsKJ1%3o}poHpZtWc0Z@{2zUy+nNj79QPklB;3uCjq;kD9kq z)3-m$_eFXrU25RV9d2`)Rfkz>4xit<7J@2wIMZp$l36y zX41?6#JCpl0hC-uVTLBNufeU-5t27@l}qdiVxJ`)xi-rA){<@*Zh@YWn2^7JkVl$% zB!|b-A=w^Z@AGYfWc2d9ceELO1BvY;sCYb7i4EbMkC62h_yDfOQYg}?*O=fE&^x|$4b0<$y9>>G-+U zYp+_8tx5ZIN9eWo)> zUl>hTei2S~rX1VRPkVgJv0Xs6{KRbCvz}R!8CSVAA#-a{<2z1+xuxNoX|mr8VioY+ zG(|6cXbi{&deRowz!!8d@O6owr}8Kek}Ytht5vx8i9O(3kv)p|c?zGwE_Sj@73{)% z!!Ef5NA^vQLm~ijy}BNiqZOJUGpwd|z>BQJjBUPzEjb6!V{nnB@+O=}k#vS4Kb#i5 zGN5@Sp}Cgu_LA#gmA5soDO|p!hrS#tFaGbaLYwI_@PpV#5+tKAe8MC1E774uuS%sS zy+KZy-iW~H0FtDruNM?_C@>HNtBbBM!6nflK7V17)K?rn> zF5!J;@_m37{s`3>Y91oKYKWrPdA;ki`gLi?*6FqJqsi9m`)2mdy00BLHA@-}PUzB=(DCH<#_qLD!@$Pm3(x znm+aC%4!m0-7(dsOtlHkZLnlo%CQpfJV9RIqVuzLP3e_;XV`@MgVnR%-=BQ%Bz)wIz9p87faUYdEAf$C$Xaxcq# zyn=!H6GzS7Qs$Eu2I?g;1}kKXfa*L3m*f2N(Bb`9y$Dsl7tV0J_q8!|o*KakJV5~k z2vmsPBs0Bk{Lb( zlg6xHN1BD%H=MFva4t;6@4t2V-rOIYgpHjGV(c%|$tBP-IO)25FLQ3(U#{kn0$v z!C@TMo}$4_ zSc#bc0|YJ*FnHGOSz-`~A^}Gnt&WQUX9XP?Z?-+bpMq(rRQ(#BLYGB==SvPgXF%rR zk+27yDx5wcoRq8eR=xj*$uZEcAcZ+ z+fwG;H}$(8Kh#oHO^+q>ZUKF*v$pNbuWh@T_nF;b#PEMyV7g8~!~3w}up&{xDE3Zc zg=`_2t!GWesx8va|tFDcH*huTj9vUq= z$KqOwwSKA5=$?C|ReExSfGEJDFY$P|0Urb_x*#NcMhSPrpOQ{BOAf&o7#wX91|dZB z_BCM&)eHGoIdO~1SEhn!bd@qmzf%r>cJm^DpvDrKpjy<@H2o#R(99zvMce*N8UK}9 a_gD6qhIV{OVg1)Wrj@3jdq`nTDEuG2Et%B- literal 0 HcmV?d00001 diff --git a/__pycache__/pipeline_01.cpython-312.pyc b/__pycache__/pipeline_01.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..99009816b5484b9ba020232fc66457cdd1f8ce7d GIT binary patch literal 14678 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 F{|DXU;MM>D delta 3511 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 \ and len(evtname.split('_')[-1])>=8 \ and evtname.split('_')[-1].isdigit() else '' - - '''事件结果存储文件夹: savepath_pipe, savepath_pkl''' + '''事件结果存储文件夹''' if not savepath: savepath = Path(__file__).resolve().parents[0] / "events_result" - savepath_pipe = Path(savepath) / Path("yolos_tracking") / evtname + savepath_pipeline = Path(savepath) / Path("Yolos_Tracking") / evtname - savepath_pkl = Path(savepath) / "shopping_pkl" - if not savepath_pkl.exists(): - savepath_pkl.mkdir(parents=True, exist_ok=True) - pklpath = Path(savepath_pkl) / Path(str(evtname)+".pickle") - yrtDict = {} - - yrt_out = [] - if DataType == "raw": - ### 不重复执行已经过yolo-resnet-tracker - # if pklpath.exists(): - # print(f"Pickle file have saved: {evtname}.pickle") - # return + """ShoppingDict pickle 文件保存地址 """ + savepath_spdict = Path(savepath) / "ShoppingDict_pkfile" + if not savepath_spdict.exists(): + savepath_spdict.mkdir(parents=True, exist_ok=True) + pf_path = Path(savepath_spdict) / Path(str(evtname)+".pickle") - if SourceType == "video": - vpaths = get_video_pairs(eventpath) - elif SourceType == "image": - vpaths = get_image_pairs(eventpath) - - - - for vpath in vpaths: - '''================= 2. 事件结果存储文件夹 =================''' - - - if isinstance(vpath, list): - savepath_pipe_imgs = savepath_pipe / Path("images") - else: - savepath_pipe_imgs = savepath_pipe / Path(str(Path(vpath).stem)) - - if not savepath_pipe_imgs.exists(): - savepath_pipe_imgs.mkdir(parents=True, exist_ok=True) - - optdict = {} - optdict["weights"] = weights - optdict["source"] = vpath - optdict["save_dir"] = savepath_pipe_imgs - optdict["is_save_img"] = saveimages - optdict["is_save_video"] = True - - - if YoloVersion == "V5": - yrtOut = yolo_resnet_tracker(**optdict) - elif YoloVersion == "V10": - yrtOut = yolov10_resnet_tracker(**optdict) - - yrt_out.append((vpath, yrtOut)) - - elif DataType == "pkl": - pass - - else: - return - - + # if pf_path.exists(): + # print(f"Pickle file have saved: {evtname}.pickle") + # return '''====================== 构造 ShoppingDict 模块 =======================''' ShoppingDict = {"eventPath": eventpath, @@ -241,13 +112,16 @@ def pipeline(eventpath, "backCamera": {}, "one2n": [] # } + yrtDict = {} + + procpath = Path(eventpath).joinpath('process.data') if procpath.is_file(): SimiDict = read_similar(procpath) ShoppingDict["one2n"] = SimiDict['one2n'] - event_tracks = [] - for vpath, yrtOut in yrt_out: + + for vpath in vpaths: '''================= 1. 构造相机事件字典 =================''' CameraEvent = {"cameraType": '', # "front", "back" "videoPath": '', @@ -266,10 +140,34 @@ def pipeline(eventpath, CameraEvent["cameraType"] = "back" if bname.split('_')[0] == "1" or bname.find('front')>=0: CameraEvent["cameraType"] = "front" + + '''================= 2. 事件结果存储文件夹 =================''' + if isinstance(vpath, list): + savepath_pipeline_imgs = savepath_pipeline / Path("images") + else: + savepath_pipeline_imgs = savepath_pipeline / Path(str(Path(vpath).stem)) + if not savepath_pipeline_imgs.exists(): + savepath_pipeline_imgs.mkdir(parents=True, exist_ok=True) - '''2种保存方式: (1) save images, (2) no save images''' - ### (1) save images + savepath_pipeline_subimgs = savepath_pipeline / Path("subimgs") + if not savepath_pipeline_subimgs.exists(): + savepath_pipeline_subimgs.mkdir(parents=True, exist_ok=True) + + + '''================= 3. Yolo + Resnet + Tracker =================''' + optdict["source"] = vpath + optdict["save_dir"] = savepath_pipeline_imgs + optdict["is_save_img"] = True + optdict["is_save_video"] = True + + + if YoloVersion == "V5": + yrtOut = yolo_resnet_tracker(**optdict) + elif YoloVersion == "V10": + yrtOut = yolov10_resnet_tracker(**optdict) + + yrtOut_save = [] for frdict in yrtOut: fr_dict = {} @@ -279,7 +177,6 @@ def pipeline(eventpath, yrtOut_save.append(fr_dict) CameraEvent["yoloResnetTracker"] = yrtOut_save - ### (2) no save images # CameraEvent["yoloResnetTracker"] = yrtOut '''================= 4. tracking =================''' @@ -322,58 +219,108 @@ def pipeline(eventpath, yrtDict["frontyrt"] = yrtOut '''========================== 保存模块 =================================''' - # 保存 ShoppingDict - with open(str(pklpath), 'wb') as f: + '''(1) 保存 ShoppingDict 事件''' + with open(str(pf_path), 'wb') as f: pickle.dump(ShoppingDict, f) + + '''(2) 保存 Tracking 输出的运动轨迹子图,并记录相似度''' + for CamerType, vts in event_tracks: + if len(vts.tracks)==0: continue + if CamerType == 'front': + # yolos = ShoppingDict["frontCamera"]["yoloResnetTracker"] + + yolos = yrtDict["frontyrt"] + ctype = 1 + if CamerType == 'back': + # yolos = ShoppingDict["backCamera"]["yoloResnetTracker"] + + yolos = yrtDict["backyrt"] + ctype = 0 + + imgdict, featdict, simidict = {}, {}, {} + for y in yolos: + imgdict.update(y["imgs"]) + featdict.update(y["feats"]) + simidict.update(y["featsimi"]) + + for track in vts.Residual: + if isinstance(track, np.ndarray): + save_subimgs(imgdict, track, savepath_pipeline_subimgs, ctype, featdict) + else: + save_subimgs(imgdict, track.slt_boxes, savepath_pipeline_subimgs, ctype, featdict) + + '''(3) 轨迹显示与保存''' + illus = [None, None] + for CamerType, vts in event_tracks: + if len(vts.tracks)==0: continue + + if CamerType == 'front': + edgeline = cv2.imread("./tracking/shopcart/cart_tempt/board_ftmp_line.png") + + h, w = edgeline.shape[:2] + # nh, nw = h//2, w//2 + # edgeline = cv2.resize(edgeline, (nw, nh), interpolation=cv2.INTER_AREA) + + img_tracking = draw_all_trajectories(vts, edgeline, savepath_pipeline, CamerType, draw5p=True) + illus[0] = img_tracking + + plt = plot_frameID_y2(vts) + plt.savefig(os.path.join(savepath_pipeline, "front_y2.png")) + + if CamerType == 'back': + edgeline = cv2.imread("./tracking/shopcart/cart_tempt/edgeline.png") + + h, w = edgeline.shape[:2] + # nh, nw = h//2, w//2 + # edgeline = cv2.resize(edgeline, (nw, nh), interpolation=cv2.INTER_AREA) + + img_tracking = draw_all_trajectories(vts, edgeline, savepath_pipeline, CamerType, draw5p=True) + illus[1] = img_tracking - # 绘制并保存轨迹图 - show_result(event_tracks, yrtDict, savepath_pipe) - - + illus = [im for im in illus if im is not None] + if len(illus): + img_cat = np.concatenate(illus, axis = 1) + if len(illus)==2: + H, W = img_cat.shape[:2] + cv2.line(img_cat, (int(W/2), 0), (int(W/2), int(H)), (128, 128, 255), 3) + + trajpath = os.path.join(savepath_pipeline, "trajectory.png") + cv2.imwrite(trajpath, img_cat) def execute_pipeline(evtdir = r"D:\datasets\ym\后台数据\unzip", - DataType = "raw", # raw, pkl + source_type = "video", # video, image, save_path = r"D:\work\result_pipeline", - kk=1, - source_type = "video", # video, image, yolo_ver = "V10", # V10, V5 + weight_yolo_v5 = r'./ckpts/best_cls10_0906.pt' , weight_yolo_v10 = r'./ckpts/best_v10s_width0375_1205.pt', - saveimages = True + k=0 ): ''' 运行函数 pipeline(),遍历事件文件夹,每个文件夹是一个事件 ''' parmDict = {} - parmDict["DataType"] = DataType - parmDict["savepath"] = save_path parmDict["SourceType"] = source_type - + parmDict["savepath"] = save_path parmDict["YoloVersion"] = yolo_ver if parmDict["YoloVersion"] == "V5": parmDict["weights"] = weight_yolo_v5 elif parmDict["YoloVersion"] == "V10": parmDict["weights"] = weight_yolo_v10 - - parmDict["saveimages"] = saveimages - evtdir = Path(evtdir) errEvents = [] - k = 0 for item in evtdir.iterdir(): if item.is_dir(): item = evtdir/Path("20250310-175352-741") parmDict["eventpath"] = item - pipeline(**parmDict) # try: # pipeline(**parmDict) # except Exception as e: # errEvents.append(str(item)) - k+=1 - if kk is not None and k==kk: + if k==1: break errfile = os.path.join(parmDict["savepath"], 'error_events.txt') @@ -389,6 +336,23 @@ if __name__ == "__main__": # execute_pipeline(save_path=spath_v10, yolo_ver="V10") # execute_pipeline(save_path=spath_v5, yolo_ver="V5") + datapath = r'/home/wqg/dataset/test_dataset/base_dataset/single_event/source/' + savepath = r'/home/wqg/dataset/pipeline/contrast/single_event_V5' + + + + + execute_pipeline(evtdir = datapath, + DataType = "raw", # raw, pkl + kk=1, + source_type = "video", # video, image, + save_path = savepath, + yolo_ver = "V10", # V10, V5 + weight_yolo_v5 = r'./ckpts/best_cls10_0906.pt' , + weight_yolo_v10 = r'./ckpts/best_v10s_width0375_1205.pt', + saveimages = False + ) + diff --git a/contrast/__pycache__/__init__.cpython-312.pyc b/contrast/__pycache__/__init__.cpython-312.pyc index c611f0a5552e17d2df22124736430d33060ced2d..b2010b8f55b0b36e10c582abb9c934542f077512 100644 GIT binary patch delta 20 acmcb}c#)CkG%qg~0}wa{KTDs;a})qN9R=e6 delta 20 acmcb}c#)CkG%qg~0}v>9E=rroa})qKq6KpR diff --git a/contrast/__pycache__/event_test.cpython-312.pyc b/contrast/__pycache__/event_test.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1cfb77aa329d07607c812cd8c025f7f32f2fd963 GIT binary patch literal 11508 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 Cn`#vR literal 0 HcmV?d00001 diff --git a/contrast/__pycache__/genfeats.cpython-312.pyc b/contrast/__pycache__/genfeats.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..acc75fafad41b4055550107dddaecec9953fbbf2 GIT binary patch literal 8337 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 literal 0 HcmV?d00001 diff --git a/contrast/__pycache__/one2n_contrast.cpython-312.pyc b/contrast/__pycache__/one2n_contrast.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..158320b7212d68ae898639e7420c7ec7ad49230c GIT binary patch literal 13024 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 literal 0 HcmV?d00001 diff --git a/contrast/event_test.py b/contrast/event_test.py index 7563a7a..d5108fc 100644 --- a/contrast/event_test.py +++ b/contrast/event_test.py @@ -9,17 +9,19 @@ import cv2 import json import numpy as np import matplotlib.pyplot as plt +from pathlib import Path + from matplotlib import rcParams from matplotlib.font_manager import FontProperties from scipy.spatial.distance import cdist from utils.event import ShoppingEvent, save_data - - +from utils.calsimi import calsimi_vs_stdfeat_new, get_topk_percent, cluster +from utils.tools import get_evtList +import pickle rcParams['font.sans-serif'] = ['SimHei'] # 用黑体显示中文 rcParams['axes.unicode_minus'] = False # 正确显示负号 - '''*********** USearch ***********''' def read_usearch(): stdFeaturePath = r"D:\contrast\stdlib\v11_test.json" @@ -35,13 +37,12 @@ def read_usearch(): return stdlib -def get_eventlist(): +def get_eventlist_errortxt(evtpaths): ''' 读取一次测试中的错误事件 - ''' - evtpaths = r"\\192.168.1.28\share\测试视频数据以及日志\算法全流程测试\202412\images" - text1 = "one2n_Error.txt" - text2 = "one2SN_Error.txt" + ''' + text1 = "one_2_Small_n_Error.txt" + text2 = "one_2_Big_N_Error.txt" events = [] text = (text1, text2) for txt in text: @@ -53,16 +54,16 @@ def get_eventlist(): if line: fpath=os.path.join(evtpaths, line) events.append(fpath) + + events = list(set(events)) return events -def single_event(): - - events = get_eventlist() - - +def save_eventdata(): + evtpaths = r"/home/wqg/dataset/test_dataset/performence_dataset/" + events = get_eventlist_errortxt(evtpaths) '''定义当前事件存储地址及生成相应文件件''' resultPath = r"\\192.168.1.28\share\测试视频数据以及日志\算法全流程测试\202412\result\single_event" @@ -74,121 +75,148 @@ def single_event(): -def get_topk_percent(data, k): - """ - 获取数据中最大的 k% 的元素 - """ - # 将数据转换为 NumPy 数组 - if isinstance(data, list): - data = np.array(data) +# def get_topk_percent(data, k): +# """ +# 获取数据中最大的 k% 的元素 +# """ +# # 将数据转换为 NumPy 数组 +# if isinstance(data, list): +# data = np.array(data) - percentile = np.percentile(data, 100-k) - top_k_percent = data[data >= percentile] +# percentile = np.percentile(data, 100-k) +# top_k_percent = data[data >= percentile] - return top_k_percent -def cluster(data, thresh=0.15): - # data = np.array([0.1, 0.13, 0.7, 0.2, 0.8, 0.52, 0.3, 0.7, 0.85, 0.58]) - # data = np.array([0.1, 0.13, 0.2, 0.3]) - # data = np.array([0.1]) +# return top_k_percent +# def cluster(data, thresh=0.15): +# # data = np.array([0.1, 0.13, 0.7, 0.2, 0.8, 0.52, 0.3, 0.7, 0.85, 0.58]) +# # data = np.array([0.1, 0.13, 0.2, 0.3]) +# # data = np.array([0.1]) - if isinstance(data, list): - data = np.array(data) +# if isinstance(data, list): +# data = np.array(data) - data1 = np.sort(data) - cluter, Cluters, = [data1[0]], [] - for i in range(1, len(data1)): - if data1[i] - data1[i-1]< thresh: - cluter.append(data1[i]) - else: - Cluters.append(cluter) - cluter = [data1[i]] - Cluters.append(cluter) +# data1 = np.sort(data) +# cluter, Cluters, = [data1[0]], [] +# for i in range(1, len(data1)): +# if data1[i] - data1[i-1]< thresh: +# cluter.append(data1[i]) +# else: +# Cluters.append(cluter) +# cluter = [data1[i]] +# Cluters.append(cluter) - clt_center = [] - for clt in Cluters: - ## 是否应该在此处限制一个聚类中的最小轨迹样本数,应该将该因素放在轨迹分析中 - # if len(clt)>=3: - # clt_center.append(np.mean(clt)) - clt_center.append(np.mean(clt)) +# clt_center = [] +# for clt in Cluters: +# ## 是否应该在此处限制一个聚类中的最小轨迹样本数,应该将该因素放在轨迹分析中 +# # if len(clt)>=3: +# # clt_center.append(np.mean(clt)) +# clt_center.append(np.mean(clt)) - # print(clt_center) +# # print(clt_center) - return clt_center +# return clt_center -def calc_simil(event, stdfeat): - '''事件与标准库的对比策略 - 该比对策略是否可以拓展到事件与事件的比对? - ''' +# def calsimi_vs_stdfeat_new(event, stdfeat): +# '''事件与标准库的对比策略 +# 该比对策略是否可以拓展到事件与事件的比对? +# ''' - def calsiml(feat1, feat2, topkp=75, cluth=0.15): - '''轨迹样本和标准特征集样本相似度的选择策略''' - matrix = 1 - cdist(feat1, feat2, 'cosine') - simi_max = [] - for i in range(len(matrix)): - sim = np.mean(get_topk_percent(matrix[i, :], topkp)) - simi_max.append(sim) - cltc_max = cluster(simi_max, cluth) - Simi = max(cltc_max) +# def calsiml(feat1, feat2, topkp=75, cluth=0.15): +# '''轨迹样本和标准特征集样本相似度的选择策略''' +# matrix = 1 - cdist(feat1, feat2, 'cosine') +# simi_max = [] +# for i in range(len(matrix)): +# sim = np.mean(get_topk_percent(matrix[i, :], topkp)) +# simi_max.append(sim) +# cltc_max = cluster(simi_max, cluth) +# Simi = max(cltc_max) - ## cltc_max为空属于编程考虑不周,应予以排查解决 - # if len(cltc_max): - # Simi = max(cltc_max) - # else: - # Simi = 0 #不应该走到该处 +# ## cltc_max为空属于编程考虑不周,应予以排查解决 +# # if len(cltc_max): +# # Simi = max(cltc_max) +# # else: +# # Simi = 0 #不应该走到该处 - return Simi +# return Simi - front_boxes = np.empty((0, 9), dtype=np.float64) ##和类doTracks兼容 - front_feats = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容 - for i in range(len(event.front_boxes)): - front_boxes = np.concatenate((front_boxes, event.front_boxes[i]), axis=0) - front_feats = np.concatenate((front_feats, event.front_feats[i]), axis=0) +# front_boxes = np.empty((0, 9), dtype=np.float64) ##和类doTracks兼容 +# front_feats = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容 +# for i in range(len(event.front_boxes)): +# front_boxes = np.concatenate((front_boxes, event.front_boxes[i]), axis=0) +# front_feats = np.concatenate((front_feats, event.front_feats[i]), axis=0) - back_boxes = np.empty((0, 9), dtype=np.float64) ##和类doTracks兼容 - back_feats = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容 - for i in range(len(event.back_boxes)): - back_boxes = np.concatenate((back_boxes, event.back_boxes[i]), axis=0) - back_feats = np.concatenate((back_feats, event.back_feats[i]), axis=0) +# back_boxes = np.empty((0, 9), dtype=np.float64) ##和类doTracks兼容 +# back_feats = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容 +# for i in range(len(event.back_boxes)): +# back_boxes = np.concatenate((back_boxes, event.back_boxes[i]), axis=0) +# back_feats = np.concatenate((back_feats, event.back_feats[i]), axis=0) - if len(front_feats): - front_simi = calsiml(front_feats, stdfeat) - if len(back_feats): - back_simi = calsiml(back_feats, stdfeat) +# if len(front_feats): +# front_simi = calsiml(front_feats, stdfeat) +# if len(back_feats): +# back_simi = calsiml(back_feats, stdfeat) + +# '''前后摄相似度融合策略''' +# if len(front_feats) and len(back_feats): +# diff_simi = abs(front_simi - back_simi) +# if diff_simi>0.15: +# Similar = max([front_simi, back_simi]) +# else: +# Similar = (front_simi+back_simi)/2 +# elif len(front_feats) and len(back_feats)==0: +# Similar = front_simi +# elif len(front_feats)==0 and len(back_feats): +# Similar = back_simi +# else: +# Similar = None # 在event.front_feats和event.back_feats同时为空时 + +# return Similar - '''前后摄相似度融合策略''' - if len(front_feats) and len(back_feats): - diff_simi = abs(front_simi - back_simi) - if diff_simi>0.15: - Similar = max([front_simi, back_simi]) - else: - Similar = (front_simi+back_simi)/2 - elif len(front_feats) and len(back_feats)==0: - Similar = front_simi - elif len(front_feats)==0 and len(back_feats): - Similar = back_simi - else: - Similar = None # 在event.front_feats和event.back_feats同时为空时 - return Similar def simi_matrix(): - resultPath = r"\\192.168.1.28\share\测试视频数据以及日志\算法全流程测试\202412\result\single_event" + evtpaths = r"/home/wqg/dataset/pipeline/contrast/single_event_V10/evtobjs/" - stdlib = read_usearch() - events = get_eventlist() - for evtpath in events: - evtname = os.path.basename(evtpath) - _, barcode = evtname.split("_") + stdfeatPath = r"/home/wqg/dataset/test_dataset/total_barcode/features_json/v11_barcode_0304/" + resultPath = r"/home/wqg/dataset/performence_dataset/result/" + + evt_paths, bcdSet = get_evtList(evtpaths) + + ## read std features + stdDict={} + evtDict = {} + for barcode in bcdSet: + stdpath = os.path.join(stdfeatPath, f"{barcode}.json") + if not os.path.isfile(stdpath): + continue - # 生成事件与相应标准特征集 - event = ShoppingEvent(evtpath) - stdfeat = stdlib[barcode] + with open(stdpath, 'r', encoding='utf-8') as f: + stddata = json.load(f) + feat = np.array(stddata["value"]) + stdDict[barcode] = feat + + for evtpath in evt_paths: + barcode = Path(evtpath).stem.split("_")[-1] + + if barcode not in stdDict.keys(): + continue - Similar = calc_simil(event, stdfeat) + # try: + # with open(evtpath, 'rb') as f: + # evtdata = pickle.load(f) + # except Exception as e: + # print(evtname) + + with open(evtpath, 'rb') as f: + event = pickle.load(f) + + stdfeat = stdDict[barcode] + + Similar = calsimi_vs_stdfeat_new(event, stdfeat) # 构造 boxes 子图存储路径 subimgpath = os.path.join(resultPath, f"{event.evtname}", "subimg") @@ -217,9 +245,9 @@ def simi_matrix(): evtfeat = np.concatenate((evtfeat, event.back_feats[i]), axis=0) imgpaths = event.back_imgpaths - assert len(boxes)==len(evtfeat), f"Please check the Event: {evtname}" + assert len(boxes)==len(evtfeat), f"Please check the Event: {event.evtname}" if len(boxes)==0: continue - print(evtname) + print(event.evtname) matrix = 1 - cdist(evtfeat, stdfeat, 'cosine') simi_1d = matrix.flatten() @@ -309,8 +337,8 @@ def simi_matrix(): mean_diff = abs(mean_values[1]-mean_values[0]) ax[0, 1].set_title(f"mean diff: {mean_diff:.3f}") if len(max_values)==2: - max_values = abs(max_values[1]-max_values[0]) - ax[0, 2].set_title(f"max diff: {max_values:.3f}") + max_diff = abs(max_values[1]-max_values[0]) + ax[0, 2].set_title(f"max diff: {max_diff:.3f}") try: fig.suptitle(f"Similar: {Similar:.3f}", fontsize=16) except Exception as e: @@ -319,19 +347,14 @@ def simi_matrix(): pltpath = os.path.join(subimgpath, f"hist_max_{kpercent}%_.png") plt.savefig(pltpath) - pltpath1 = os.path.join(histpath, f"{evtname}_.png") + pltpath1 = os.path.join(histpath, f"{event.evtname}_.png") plt.savefig(pltpath1) plt.close() - - - - def main(): - simi_matrix() diff --git a/contrast/feat_extract/__pycache__/config.cpython-312.pyc b/contrast/feat_extract/__pycache__/config.cpython-312.pyc index be160605606b042f779a9b3ce5d09e31d4c4816d..3972bf5a89fb814a3dd3373a1abced8750d122bd 100644 GIT binary patch delta 21 bcmaDZ^jwJNG%qg~0}wa`KTF@p6U_+#MY9F* delta 21 bcmaDZ^jwJNG%qg~0}v>9E=t?T6U_+#Lcj%p diff --git a/contrast/feat_extract/__pycache__/inference.cpython-312.pyc b/contrast/feat_extract/__pycache__/inference.cpython-312.pyc index 108697e67e62ff558c82eb174f98d00126d1842d..3b2ee0ed22bd9618b1946ad1dc76364dc548a54e 100644 GIT binary patch delta 2614 zcmZWreT-Dq72iAa=FRLE%*smH50=?gmKj)FMrE;lEG#IMMxZN{wTcf17umo1A*8^;T29vc?Q;b2?_sG~^7KYs|!Q z?edPs6X~3x4BswKD5L1P6VxehXqpvgWY}~j{zj@Je6;y4L!_mdzGv+MHb`xNG=nm& zYSng2)DBJtoP-}(#VHjp+pbE?+T{6kC4`;wWO|vnO1_hRT=a*B+b#%^4G%2%qcOLF z#s7^%rxh>&SP2+p$aPSjA8dBNRkc-uEO*kTA+Su#4`!HWIBrm&HDJXnj!SEqqSb(J zI(x}US_kQRz=no7#>hjQhXES_n*bw#%?!CVx{4nv;Z!Vk;6~8mW+ldyDA4zybu-{5 z%`Yh6+P+T*WpnTD=$?(ZhwcO1&v4m$^8?!tzW(lE)_NZ5hXC2|j=t;Ta|c1| zX3sFClCD>nB&($2vrd)pMy^R`M!T!xt{p^EkqF4*M%=_2QO$J_$qCyEYGf1Q@^$^b zDoQ5GT4SW)@Yp=SI^n$jRk68WFvS(Xb(eghBRFmXpha`ZOMcKV!A%2x1=s}G%HSs% z>NnP_bn(7Io*rVUDOhcsiTfHZENp1$`t8us@cHbuB87D349d$-bJ_NOKB$(W=R0np z!ZABVdRSh!d<&<3drwFB(DJ2Xi5}XdIU3N?k5B$bN(-#f7udh8kKd>t%2Ic0#vm!5hR*mJKWEnjTcn0t+ zgA&tzf}c9dD8>|9y=Rh~61^lJU-cJWI#c=I$5W57R!-0p@;j@COgKxYI=DcVIDom3Hb8*kF(qbI-4nl3|QNY6hJuAmRy$#Sg zPUsA?cP;hyDwLdJKzFl(YSdj$o);)FK|WY5zEg3^7Iiy;!xQ`u*r@@EkYZO|ODE*} zYp)R}W%s&{dUc9krCJN@f>kWm$STgzxp4cs(O9=`i$vtyC5N?}Yvid7+p_;=tC#oP z{E}^zd6cjss+L1^UalDa8JFhC;f|R89#9NEnE-qga`U4WItzwQ&(%z+l#cJmR+;X_ zF&b*Uqze95Lqyn*)Ctft0q2y-@6Hk5)GARooPzM5fYUPAncMI($QPiO^6j87 zQ|8V2C-7bb{2A~!hTKxRzz=1*$iGkjhv0Lmc5X1E(BG$Rk}xrL+u>z={%B3S4G z=+4f|%^*y44;2dU9h8~UwaK^riI`@;Q`-RrTGU TTF(`#mF;2L8h&xx`>`(pp8lLS delta 2650 zcmZWreQX@X75Ci7`r@ygjlr=T$Cortyv`-ILrlQLiBpp11Du$WIQgUWvc6l}3wO82 z+dUG8fTI9Pia?+YLRC@Qq>6})koZ_gs{&Efq^bl|s?`GO1X}o`Ek%G3K_Ec{eZN`9 zDdZ&o=FOWoGjHDey|@12l=$ekqW1OL+NuivrMCQL)Oo)4$A&l;>@n_*)c7XU_~l}< zzNs;CK*&;EqdXRAh)qDxagzZy}e}h^pe$ot-Jos#0^1B^&K%$FZa&f+tK^XYgh6b0N~fM-69UlU=<0-zaQq0o{Nez_ko! zGxhSo$BtViTgAyLj@i@)m0@}Q1nXk_;0)aeRkYv~X)Q~11K_*PUUrh!VRZnozG9Lw z^bqqO0&W6q0Bi*Oh{3F7y;n*Dr%&x7IRDRZtqTHUn!2km5fN zxp<)Bvq(d{??Oj9KJUU$#Paw8N(aT3r^J#ROcD&KnV&vF)s&0QU1d8HKIVYzYrS7= zlBZig*)hPjbUR=V0I@U;+Qfs3k63x(^jdJ=ugQf6-@cimAa?7Qe;}0Ee z8xd(aoqFZ=akiU^Q;Y{H0d%gw8=aD=@TM?t2cgvwj5r0IjVrIol*lfTo3%ZU4$A|n z9pOFea1T8Ic#z?WeREM2|G)Pkwt5xjM*!*IjfJbClZPQ|s%v6b7TwGkSveKm@018T z%qkri?XHRzZ9lAuxK9?-Q1fRi&d`sj9JMXKOg0^4m8a8pDJQ8gXmdgfhl}PY+XR#C z-I2+MS>goXy34-MBbe$7Kv1*tvLEy)mcT4}Y}N=~c$Ew@H_jw!_P$IHJz20e;V*#6B<1qkd)h#sr_bcZ{4I zy(XKw&vDCnr~5=SF~wGyoXEyftFy zJvzZ!Rq1g76|**JM`nGXQ?jdfyXcgYy{+PW@XOvuMEHy-o*^@a5o}$3Uu1)elk37F zxC{4rI5g^dC0c-~Zb3*c{TlEjK)ZAj(s@9ytm$i6Q)W@k(S#<~^_3WNGY?0LHM0p0tu)l-a%&D_>@Xmt>eB$LtVBFqw4=rLu2ltZcSSR(66u2+sE1 z8kw(25f44P?5+0kM%mrJrQ_c?_zKp|&DmC-3km(9WI05i%H#cqI5CUYHb?ZgfFit+ z&{FgV!JHcs=v^puY&uv{3H{`|tvnsVG%RV|p)%g35~8cHrv;!Z0?sLe_mnv#pX!Od z&*uhaR;zmcCi?P~fek%qYr1A<+Mf26Y-sh9s#%&1Qi_XL_N<>TE(Y7yzgI1$WY^$W zwf>~7!H$>Y@xfKXm2V9$7B9-L2Y<1157YyIDgYky{Re&qoo@d6v#1IBE7qyXg0;^n zlnWshPQ&aUfHU&LZD#+UA^rh&3D5R36M62Ne}wKV;7!}Ir8GpTlkGzhP#r@u$vFi z%t!KG}vf9T$Rh0B|2bC)wCx z7d@BgFfWUB$iRSVV!&c3E8HLfHZeGav&`MGyuR3RW)o)GBY+3 z@fGdRBrg5u6!wJ_Ocw!~06$<*RUwl>#+fS2JDwl*;{~wNxx4^VLz{Z^PpH2JXnKNJ z$|#p|mTy9E=t?T^F#yyNUsJ| diff --git a/contrast/feat_extract/model/__pycache__/Tool.cpython-312.pyc b/contrast/feat_extract/model/__pycache__/Tool.cpython-312.pyc index 40a3f88737f9091ce34dd48c1ad7c57699199a98..18632785c1bf75086f3c46b493137f83a41c5a16 100644 GIT binary patch delta 21 bcmbOrH9?B!G%qg~0}wa`KTF@p!@>&yIH3gq delta 21 bcmbOrH9?B!G%qg~0}v>9E=t?T!@>&yHLe7Y diff --git a/contrast/feat_extract/model/__pycache__/__init__.cpython-312.pyc b/contrast/feat_extract/model/__pycache__/__init__.cpython-312.pyc index 62895b2a7a865d5ea425bab984e8127811f97c08..48924045e2976b6e536df8e034ec1a7b2f07774c 100644 GIT binary patch delta 21 bcmey!_K}U}G%qg~0}wa`KTF@plgbPLMTrIR delta 21 bcmey!_K}U}G%qg~0}v>9E=t?TlgbPLLY4)9 diff --git a/contrast/feat_extract/model/__pycache__/fmobilenet.cpython-312.pyc b/contrast/feat_extract/model/__pycache__/fmobilenet.cpython-312.pyc index 9a868d0d4bccec85841e539514806f72b8862626..d809e7c054351ad174db014cd20edf24ca03613e 100644 GIT binary patch delta 21 bcmdmQz2BPWG%qg~0}wa`KTF@pvso4ZMok7^ delta 21 bcmdmQz2BPWG%qg~0}v>9E=t?Tvso4ZLs|vy diff --git a/contrast/feat_extract/model/__pycache__/lcnet.cpython-312.pyc b/contrast/feat_extract/model/__pycache__/lcnet.cpython-312.pyc index b60f55538d6df0fd7bbe3633a570dc49a69b4e90..3e1a42fa4e3e0a8a60846ca0cd3810dd9e894f95 100644 GIT binary patch delta 21 bcmdlTvpa_8G%qg~0}wa`KTF@pqpt@5Nt^~I delta 21 bcmdlTvpa_8G%qg~0}v>9E=t?Tqpt@5MyUn0 diff --git a/contrast/feat_extract/model/__pycache__/loss.cpython-312.pyc b/contrast/feat_extract/model/__pycache__/loss.cpython-312.pyc index a42dd74bceb72477985bc5de0086d1df9b525ad0..ce31fb48438c559bf3fbc998a64ad38e74851f05 100644 GIT binary patch delta 21 bcmZ3+xr~$NG%qg~0}wa`KTF@pGm8ZPI<5tm delta 21 bcmZ3+xr~$NG%qg~0}v>9E=t?TGm8ZPH@gKU diff --git a/contrast/feat_extract/model/__pycache__/metric.cpython-312.pyc b/contrast/feat_extract/model/__pycache__/metric.cpython-312.pyc index d0cb7a2edc4bd8acb60a523f3fd1b61a051cf0c1..babe348fc840df8f7428e5d5723bef5124734a13 100644 GIT binary patch delta 21 bcmaE%`a+fGG%qg~0}wa`KTF@pb4LgONw@~1 delta 21 bcmaE%`a+fGG%qg~0}v>9E=t?Tb4LgOM#Tm) diff --git a/contrast/feat_extract/model/__pycache__/mobilenet_v2.cpython-312.pyc b/contrast/feat_extract/model/__pycache__/mobilenet_v2.cpython-312.pyc index 2143e6406b41ea6ca657df8afe91e5d9460b9321..696ba13dd175265065ed45016ef0708f92acf28d 100644 GIT binary patch delta 21 bcmZqkX!GDX&CAQh00d6K&(b&Y{89!0Kj#Ki delta 21 bcmZqkX!GDX&CAQh00au2i_$jo{89!0JoE+Q diff --git a/contrast/feat_extract/model/__pycache__/mobilenet_v3.cpython-312.pyc b/contrast/feat_extract/model/__pycache__/mobilenet_v3.cpython-312.pyc index 6a35563006868a069a62bf7e3cb6079840ebd32c..d4e74ee9305ebb5ec08b1ae57434e06128418a35 100644 GIT binary patch delta 21 bcmX?=dn%XbG%qg~0}wa`KTF@pv(F3wPoM_< delta 21 bcmX?=dn%XbG%qg~0}v>9E=t?Tv(F3wOsxit diff --git a/contrast/feat_extract/model/__pycache__/mobilevit.cpython-312.pyc b/contrast/feat_extract/model/__pycache__/mobilevit.cpython-312.pyc index 4e46a9b7fc4c12591b894b7afbfa56dd05da3706..ec3d4defe200e77e60a47585ab711aef4b59c143 100644 GIT binary patch delta 21 bcmcanexsb{G%qg~0}wa`KTF@pbH*9~Q*8%8 delta 21 bcmcanexsb{G%qg~0}v>9E=t?TbH*9~P diff --git a/contrast/feat_extract/model/__pycache__/resbam.cpython-312.pyc b/contrast/feat_extract/model/__pycache__/resbam.cpython-312.pyc index 9fb626945f302138ef13102a3787b9b2f568394c..2605e1c90f7ea0961728796c37d8e92b9a28d86b 100644 GIT binary patch delta 21 bcmbQ~Fw=qOG%qg~0}wa`KTF@p!>a%QKhgzy delta 21 bcmbQ~Fw=qOG%qg~0}v>9E=t?T!>a%QJl_Qg diff --git a/contrast/feat_extract/model/__pycache__/resnet_face.cpython-312.pyc b/contrast/feat_extract/model/__pycache__/resnet_face.cpython-312.pyc index 9d4ae18ade3f754c8b2d9769be6b80a53d83c9d2..2c34e5ec6974a9aea15c380cc54178db2cf858b4 100644 GIT binary patch delta 21 bcmbPeHqngdG%qg~0}wa`KTF@p!zv8`Jplzt delta 21 bcmbPeHqngdG%qg~0}v>9E=t?T!zv8`It~Qb diff --git a/contrast/feat_extract/model/__pycache__/resnet_pre.cpython-312.pyc b/contrast/feat_extract/model/__pycache__/resnet_pre.cpython-312.pyc index 1afbcb1d69b54af411a74a99586ce7ffc4d4368e..700c72462333d07c6c5e89c08c3426cd4b73f9ee 100644 GIT binary patch delta 23 dcmcb1SG%qg~0}wa`KTF@p1SG%qg~0}v>9E=t?T=2 and evt[-1].isdigit() and len(evt[-1])>=10 - if not condt: continue - - pickpath = os.path.join(eventDataPath, f"{bname}.pickle") - if os.path.isfile(pickpath): continue - - # event = ShoppingEvent(source_path, stype) - try: - event = ShoppingEvent(source_path, stype) - with open(pickpath, 'wb') as f: - pickle.dump(event, f) - print(evtname) - except Exception as e: - errEvents.append(source_path) - print(f"Error: {evtname}, {e}") - # k += 1 - # if k==1: - # break - - errfile = Path(eventDataPath).parent / 'error_events.txt' - with open(str(errfile), 'a', encoding='utf-8') as f: - for line in errEvents: - f.write(line + '\n') +from utils.tools import init_eventDict def read_eventdict(eventDataPath): evtDict = {} diff --git a/contrast/one2one_contrast.py b/contrast/one2one_contrast.py index fdce5f1..2e79b27 100644 --- a/contrast/one2one_contrast.py +++ b/contrast/one2one_contrast.py @@ -27,188 +27,24 @@ Created on Fri Aug 30 17:53:03 2024 """ import numpy as np -import cv2 import os import sys import random import pickle import json -import random -import copy -import sys -# import torch -import time -# import json + from pathlib import Path -from scipy.spatial.distance import cdist import matplotlib.pyplot as plt -import shutil -from datetime import datetime -# from openpyxl import load_workbook, Workbook -# from config import config as conf -# from model import resnet18 as resnet18 -# from feat_inference import inference_image +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) -sys.path.append(r"D:\DetectTracking") -from tracking.utils.read_data import extract_data, read_tracking_output, read_similar, read_deletedBarcode_file -from tracking.utils.plotting import Annotator, colors -from feat_extract.config import config as conf -from feat_extract.inference import FeatsInterface -from utils.event import ShoppingEvent, save_data +from utils.calsimi import calsimi_vs_stdfeat, calsimi_vs_stdfeat_new +from utils.tools import get_evtList, init_eventDict +from utils.databits import data_precision_compare from genfeats import gen_bcd_features -from event_test import calc_simil -from one2n_contrast import init_eventDict - - - - - -def int8_to_ft16(arr_uint8, amin, amax): - arr_ft16 = (arr_uint8 / 255 * (amax-amin) + amin).astype(np.float16) - - return arr_ft16 - -def ft16_to_uint8(arr_ft16): - # pickpath = r"\\192.168.1.28\share\测试_202406\contrast\std_features_ft32vsft16\6902265587712_ft16.pickle" - - # with open(pickpath, 'rb') as f: - # edict = pickle.load(f) - - # arr_ft16 = edict['feats'] - - amin = np.min(arr_ft16) - amax = np.max(arr_ft16) - arr_ft255 = (arr_ft16 - amin) * 255 / (amax-amin) - arr_uint8 = arr_ft255.astype(np.uint8) - - arr_ft16_ = int8_to_ft16(arr_uint8, amin, amax) - - arrDistNorm = np.linalg.norm(arr_ft16_ - arr_ft16) / arr_ft16_.size - - return arr_uint8, arr_ft16_ - - -def data_precision_compare(stdfeat, evtfeat, evtMessage, save=True): - evt, stdbcd, label = evtMessage - rltdata, rltdata_ft16, rltdata_ft16_ = [], [], [] - - matrix = 1 - cdist(stdfeat, evtfeat, 'cosine') - simi_mean = np.mean(matrix) - simi_max = np.max(matrix) - stdfeatm = np.mean(stdfeat, axis=0, keepdims=True) - evtfeatm = np.mean(evtfeat, axis=0, keepdims=True) - simi_mfeat = 1- np.maximum(0.0, cdist(stdfeatm, evtfeatm, 'cosine')) - rltdata = [label, stdbcd, evt, simi_mean, simi_max, simi_mfeat[0,0]] - - - ##================================================================= float16 - stdfeat_ft16 = stdfeat.astype(np.float16) - evtfeat_ft16 = evtfeat.astype(np.float16) - stdfeat_ft16 /= np.linalg.norm(stdfeat_ft16, axis=1)[:, None] - evtfeat_ft16 /= np.linalg.norm(evtfeat_ft16, axis=1)[:, None] - - - matrix_ft16 = 1 - cdist(stdfeat_ft16, evtfeat_ft16, 'cosine') - simi_mean_ft16 = np.mean(matrix_ft16) - simi_max_ft16 = np.max(matrix_ft16) - stdfeatm_ft16 = np.mean(stdfeat_ft16, axis=0, keepdims=True) - evtfeatm_ft16 = np.mean(evtfeat_ft16, axis=0, keepdims=True) - simi_mfeat_ft16 = 1- np.maximum(0.0, cdist(stdfeatm_ft16, evtfeatm_ft16, 'cosine')) - rltdata_ft16 = [label, stdbcd, evt, simi_mean_ft16, simi_max_ft16, simi_mfeat_ft16[0,0]] - - '''****************** uint8 is ok!!!!!! ******************''' - ##=================================================================== uint8 - # stdfeat_uint8, stdfeat_ft16_ = ft16_to_uint8(stdfeat_ft16) - # evtfeat_uint8, evtfeat_ft16_ = ft16_to_uint8(evtfeat_ft16) - - stdfeat_uint8 = (stdfeat_ft16*128).astype(np.int8) - evtfeat_uint8 = (evtfeat_ft16*128).astype(np.int8) - stdfeat_ft16_ = stdfeat_uint8.astype(np.float16)/128 - evtfeat_ft16_ = evtfeat_uint8.astype(np.float16)/128 - - absdiff = np.linalg.norm(stdfeat_ft16_ - stdfeat) / stdfeat.size - - matrix_ft16_ = 1 - cdist(stdfeat_ft16_, evtfeat_ft16_, 'cosine') - simi_mean_ft16_ = np.mean(matrix_ft16_) - simi_max_ft16_ = np.max(matrix_ft16_) - stdfeatm_ft16_ = np.mean(stdfeat_ft16_, axis=0, keepdims=True) - evtfeatm_ft16_ = np.mean(evtfeat_ft16_, axis=0, keepdims=True) - simi_mfeat_ft16_ = 1- np.maximum(0.0, cdist(stdfeatm_ft16_, evtfeatm_ft16_, 'cosine')) - rltdata_ft16_ = [label, stdbcd, evt, simi_mean_ft16_, simi_max_ft16_, simi_mfeat_ft16_[0,0]] - - if not save: - return - - - ##========================================================= save as float32 - rppath = os.path.join(similPath, f'{evt}_ft32.pickle') - with open(rppath, 'wb') as f: - pickle.dump(rltdata, f) - - rtpath = os.path.join(similPath, f'{evt}_ft32.txt') - with open(rtpath, 'w', encoding='utf-8') as f: - for result in rltdata: - part = [f"{x:.3f}" if isinstance(x, float) else str(x) for x in result] - line = ', '.join(part) - f.write(line + '\n') - - - ##========================================================= save as float16 - rppath_ft16 = os.path.join(similPath, f'{evt}_ft16.pickle') - with open(rppath_ft16, 'wb') as f: - pickle.dump(rltdata_ft16, f) - - rtpath_ft16 = os.path.join(similPath, f'{evt}_ft16.txt') - with open(rtpath_ft16, 'w', encoding='utf-8') as f: - for result in rltdata_ft16: - part = [f"{x:.3f}" if isinstance(x, float) else str(x) for x in result] - line = ', '.join(part) - f.write(line + '\n') - - - ##=========================================================== save as uint8 - rppath_uint8 = os.path.join(similPath, f'{evt}_uint8.pickle') - with open(rppath_uint8, 'wb') as f: - pickle.dump(rltdata_ft16_, f) - - rtpath_uint8 = os.path.join(similPath, f'{evt}_uint8.txt') - with open(rtpath_uint8, 'w', encoding='utf-8') as f: - for result in rltdata_ft16_: - part = [f"{x:.3f}" if isinstance(x, float) else str(x) for x in result] - line = ', '.join(part) - f.write(line + '\n') - - - - -def simi_calc(event, stdfeat): - evtfeat = event.feats_compose - if isinstance(event.feats_select, list): - if len(event.feats_select) and len(event.feats_select[0]): - evtfeat = event.feats_select[0] - else: - return None, None, None - else: - evtfeat = event.feats_select - - if len(evtfeat)==0 or len(stdfeat)==0: - return None, None, None - - - evtfeat /= np.linalg.norm(evtfeat, axis=1)[:, None] - stdfeat /= np.linalg.norm(stdfeat, axis=1)[:, None] - - matrix = 1 - cdist(evtfeat, stdfeat, 'cosine') - matrix[matrix < 0] = 0 - - simi_mean = np.mean(matrix) - simi_max = np.max(matrix) - stdfeatm = np.mean(stdfeat, axis=0, keepdims=True) - evtfeatm = np.mean(evtfeat, axis=0, keepdims=True) - simi_mfeat = 1- np.maximum(0.0, cdist(stdfeatm, evtfeatm, 'cosine')) - - return simi_mean, simi_max, simi_mfeat[0,0] def build_std_evt_dict(): @@ -218,18 +54,6 @@ def build_std_evt_dict(): ''' stdBarcode = [p.stem for p in Path(stdFeaturePath).iterdir() if p.is_file() and (p.suffix=='.json' or p.suffix=='.pickle')] - - '''*********** USearch ***********''' - # stdFeaturePath = r"D:\contrast\stdlib\v11_test.json" - # stdBarcode = [] - # stdlib = {} - # with open(stdFeaturePath, 'r', encoding='utf-8') as f: - # data = json.load(f) - # for dic in data['total']: - # barcode = dic['key'] - # feature = np.array(dic['value']) - # stdBarcode.append(barcode) - # stdlib[barcode] = feature '''======1. 购物事件列表,该列表中的 Barcode 存在于标准的 stdBarcode 内 ===''' evtList = [(p.stem, p.stem.split('_')[-1]) for p in Path(eventDataPath).iterdir() @@ -259,10 +83,7 @@ def build_std_evt_dict(): stddata = pickle.load(f) feat = stddata["feats_ft32"] stdDict[barcode] = feat - - - - + '''*********** USearch ***********''' # stdDict = {} # for barcode in barcodes: @@ -282,7 +103,7 @@ def build_std_evt_dict(): return evtList, evtDict, stdDict -def one2SN_pr(evtList, evtDict, stdDict): +def one2SN_pr(evtList, evtDict, stdDict, simType="simple"): std_barcodes = set([bcd for _, bcd in evtList]) @@ -312,8 +133,14 @@ def one2SN_pr(evtList, evtDict, stdDict): barcodes, similars = [], [] for stdbcd in bcd_selected: stdfeat = stdDict[stdbcd] - simi_mean, simi_max, simi_mfeat = simi_calc(event, stdfeat) - # simi_mean = calc_simil(event, stdfeat) + + if simType=="typea": + simi_mean, simi_max, simi_mfeat = calsimi_vs_stdfeat(event, stdfeat) + elif simType=="typeb": + pass + else: + simi_mean, simi_1, simi_2 = calsimi_vs_stdfeat_new(event, stdfeat) + ## 在event.front_feats和event.back_feats同时为空时,此处不需要保护 # if simi_mean==None: @@ -376,6 +203,10 @@ def one2SN_pr(evtList, evtDict, stdDict): ax.set_xlabel(f"Event Num: {len(tp_events) + len(fn_events)}") ax.legend() plt.show() + + rltpath = os.path.join(similPath, f'pr_1toSN_{simType}.png') + plt.savefig(rltpath) + ## ============================= 1:N 展厅 直方图''' fig, axes = plt.subplots(2, 2) axes[0, 0].hist(tp_simi, bins=60, range=(-0.2, 1), edgecolor='black') @@ -391,11 +222,14 @@ def one2SN_pr(evtList, evtDict, stdDict): axes[1, 1].set_xlim([-0.2, 1]) axes[1, 1].set_title(f'FN({len(fn_simi)})') plt.show() + + rltpath = os.path.join(similPath, f'hist_1toSN_{simType}.png') + plt.savefig(rltpath) -def one2one_simi(evtList, evtDict, stdDict): +def one2one_simi(evtList, evtDict, stdDict, simType): barcodes = set([bcd for _, bcd in evtList]) '''======1 构造 3 个事件对: 扫 A 放 A, 扫 A 放 B, 合并 ====================''' @@ -421,31 +255,50 @@ def one2one_simi(evtList, evtDict, stdDict): continue stdfeat = stdDict[stdbcd] # float32 - - simi_mean, simi_max, simi_mfeat = simi_calc(event, stdfeat) + + if simType=="typea": + simi_mean, simi_1, simi_2 = calsimi_vs_stdfeat_new(event, stdfeat) + elif simType=="typeb": + pass + else: + simi_mean, simi_1, simi_2 = calsimi_vs_stdfeat(event, stdfeat) + if simi_mean is None: continue - rltdata.append((label, stdbcd, evtname, simi_mean, simi_max, simi_mfeat)) + rltdata.append((label, stdbcd, evtname, simi_mean, simi_1, simi_2)) '''================ float32、16、int8 精度比较与存储 =============''' - # data_precision_compare(stdfeat, evtfeat, mergePairs[i], save=True) + # data_precision_compare(stdfeat, evtfeat, mergePairs[i], similPath, save=True) errorFile_one2one = list(set(errorFile_one2one)) return rltdata, errorFile_one2one -def one2one_pr(evtList, evtDict, stdDict): +def one2one_pr(evtList, evtDict, stdDict, simType="simple"): - rltdata, errorFile_one2one = one2one_simi(evtList, evtDict, stdDict) + rltdata, errorFile_one2one = one2one_simi(evtList, evtDict, stdDict, simType) Same, Cross = [], [] + for label, stdbcd, evtname, simi_mean, simi_max, simi_mft in rltdata: - if label == "same": + if simType=="simple" and label == "same": Same.append(simi_max) - if label == "diff": + if simType=="simple" and label == "diff": Cross.append(simi_max) + + if simType=="typea" and label == "same": + Same.append(simi_mean) + if simType=="typea" and label == "diff": + Cross.append(simi_mean) + + + # for label, stdbcd, evtname, simi_mean, simi_max, simi_mft in rltdata: + # if label == "same": + # Same.append(simi_mean) + # if label == "diff": + # Cross.append(simi_mean) Same = np.array(Same) Cross = np.array(Cross) @@ -508,7 +361,7 @@ def one2one_pr(evtList, evtDict, stdDict): ax.legend() plt.show() - rltpath = os.path.join(similPath, 'pr.png') + rltpath = os.path.join(similPath, f'pr_1to1_{simType}.png') plt.savefig(rltpath) # svg, png, pdf @@ -521,7 +374,7 @@ def one2one_pr(evtList, evtDict, stdDict): axes[1].set_xlim([-0.2, 1]) axes[1].set_title(f'TN({len(Cross)})') - rltpath = os.path.join(similPath, 'hist.png') + rltpath = os.path.join(similPath, f'hist_1to1_{simType}.png') plt.savefig(rltpath) @@ -529,158 +382,25 @@ def one2one_pr(evtList, evtDict, stdDict): -def gen_eventdict(sourcePath, saveimg=True): - k, errEvents = 0, [] - for source_path in sourcePath: - evtpath, bname = os.path.split(source_path) - - ## 兼容事件的两种情况:文件夹 和 Yolo-Resnet-Tracker 的输出 - if os.path.isfile(source_path): - bname, ext = os.path.splitext(bname) - # evt = bname.split("_") - - evt = bname.split('_') - condt = len(evt)>=2 and evt[-1].isdigit() and len(evt[-1])>=10 - if not condt: continue - # 如果已完成事件生成,则不执行 - pickpath = os.path.join(eventDataPath, f"{bname}.pickle") - if os.path.isfile(pickpath): continue - - try: - event = ShoppingEvent(source_path, stype=source_type) - # save_data(event, resultPath) - - with open(pickpath, 'wb') as f: - pickle.dump(event, f) - print(bname) - except Exception as e: - errEvents.append(source_path) - print(e) - - # k += 1 - # if k==1: - # break - - errfile = os.path.join(resultPath, 'error_events.txt') - # with open(errfile, 'w', encoding='utf-8') as f: - # for line in errEvents: - # f.write(line + '\n') - - -# def init_std_evt_dict(): -# '''==== 0. 生成事件列表和对应的 Barcodes列表 ===========''' -# bcdList, event_spath = [], [] -# for evtname in os.listdir(eventSourcePath): -# bname, ext = os.path.splitext(evtname) - -# ## 处理事件的两种情况:文件夹 和 Yolo-Resnet-Tracker 的输出 -# fpath = os.path.join(eventSourcePath, evtname) -# if os.path.isfile(fpath) and (ext==".pkl" or ext==".pickle"): -# evt = bname.split('_') -# elif os.path.isdir(fpath): -# evt = evtname.split('_') -# else: -# continue - -# if len(evt)>=2 and evt[-1].isdigit() and len(evt[-1])>=10: -# bcdList.append(evt[-1]) -# event_spath.append(fpath) - -# '''==== 1. 生成标准特征集, 只需运行一次, 在 genfeats.py 中实现 ===========''' -# bcdSet = set(bcdList) -# gen_bcd_features(stdSamplePath, stdBarcodePath, stdFeaturePath, bcdSet) -# print("stdFeats have generated and saved!") - -# '''==== 2. 生成事件字典, 只需运行一次 ===============''' -# gen_eventdict(event_spath) -# print("eventList have generated and saved!") - -def get_evtList(): - - '''==== 0. 生成事件列表和对应的 Barcodes 集合 ===========''' - bcdList, evtpaths = [], [] - for evtname in os.listdir(eventSourcePath): - bname, ext = os.path.splitext(evtname) - - ## 处理事件的两种情况:文件夹 和 Yolo-Resnet-Tracker 的输出 - fpath = os.path.join(eventSourcePath, evtname) - if os.path.isfile(fpath) and (ext==".pkl" or ext==".pickle"): - evt = bname.split('_') - elif os.path.isdir(fpath): - evt = evtname.split('_') - else: - continue - - if len(evt)>=2 and evt[-1].isdigit() and len(evt[-1])>=10: - bcdList.append(evt[-1]) - evtpaths.append(fpath) - - bcdSet = set(bcdList) - - return evtpaths, bcdSet - - - -# def init_stdDict(): -# evtpaths, bcdSet = get_evtList() -# gen_bcd_features(stdSamplePath, stdBarcodePath, stdFeaturePath, bcdSet) -# print("stdFeats have generated and saved!") - - -# def init_evtDict(): -# '''==== 0. 生成事件列表和对应的 Barcodes列表 ===========''' -# bcdList, event_spath = [], [] -# for evtname in os.listdir(eventSourcePath): -# bname, ext = os.path.splitext(evtname) - -# ## 处理事件的两种情况:文件夹 和 Yolo-Resnet-Tracker 的输出 -# fpath = os.path.join(eventSourcePath, evtname) -# if os.path.isfile(fpath) and (ext==".pkl" or ext==".pickle"): -# evt = bname.split('_') -# elif os.path.isdir(fpath): -# evt = evtname.split('_') -# else: -# continue - -# if len(evt)>=2 and evt[-1].isdigit() and len(evt[-1])>=10: -# bcdList.append(evt[-1]) -# event_spath.append(fpath) - -# '''==== 2. 生成事件字典, 只需运行一次 ===============''' -# gen_eventdict(event_spath) -# print("eventList have generated and saved!") - - - - - -def test_one2one_one2SN(): +def test_one2one_one2SN(simType): '''1:1性能评估''' - # evtpaths, bcdSet = get_evtList() + # evtpaths, bcdSet = get_evtList(eventSourcePath) '''=== 1. 只需运行一次,生成事件对应的标准特征库字典,如已生成,无需运行 ====''' # gen_bcd_features(stdSamplePath, stdBarcodePath, stdFeaturePath, eventSourcePath) '''==== 2. 生成事件字典, 只需运行一次 ====================''' - - # date_ = ['2025-3-4_1', '2025-3-5_1', '2025-3-5_2'] - # for dt in date_: - # evtpaths = os.path.join(eventSourcePath, dt) - # init_eventDict(evtpaths, eventDataPath, source_type) - - init_eventDict(eventSourcePath, eventDataPath, source_type) - - + # init_eventDict(eventSourcePath, eventDataPath, source_type) - '''==== 2. 基于事件barcode集和标准库barcode交集构造事件集合 =========''' + '''==== 3. 基于事件barcode集和标准库barcode交集构造事件集合 =========''' evtList, evtDict, stdDict = build_std_evt_dict() - one2one_pr(evtList, evtDict, stdDict) + one2one_pr(evtList, evtDict, stdDict, simType) - one2SN_pr(evtList, evtDict, stdDict) + one2SN_pr(evtList, evtDict, stdDict, simType) if __name__ == '__main__': ''' @@ -694,21 +414,10 @@ if __name__ == '__main__': (7) similPath: 1:1比对结果存储地址(事件级),在resultPath下 ''' - # stdSamplePath = r"\\192.168.1.28\share\数据\已完成数据\展厅数据\v1.0\比对数据\整理\zhantingBase" - # stdBarcodePath = r"D:\exhibition\dataset\bcdpath" - # stdFeaturePath = r"\\192.168.1.28\share\数据\已完成数据\比对数据\barcode\all_totalBarocde\features_json\v11_barcode_11592" + stdSamplePath = "/home/wqg/dataset/total_barcode/totalBarcode" + stdBarcodePath = "/home/wqg/dataset/total_barcode/bcdpath" + stdFeaturePath = "/home/wqg/dataset/test_dataset/total_barcode/features_json/v11_barcode_0304/" - # eventSourcePath = r'D:\exhibition\images\20241202' - # eventSourcePath = r"\\192.168.1.28\share\测试视频数据以及日志\各模块测试记录\展厅测试\1129_展厅模型v801测试组测试" - - # stdSamplePath = r"\\192.168.1.28\share\数据\已完成数据\展厅数据\v2.0_abroad\比对数据\all_base_二筛" - # stdBarcodePath = r"\\192.168.1.28\share\测试视频数据以及日志\海外展厅测试数据\比对测试数据20250121_testing\bcdpath" - # stdFeaturePath = r"\\192.168.1.28\share\测试视频数据以及日志\海外展厅测试数据\比对测试数据20250121_testing\stdfeats" - - stdSamplePath = r"\\192.168.1.28\share\数据\已完成数据\比对数据\barcode\all_totalBarocde\totalBarcode" - stdBarcodePath = r"\\192.168.1.28\share\测试视频数据以及日志\全实时测试\testing\bcdpath" - stdFeaturePath = r"\\192.168.1.28\share\数据\已完成数据\比对数据\barcode\all_totalBarocde\features_json\v11_barcode_0304" - if not os.path.exists(stdBarcodePath): os.makedirs(stdBarcodePath) if not os.path.exists(stdFeaturePath): @@ -719,18 +428,24 @@ if __name__ == '__main__': "data": 基于事件切分的原 data 文件版本 "realtime": 全实时生成的 data 文件 ''' - source_type = 'realtime' # 'source', 'data', 'realtime' - eventSourcePath = r"\\192.168.1.28\share\测试视频数据以及日志\全实时测试\V12\基准数据集\2025-3-4_1" - resultPath = r"\\192.168.1.28\share\测试视频数据以及日志\全实时测试\testing" + source_type = 'source' # 'source', 'data', 'realtime' + simType = "typea" # "simple", "typea", "typeb" - eventDataPath = os.path.join(resultPath, "evtobjs_0304_1") - similPath = os.path.join(resultPath, "simidata_0304_1") + evttype = "single_event_V10" + # evttype = "single_event_V5" + # evttype = "performence_V10" + # evttype = "performence_V5" + eventSourcePath = "/home/wqg/dataset/pipeline/yrt/{}/shopping_pkl".format(evttype) + + resultPath = "/home/wqg/dataset/pipeline/contrast/{}".format(evttype) + eventDataPath = os.path.join(resultPath, "evtobjs") + similPath = os.path.join(resultPath, "simidata") if not os.path.exists(eventDataPath): os.makedirs(eventDataPath) if not os.path.exists(similPath): os.makedirs(similPath) - test_one2one_one2SN() + test_one2one_one2SN(simType) diff --git a/contrast/onsite_contrast_pr.py b/contrast/onsite_contrast_pr.py index e228bf6..ffd744a 100644 --- a/contrast/onsite_contrast_pr.py +++ b/contrast/onsite_contrast_pr.py @@ -16,7 +16,11 @@ from pathlib import Path import matplotlib.pyplot as plt import sys -sys.path.append(r"D:\DetectTracking") +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) + from tracking.utils.read_data import read_similar def read_one2one_data(filepath): @@ -531,21 +535,23 @@ def contrast_pr(evtPaths): # bcdSet = set(bcdList) - one2nErrFile = os.path.join(evtPaths, "one_2_Small_n_Error.txt") - with open(one2nErrFile, "w") as file: - for item in fnevents: - file.write(item + "\n") + + + # one2nErrFile = os.path.join(evtPaths, "one_2_Small_n_Error.txt") + # with open(one2nErrFile, "w") as file: + # for item in fnevents: + # file.write(item + "\n") - one2NErrFile = os.path.join(evtPaths, "one_2_Big_N_Error.txt") - with open(one2NErrFile, "w") as file: - for item in fn_events: - file.write(item + "\n") + # one2NErrFile = os.path.join(evtPaths, "one_2_Big_N_Error.txt") + # with open(one2NErrFile, "w") as file: + # for item in fn_events: + # file.write(item + "\n") print('Done!') if __name__ == "__main__": - evtpaths = r"\\192.168.1.28\share\测试视频数据以及日志\全实时测试\V12\2025-3-3" + evtpaths = r"/home/wqg/dataset/test_base_dataset/single_event/source" contrast_pr(evtpaths) diff --git a/contrast/trail2trail.py b/contrast/trail2trail.py new file mode 100644 index 0000000..cbd364a --- /dev/null +++ b/contrast/trail2trail.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" + 取出再放回场景下商品轨迹特征比对方式与性能分析 + +Created on Tue Apr 1 17:17:47 2025 +@author: wqg +""" +import os +import pickle +import random +import numpy as np +from pathlib import Path +import matplotlib.pyplot as plt +from scipy.spatial.distance import cdist +from utils.calsimi import calsiml, calsimi_vs_evts + +def read_eventdict(evtpaths): + evtDict = {} + for filename in os.listdir(evtpaths): + evtname, ext = os.path.splitext(filename) + if ext != ".pickle": continue + + evtpath = os.path.join(evtpaths, filename) + with open(evtpath, 'rb') as f: + evtdata = pickle.load(f) + evtDict[evtname] = evtdata + + + return evtDict + + + +def compute_show_pr(Same, Cross): + TPFN = len(Same) + TNFP = len(Cross) + + Recall_Pos, Recall_Neg = [], [] + Precision_Pos, Precision_Neg = [], [] + Correct = [] + Thresh = np.linspace(-0.2, 1, 100) + for th in Thresh: + TP = np.sum(Same >= th) + FN = np.sum(Same < th) + # FN = TPFN - TP + + TN = np.sum(Cross < th) + FP = np.sum(Cross >= th) + # FP = TNFP - TN + + + Precision_Pos.append(TP/(TP+FP+1e-6)) + Precision_Neg.append(TN/(TN+FN+1e-6)) + Recall_Pos.append(TP/(TP+FN+1e-6)) + Recall_Neg.append(TN/(TN+FP+1e-6)) + + # Recall_Pos.append(TP/TPFN) + # Recall_Neg.append(TN/TNFP) + + + Correct.append((TN+TP)/(TPFN+TNFP)) + + fig, ax = plt.subplots() + + ax.plot(Thresh, Precision_Pos, 'r', label='Precision_Pos: TP/(TP+FP)') + ax.plot(Thresh, Recall_Pos, 'b', label='Recall_Pos: TP/TPFN') + ax.plot(Thresh, Recall_Neg, 'g', label='Recall_Neg: TN/TNFP') + ax.plot(Thresh, Correct, 'c', label='Correct: (TN+TP)/(TPFN+TNFP)') + ax.plot(Thresh, Precision_Neg, 'm', label='Precision_Neg: TN/(TN+FN)') + + ax.set_xlim([0, 1]) + ax.set_ylim([0, 1]) + + ax.set_xticks(np.arange(0, 1, 0.1)) + ax.set_yticks(np.arange(0, 1, 0.1)) + ax.grid(True, linestyle='--') + + ax.set_title('PrecisePos & PreciseNeg') + ax.set_xlabel(f"Same Num: {TPFN}, Cross Num: {TNFP}") + ax.legend() + plt.show() + + # rltpath = os.path.join(similPath, f'pr_1to1_{simType}.png') + # plt.savefig(rltpath) # svg, png, pdf + + + fig, axes = plt.subplots(2,1) + axes[0].hist(Same, bins=60, range=(-0.2, 1), edgecolor='black') + axes[0].set_xlim([-0.2, 1]) + axes[0].set_title(f'TP({len(Same)})') + + axes[1].hist(Cross, bins=60, range=(-0.2, 1), edgecolor='black') + axes[1].set_xlim([-0.2, 1]) + axes[1].set_title(f'TN({len(Cross)})') + + # rltpath = os.path.join(similPath, f'hist_1to1_{simType}.png') + # plt.savefig(rltpath) + + + plt.show() + + + +def trail_to_trail(evtpaths, rltpaths): + # select the method type of how to calculate the feat similarity of trail + simType = 2 + + ##1. read all the ShoppingEvent object in the dir 'evtpaths' + evtDicts = read_eventdict(evtpaths) + + ##2. Combine event object with the same barcode + barcodes, evtpairDict = [], {} + for k in evtDicts.keys(): + evt = k.split('_') + condt = len(evt)>=2 and evt[-1].isdigit() and len(evt[-1])>=10 + if not condt: continue + + barcode = evt[-1] + if barcode not in evtpairDict.keys(): + evtpairDict[barcode] = [] + barcodes.append(barcode) + + evtpairDict[barcode].append(evtDicts[k]) + barcodes = set(barcodes) + + AA_list, AB_list = [], [] + for barcode in evtpairDict.keys(): + events = evtpairDict[barcode] + if len(events)>1: + evta, evtb = random.sample(events, 2) + AA_list.append((evta, evtb, "same")) + + evtc = random.sample(events, 1)[0] + + dset = list(barcodes.symmetric_difference(set([barcode]))) + bcd = random.sample(dset, 1)[0] + evtd = random.sample(evtpairDict[bcd], 1)[0] + AB_list.append((evtc, evtd, "diff")) + + mergePairs = AA_list + AB_list + + ##3. calculate the similar of two event: evta, evtb + new_pirs = [] + for evta, evtb, label in mergePairs: + similar = calsimi_vs_evts(evta, evtb, simType) + if similar is None: + continue + new_pirs.append((label, round(similar, 3), evta.evtname[:15], evtb.evtname[:15])) + + ##4. compute PR and showing + Same = np.array([s for label, s, _, _ in new_pirs if label=="same"]) + Cross = np.array([s for label, s, _, _ in new_pirs if label=="diff"]) + compute_show_pr(Same, Cross) + + +def main(): + evttypes = ["single_event_V10", "single_event_V5", "performence_V10", "performence_V5"] + # evttypes = ["single_event_V10"] + + for evttype in evttypes: + evtpaths = "/home/wqg/dataset/pipeline/contrast/{}/evtobjs/".format(evttype) + rltpaths = "/home/wqg/dataset/pipeline/yrt/{}/yolos_tracking".format(evttype) + + trail_to_trail(evtpaths, rltpaths) + + + +if __name__ == '__main__': + main() + + + \ No newline at end of file diff --git a/contrast/utils/__pycache__/__init__.cpython-312.pyc b/contrast/utils/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0804b41f77853eb174680c031902213ccb8b5437 GIT binary patch literal 215 zcmX@j%ge<81Wv)v(u08XV-N=h7@>^M96-i&h7^VD`Eqh0diq6$O9jk85tQrv9K_*6tMug0D5>gP5=M^ literal 0 HcmV?d00001 diff --git a/contrast/utils/__pycache__/calsimi.cpython-312.pyc b/contrast/utils/__pycache__/calsimi.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fe0388da1adb4ef9bfbf33712cbc741692fe8eb0 GIT binary patch literal 5739 zcmcf_TTmOZ7W}?hEsoao4JDJ9Lw9QQWkxqY5q!`VX&M;HJ_Dp9=Lq0nF>bbjG zNhTWG(~lm_-h21lbI(0G_uTW?znDxk29Qbo!!u>Uu)m`h6*Sqw`XLxhVGP!XF*u{~ z;e8tD2_NAn`$!yP$a7eqmN78eb9kSQp&1?Y6hi@4&*-5wjA?QfG=_RI71gnd_@-n{W3pmT==hScdY-Ia2R_&x z$BGU|KGu)mK>nY{nlk{62*!lLn@ba!T`te1Ckb*c#EWS`$hzolc>XT z&r7&hqTN2hi7o@+2^jNe6J+rSxKhN0f@M6+bKBsp8Xo@7(A>>>OG+oYBi+%i^T$Jv zXKEgZoxEHfqvMZ-yF*77P1b13C3kG+#lahN{cycgltc~yb z%4pA&SSOB0j>mS!@yqtFOLi=kluz_VdSmVBlI} zI!+k|i+ITVbrDHX#}EwhvZi07TnP25s2sukw1c@TrE)DaFfgnGBqrppi>MU|mCLwZ zfS9F#sL$~N~3#;*0S6+SPX5^EV-@kbK$}0-~ z=9TNqpMSpc>HFY|Z-*kQ=da!T@U5F~zQ-lFsiEIPa*WN6yv>^xPJCCA>;{uwysE zN#v6-%Ol4w+q2xLMlJhkAGZf4_rb%DKoi22Or@79qa!gk{^OLTDQRj79m$w2p`&28 zm)fGIE*`jH+7`waOUoua5l`B-D}E~B`i&*QyerNX=MRRukOh{7jwuG13%MXh&WHa1%(Bpj4;E4ZAp$T@ zWdQA9p&4hfGn(9SYx0I%loN5^oQS*$3+TGYAYy|^)f+%HE47D9(2K53fh;H_ZUFGg zMY)M2x(NLmhMdtB{a?j+5x@(%vJFs_7jfYUxGuS5sHmRqU*p<)aJqku7dVYOG+rdS zsG3&$`_#A=v{Zy!Q7skzuVNb40WWm>H$YKdI;3$%_bk}&6NnqW5^&9 zBAz>Ws(@Oj{@**Obp_OV16Dwv=f1B1o9D7yK)y-YlM?lE%Bm*0;364ns0$ocselYJ zN9D<7HRE*Pu!z>d9HT!20U0nI1v};Uw-jJ=`!nQ_9rzO>1?wItpvbMuQj`|V{%*hEaT-6AQ7(Td2TzB(Fi-8f{aL_c!5C_ z+OBAvL~zTsdC2+({6}Xw(6e#Ls%`AP5PFvbSJ&RDNAe?<>`|R#(yVI6^fKz2?NLDqZ%I!By z4v?X;YU;Vk=i+^Hl?yGM$(GJ9>XI#8^YxE^*_p2F4byj@kI+bl-H^|1ZAg+ep`NH= zk)p!~(p1%A<(AkpiH1~VD=-0E$GI04D>lb^5>%>UZ`iOz+EvQw!*P20hl>?ekc<8# zS>2SXXbu}P#){}uuN_*n)xxwmOq@vCnj+nchLZ3zX+zDl zJHGo$Fmdv$2li&HTOyQ5%*3GEaVz=QCz5ymz7#1bfqM0Ww@3NolZkvml24~nkI`APe|D3v-cM_*Q4 z28C)|6EKaTs9i)#_#b(%p7W3ljyxP+=)Z7vFJ+FyfulyqWfg-(VokB?3o1}zhEz4e zz^9j&H4J18$W@<#5(Yjw;Qs?x_-J!it}tJaP{SUK_Ks44fKMOraRdGvI5w1B=TrTn z(K6@hAzMQJLxw?=KyLs@>D9=jEubtGfpPfsq?@5sxu6)yb1p`YK2;UcQ}7@2D^Sk9 z0hq#~LMKvr9jNCamrZ&oZnUDFG06Fx9GjH77wX^MUb%GOT7WfI2hCFuFIu6O^g}E= z%y|90N8L3WN#r2nD3MIEOLw}1{^20c%Ehx(qTqPe2j6X!QaV?ENIIW4;PQDSG7#ka zN`)eqBq$U}6ciC&|A-%ImxJ)mp$~Zy#hw!6u+V_s49LwpQPs_XF@uCzKMrL`md-EH z3XLoVx(B&9pwuGP??wUc2_WO(;g87?AX8etP+FHPtqXN8QkLk>1#5lMT7Q*EQ;n#c z7+EmaCCznd#k(uqv?iDD3%v&_N2|8uq17b;M>Y~ELp1*24QL$ zT;~3l#OR5iy)eBa=DD&bfxq3HF>hPbK}mgqn;46XO`MIKjd>EC;j<}o(=SiX)hA9T z&HIz&{!n*@G~Sa&si;oJsYG?k(wa22LPb@xDRd;<9_@^DBuU$HnRSYqq++^@=Fs;S z;YBy8gG#FuDkbY40`@mC*D*yoO3A4t`Arz(yn zEk{E=OW@uI;&h_zUGu!Ld7f;R9kB!F+CaAs&Fy1I&GML*D5sMNx}8o*8yN8qk10uq zjdy#8$C~(Im*92zn$TBN^ifeU6uE3g6|0;=$WdE9xNDfajdHsBhy6ij#K#`uegu^0 zn(}*~StD>9|Cf%$$#ojT%m0SiztI`-n)T|%amcnBIPjKn4|5+`M0 zd;;g6vI!aglur=wl!p}&<%AN)Na77_LPaW|R+B1H`363rnU{Ig3%%MwD(Gi|q$?J6 zot_Q44$n|7SGTLX|3F{wf!%$sp4~lrwAw@dS>{5FI^deSG^M?dY#8<6oFYJmXeJ;> zbg7^=`g?d5suae8bqhKSV`VJ90A4L9pp7rU*fb8+hQf&6VbjEhAs|02NyO!>dN8==I1srJrWzXM&t8I>V_Z!!bY8-R~hdjh~`?v!N)nk0bn%P!!ev%bXf@PXY^# z=5RszrgztcSR}X$eA`6^nP7lnD1YE$C_1$(5Q{>aW_Haop)kFR^fUhRA%^anndkIK zvyX}Kx~Lk^WrRPv6RHGOG}WaClQo&XEb;#Sys2}A$ea4sYXTtw0wls$TnV!&CS_w7g`(%tP{>G5j?ylNtW(G%PQjyr&lRT(hob)Q6h}m3RD>hw z&_d9oq71-BArB~Iq5z>urf1I{3N1;I?(X+-I)Kp-pnnv^X`~$?2?~W!z!?z05IBSx z8=wzXGDg1vRRa6kgz1e-{fqs}?t-o%F?3gFkWfW)U3w_lm>JBQ+OmBs#B~7Bp2RVL z)Vj%)H@U7^KB#@awqR;c9Q(qwC4DAKWXXc57buG@PgDGOlK^>GG1O_$PVQ zRap$>D4ALO2S{63vt%9w%nfDQyrBa~)=c6z)S_o3d}4kfBe6*t@@JtIa%^TT-$Scq z6Rj{Vi89Pli83Eut0YI&P+%>`%qHQihO7#wUBX#Sr+EWX9Gmc4Ht;*23Rw=;S@Btn zKks{O30XGQ&eoQZrO}{VY0wLN6O34%%yKzebr9(vs-vE*+r)zZfN_`|y}%pT`X8)g z%lE)#!-h``Hf?({TD*l@A46yZyQPvXK1 zOPM%Jd^@vMWMa3II3*s45PHQOq3!$z3@Rp{?+n_gnu4vB3$NCRoS zQ6qkhkbSIr2s<|h7;j_ShOi}fKsJR1WapZo$IY~ema=YUyVw@(qX^bbn%*IzTBc1L zW8ET-lCrBU1Qz$i-K4o{6g?tmyq#^G_J|rPPqv-3pv}0*hhtY?CNRy97bUACN;@S{ z+WAx&)cjX6Xp`91A+fEaN(MFmw;8lcqSPsgQs+};Q2SrWphIF?m&CTNDjC%NuV-)` zYr(oP8lRKl*cl9m-?HrLYnSC`usJ*ceF0hAJ@+IJe)X>c&lA%4)n9!F>8;hJuin{A zb{-QrJkHVk=mg6t12H-j4N_>&eA**}COgDNP*FmPi=#*eP@}5Dt?>BR(jIUTsfN< zzGpDLWnZ4lsIs*Mb5GvTlQ?qMWJ#%#s?FU>8^0sE;H z+geS3wVtBc^44>y4cQ`Do&JvBtJMnGR(3XD_U3Z}r}+ z$r+C(h99UgTSMw#^5C`R58B^vFIYPhBSmZd#vZ~1nvW%qrACvZnSmAm@@T=f?>FYv zp;c$zb~sNQ2C47B^FWDNZEpqBBiW8sb-{5sZ#kSeao6rld6VAss|C9!F^Z^HlCPvs z6zuNA$-6d3YB)Iz0+&|%)@+BW^%Nb>cP;PLzg?dhykXDAS0kT}7d)>N>b!Y}H}OKz zR+sM2^k$8#hFd?+c_;G2ujZ_06C?MC!we@U~5{px$`#n4a-OM*Xs+mzLl}OZ68Q{+rSq_(^6`1P4f5C77AgVE3nOr8< zG!5xXch$xv-J))JIDKkO-S|k3X}5f>d{XvUuC>2l*el8gGQ+nu9V_@9$JQ%H{yg$h z!8-Q4BeyPHYtNqgwPLNgfB90{nw0VQ}BH3oJ{R!Fj+|FkT z)`Oz#V7BeHrf0=}$Ic@&^bF)buW9(_S9;8L8h@mKbmTQ1-#oHFZ1WnI zq`xPx>E`>JbDAbeKT`7z{WExZ{=wn&>g1p8(0aGZKij>-TdV$~!vpQyUZ=NR{<%u) z9gu%+-r?P={(P?o+H1AWagF@8TRUDazumKA+^+sptq0ocI)&G+TCY`r?D|%Pw@tO) zuJHD$*7qtvYJEU4u2dB@igAmoXjcG#v0gFWqJkY3Y_qhS%I70v0iTaT=RXSldxBF$ zVdF6`>}nizAT%@IMZ-rallA+EPOfC1Cbax8x9_% zF2Fe2;L&cV9>{SV|58cd#6vBHYwuu&JDBA!nENZG9JhU?HRGD7b8<8c{DRK^-ubnI4D*i|5r2wA;O?JE7-oWD znKp)%u+kn$n}j^2ZBp`-waLg+-XVl6IHfi~FR6tH_+wU2!jVdW~Yu5`0fZPi}8s zTV8K|TRw?r^%V3LwiS}FvZtum*kdp`jLmtLX)Bj9I~i8@EW_$AONBnQSy=<*RJbbH+!Hkn!>OQW72>!^ zm|^L#)RsTeq}j^3oE{fz?eDW58gyCr^*?ECT5YwjX zYqbvdYHncz`)m?k{)p3a{1&!nlk(~CFev)cQ6`Z+gXs9DZ=>JaB_KVg&c zTGx;Vf*uF!^f>tfXqI(g!ilcFPDlTsXJF97Ye}lRtGBDi$w94!sbw6H+2iTzb@7%= zg=w};J|b^8);j>Od!Tbf0npX?M|s0QUneB>4m1OFKH1ft7%4JdxH4t%fA?iMu1v3F zbhC$KAm~oTOr&;;Ynfs(%za8IQ&1B@k4j7vSBm)bN$yiywpcRx^h&%;w>B9ULuVOQ zdKupiem?1+v|bslS9YIz^+Nlp&?^<+)?MgHe9bW0hEyCOoWzveZq~bqsR^)`w5w%ev19WSTLlS0R3}KBb3JvhJb`Ei1iQBCdovy+MvW zL^8JM=cVu9Q+ZV>JyiQNU!aFFuUc&NGxSg+;?f?LEb1OaMJnXW{sR4xuyU~tpY}fG zGpz;fXI={w^S)~?)68l!e~YYQ1Vp%a&!fU~Oe3pCgSXXZ+F9+b}H9%jxUF|@Whq)XmXVdZ0em5^4 z0K&~H*)Fcn3Di{SJmw}TDu<(^tH=Cl;t&? z%RSiRK~BPJgo=c&VE;)dTTI1f6Da$j+Z;|VuSoP9&h{^}@zlxAM%Lwl(G!_eV|#xegx#LTK~GnYyOF#> z!@w}FCa;NXjcb7Vs^H)KJkYaIW?q>aQJUupjT4WLKR)3Ycl_|c#m6r^e$jEk@z&wk z(v7jgO@7VqvY5Pr3FEkNqIA48*d2cK^`n=Lh990j9?RW1`rw>C_sprWQ)j$m-r$4b zRj+Tjv?1I$y(6aII=X8vJLk-ru{CElj%^Iq&SWp0Q)$j*k7WlQoKcmh=GDw(SBZJM zW>l8>JmYMhEt+Qw*T(WzjqdrV%obG@`!#_bbB4SL<+yS}JFX43g^Oc`X1`)il}&2h z9$bA*Re4*%l-J(YFowce{gSADN$7A)-!QuCBa?MZ>sJQyQ)@UJIu$cCrq;0XnyMUX zFjw4GG5Ug8U3pYj9@ABf?o5A8ZA`x^{q+{V!dyYo#Ln@Z6MM(^hD^e+OczC$Z;BOc z9^E@9S3bYz={*5$u=ARH*SlX;~;-`4>5k*D;J$lvKb^vb+)e3#^# zVK03OFXL4RJs0}z%koOPky0%B0q04K5770szU3##!IhUpMKX$z8&j=f8yf{VTvhWwOYS2WUsRh!~akdJmH^UJG$69tGm6QbJbbf zd)#%_4h}wdM^_)~8mhBG148g9sqTQwGsyM*=KYsx@iG_>H!jCS54d^=^BO0|Ift8ifUI+yAz>^0yT1!yl(}tS zbcWF#b4rbW^)p`&Z27Zq#Pzv;^>v-$OxIXfFze-$p^BhqQafu}9yKk$vNdK}5!2a6 zcg77x-#!_v2zbV|vxcguq3VZQV}_d1-5(i@e)$}fK0bClFdW(zHP*y*ws1vMSLc_- zbp?TgFINN}8|#CJN_Qq_EGN)@O;vnb$>f@V%xLpQAL1IJW9{%yf1*HscP}JOFfIlZ zNCuQgEh_<~NXF){Qh3T)8K^)CRt_+WRRC17SpZe65}=w@0o1T+fZ41DpmsPLI8)BS zI!ne*_G21E>yE*2+aqdc5VX=Eq!E@n-AN~1_iJ#E6Qj5|;JhShTlyIF} zNFgpscm+#Xj2s){RbqvpKajBykr|*~wi;edL|r02%V5Yjq=~%T?Q!*T`1$e5V@|HU zp9NI{G=@XSx^&0Du;X~Li*@yrV)_magy)om9D*Q<;k-`Br*UO}pQ{P}c?Aag_$+)J z+{f!lv0*SUCAgr_5GHhh9m~zF#QrE;y#t(@C-sky{hF>s=X*OKB6x2p$qA3jHjwfFZ9^t)ZWR!DXv znn)xIQLypJA-jXyN9KThVs2b2AbAK<2Pl|beO(@hW27jJ$u@}TZGi3mE-X3_Lv&1W zm0x~ZH)kw9*Bnxx-85U$7%gdx8CO86Hf}VhJmys!<7HOAd`49gFR#F7Y1~qd&tfrs zUbQ1`EFonIv8X0qR1A-7Oc#qJs+g;&x@fv!3NL$K`g6@Ynwg5NSW{WN0{Vl`$|d+L z7oYRiN{m~?YUV1JT&%fJ6JGs(-p`BQDW0j^mWCd$T8eS2_{0trmqJ(c;-kcZ2&Q=A zc{_{I<_4C%upzEB%xcS`+OpvAjMf&!q!N#F8n1S|jLgaiiMLBlFY*=%oC zHX5R^E2`vsoj!^>RN{Tq*k(7Cx02<3 zTCWz~u?5~S$E(cvjyajErDCh_#;Q*!m6vQq3?)mQZiU`~#^_aev%E^Lsw2y%BeP)e z=@<2yN^N2-(AQjVF737c6WY&U<4v~jHGD#;`}bP!HFQXQd0w42uR{tts%B(^CZYIP z+nv40^AcRY5((;7G$c7It^J&}k`U5F0xiR#kj0_&#OES;Kj3orxjct(+rq_hYcV~` zBM@H&p^1da0)Le|!DL3vPGp0_mQ6SlcLb|DiU4L6$_@?y0|w(5n3ljyjI*!OuQU&`E@Hq8u@r$R(OMwy+oUMqW*$+z`IeD0W0aitvgPM6k#cE5HpN zhtObp8mXCk28${I2TQq8F%Ty$<(c3i(DOb-Tg*em^zTDy_Y(pSQ8DEep~^suUp;3u zPYjI@g|e<3d%gQo_l$9^UmGtn`Lp9Swc!T>K7Y=~Q%dZzYVwL~5{8Zms;uYkm+=BWdb z(uN3-acIOCEdU!|v|!b2!KP@zCcpZl!ZK{6Y*xE8s$Cj#T|9B&1agg(l)ejn*R-p! zk#eZ7U|FPkZ6vSNubkHx1UmiSh^Qqdio)g*%QnuiOsN&mvYAvn$RP- zT_Gq%WGiAnw9Op`z!TA2U?RMls6PZ(5X=+l8nPjR>25(KLji@u1$+xvHfP5Wu3ejj zm-mC!kIx$DYCi!oyd3lymWbCx@8U?iO;`pS=MEw`gy2yGk0JOD0u-w`5S1A2s|e6$ z#eEHd6TvYA?Fd)|E(9G2IuRU4(1oBI!3h916=6DpoG9pOi@632o>4AZ5fNvNB?SYgnY7yaOoiR|$28eG^??z!p3-lT#UT z&XrW0UpKifbn@&*|K8ur7+n=mui|B)6H#*$2-mu}u`0ADDk=|Eq1{nq1Eg!OXY2gl z;7-`dfDM#*f(Q7woqmw$6t&^?(Xy85l4#j>l#M~VSRQ^TTHZRnE?T}5Q$WwKh3lf0 zHPhOth2Vh3Q5)V6En7QX7cC<=CD0S~Ba(Q<(ubVBWRzVw|I?Dok{^(8s&Avsh)JMEP-FiMSL zf0MMR8zq-TKbCq|f>xf_y>d}DL@A}Uc~*(J-aK)HeEHsdDiG4QhBQ$iq~aT-8SvwV zx1is`=b25QqqQ)f1z%|73+Tuf-lzNq@g0*-Z=v|MK*_dw3+_V?6O;@D;DU_QIajO= zsPi_Uumhe=Vq3|Uj)2PMEAknACZE|?>?@(`pw?RiBWR^1j1a4!F%!h-m+v)040w<5 z^AjOB{ma|1a>nrGZl14*=Zye-PyrU47^jtLXQD3jpk9pdZ9;mgo$;WCbs= z|4}=@^|!m+?go^vxyP|M(FE`%N3sQPE0Xue!o|L}B-v&cHgLd=s;A4tp(+7BQ*O4a z6JkWWIDmB`HRYA)EC9}598xr1MM{8sF0a}B&`!sWhYviovZ>X9_}ejC#nf5DZJ*f-P;nSQ}h=U2zV7bp^@Dq=o0ZvT+h5*a7n}A zQWGr@H_5mkVHP^9k(U%|*$plmq$~y`UAz*MNKzOB0v^t}5IP8s(!}7W!ucm?B!syM z<79_mVDn>BqTx?SdI4YeMNBVDwbH?gOBm|zNhamoxT!6wZJD2fGS>rmBPAJ>IqWOW z*a9H9|1V7SC=<^sny4GEo6TDi&07*W7|XNym2;q&oqBP7F!zN`=iH$+;ie1gV&#of zc^{UqoK{|yzLP!MvM1WIXQt($cu8fbX>uJXZF^G+1y6;z$*+eWpE_{qD<77(0Fr;( zOMB<>aeD8(suebd1k+%=v@9eIRQpwEBODnY3E5_ib^e`mrsDI;N#(4mCTgk)8)GK> z*lz!}Kvi6ycdi!H#jyN!^(FO`EmpIB`s9Z-o3GZ)>GJ~36RqQ|!S?TLis`FDCqLBJ zOclIc{6_Kg);G(q=0@#XXYG5U_B}K9hdvmZHY*n^risq+&WWD!p3vHGXRK(oe`j283U2*SUmiD@CiLU_kaEUQ z6E_$qbmO|o&&ZgP?<DnxGKA-l_3Z z6W(!eXm@xhW^949{KAPf<7*~1j&BUr%s{J$<0k8Q-J~w$j+sF9j+z?$yXUp5<9g#6 z-m&U6}rAx^37X?dx zyNNM3{Nc_@rhL;Mc*{CBYE>VYwfpVz5A53gtL14%0#ulh7u+>L=--S4pHnrF-A5G7 zq?*vf1JvrQNHqz32Gs-^|Dqo#!ZIo#XL;rK5pao>9IV)2wDn2J` zW2xfHs)=gSoT5h3mdMJ};+A(}{&ikBOyMwz^>}k2mNereRs$zsC9VF5MHR+R>`_u# zB0Yk)eA}~@wv_A>nEre^pWbJH?QOAN7T9J^Q8vA3c%UwSUIWDFsv|12Rjl{)t&}zV z8&V5heWaG8iiNc#*B+|qRK)^CBnMRsTi!k{3{?|Fg1dyFe}@1S2@aPqcLl*~2tdRYQh5d#%5xoh)TL{t>1n$R}hHIYt34(VK;F4S< z*K_Y-+WQDHi1XY}F=HA*HiG1a1&dJ^0{jZNuOV%-0u^^J4&4_s}D)$ffO zYT@8X50#1*31{=7Ft%9u$|!6-%0=8?k3H&*8V&?0TW7xse#6{e$RVyr0@Vg%GaS2CE%qZK zUo+w=LnLXQNS8yu7j?lnpA~M zZ{?vfJ7Ze!&p}PwGpjF;>dR-ct#MN+D9SUYnt*)HT6s}-K{u5%?TIvQ`@lY9eP}%A zwu~{`aI4jG=Bcr#X0pqnzS{imSU%v);xaySZd@7lx{!T-Bg0Hm%>STV@q7X9d) z7G}<8B`8h6%+RvKDXR<0fUR`#FRjiD`I+hj?{itk`5qm+@!};i%lm9{fx(g)?T1#$ zjM^k*GTpf36Z3Zxf+NN0JS5dQ_c@%t?SKT+mp)b2C9~EQQR|AS+^BV>f7>;!WiH1M zD3~Z8FQ3V&h+CIj)L+m~Nut&!k_l6%tGw6c2fqz62mcJC26s6~o`r7`_AtRsM>rV` z_Vgb3P8HyiAtPcuSc{P@FaE)qvy8LmQ}%&9IFp+YDUo5!eM%{ukVu|Y6V5+FKb9uW zXu}C;uhN5dKJo*xTs{J{L!3)o1t276C$cl1rB4dPaQav;VtTdRxnel^yqpNKiYwHa z2X@4gYJo;<8K}z3i9Ujm>D3>BKBB1U%k$;?3VelNsaN}qDLpR`OQxh1iD@0uvy9K= zEnt;opS#3c1fd#ON=3=j#+k|`9f^GAzPd%_*L-4m+LyHQ+GJZS9JQkApV@1GGte-` z-rU49FY(M5o*i;uu{S5v&Iar-n7rmI8u88nIE#1=JXLctxkZU%4?7#OZmI?(=f;y% z5~+}%>GltANe6XGBMw0|a&!yoM-N%>FU{U}&%sih-n*sn^`X52uKkd}u~1+|xVXCU z`(5<&P@*GF9~?$ih)9`8&ljte)=oZBuN0OX=s9q3G}%@LW(*7~{ottJd@URtCGSQL zj>@{}ha>hLCRy&yN*%z{>kDg`AuaO_FI* z9K0%%a9D+tk#1hr0S6|tIt1xm-T`UcMnuP*vU^TTa+@J_#GX!T7oBf!Sl`p%?(A`I zY)GE0{1%en=b$Vc1UHpsI5!CvUof-U#%;kJuh>J*Q1j&8+0w>nY2#b6SZOmH&Gv7N z7aILLJ~EX6qXaAP@$utecU?01RII2GD0ER%Ko&154IX@@BKX*NA4CjA6FK8KK~Lyl z@WeGkEu5k>m%>r&f?~gLit>__SCHKbUXB|S+<%4Mapw@o0l<|l8a%n=IMv0%4g#*s zL$`1}LxzIf>S8kpPGV#Ohv;UwizAFY?!>}wOfM)gEQhO#m$&!h@pxC?Ai7z5TpSW@ zUJaw}=y4u%_3&BXlnlrJg?%FACPXo_l@e|TdrWYB0NKmfj9Iu(NL-ttE;rmVLwvWn zr!iF}9vtF+g;7}t?8V4&cDa9#afNUNf!ZnFQN#TQNG6lbONZ>dbQu1Jn&8>Q%REq4 zLCzoZGB|$>2WT;Y^q0GVwaJHuhlb&BZSM*ND(Vs=HD@AsTx-YWPw9q#Qx#RkUMO@F!*X~w74OlylyHXcI-7^ zlMX1Zm!eZ}_l53Pd!|p$lx_*A=gO+X@;~n%-x1gnaK|@qjTUSOJP?!y9|%c9Tf>D@ zvZ;g9RdeN)u#GWvB|m)dvMEw-kCZh9w#SXd!TsMp6wt=9qOwPyxF$!IP8QLY1NY7nX#jVf!U{_}EnL zB{ovBGO#UPV3{qbjut>4!>;L7k%H=L1zTm_Ff`NeE?AFW$kAZPD*a(n6{Lzg$9fxiy)E&x8_^m7)S=qTO(O15}_? z;X{Ec5Y(ALVFGb$HRPaJx9In!ThlG75Tf9&Mg=Cg0w*zY(9&-cVi0jgBVv%om+b>< zplE#qHxgxv2$jn!?-AkhlcGn)i*)kE_Iw52f|Rx&_WNjXm(SpWpbo4x@*y%cT>w^vII-T$%M;XCLAj49Dy|`I)JcR zZxLJ)mF-mlOchXd;#fesF6GUr)fCe8UNb<$53)gQlXh1m`y+-xY%5HY0qznJ3Pm?O zqLVxLb(nrll4x433oo4i_?e%!T7_F};GTvXS1x?~)@wJ%E>TT6_41pvvTLny{Y z5|OlC(RxUxBcW(R3DnCIXD!nTq+aU-Z@=*F8NAZsIX|2?hQr4HIQlf4Iu;Hd!_^hn z-}?*e2`k*Uar6D}FPwQB@4Wc-X*khDDo?ak3Hh%HHQhWr4cA}L=D1(OOeGIG2{Hll zehy6zN$CKbRT_w)8Tg{JmzO($Q;sOWF@vock=9v96gIqK4NfEx5$p(-J&FL8KEXIa zq=w@dB~rsJ46R0he3ZM10L`We50hg~Hynrp$>B{*YXQJ31~|AAgE*esN(B4H|G-QX z4Y>b_;C~@_8UQaj#{C8(l+|;;!|4A;@J|SSkKmsX`~krq5!^=be-NPHz}-QBS{|<^ z;s!a}tin6!4mo=VguzJovvAXjpv zO9OcO&93oX!N;yNz217Mb*5l7oazxJ1hZwZ@ec|m>_HgU;mYLFx zdgO;N+zfHWZw$U={X zw@&3xwa?!pWXz=r8S~~c@aSj?IWIJy9R``OcjRyGe!u-{ z<<e;3TqD>E6T@!2CGuyO3+O$7%;L%vq zW0A)XN1L9QZE{4L9FecJ$C}uvp)sHiwuJVFm2r?!)`pgc_lHl0+ouZNYM-up^Y~QT z^x)qd{2>3Y4_|%ogJY5Xha-b4)&p`>K zsvCIIX1oDN)TgN)uShAA@$~9vtS2j_9yu@&6touo?rB?@Qsxux3;ay=sFEzLn{Lb| z8^`mni)_fS<(o;QfTL=PV&NV@5LZ&fGRoppYE^rvJ;IwU*gV9UV4=NF&h={W95Ji7 zoS0X*mkyOP^2^wNJiD821BVmEU%LO=PwwI8?Y~#;)pkn3CYH3uP=8@=@IG&slV;u5 zWvU}_v&ti0-IsoA-4}i9lyX!+gIQ6*DGEA|PwDWi^1hJ=wzVGFMlPK@l(-r7h`8B! z#0}RHwL3Y_5d;p9aRxj`j`ce^*3seV9dMxDPOdmz_c`luv7O|)5-cn*d&2fnMG>qk zvRk7NzV$DdpaGHrI}7*_KsJVc09iJD3K!puxGVx5@eKrV0QWSYJ~!rS1o;em36=vC-7uJ}oLqHiC$NdYl>{~u$4WR;ZRaJsc*)~p zvJw1bNt`;hHBWqv8qy-L*qVtG3okOQwVEEtQt=-6=N13@o(?r{NTg2*$6?XVF za|OnU2ge_blpl>1d=+lZvVdkfTeB%zvngiT45xDEN|%K^v(+1-)f-}^8zU++oMJPW zBj)Adw$~k(9I^V1G5sdEFAE&m3TDmrsM$W%`u3(bHpNzMi|OHf*>$}sVy+GEetqAi zeX+XrG5rRLydr8|F=czZ;f;n^(*tlnpkMww6$3tK4dV?V@Ky|!PB~}tTKvkmzKHmn z9SAxjdh3|nFY(*)jz86yDquXfGI%nSJLx_PJTq8-r7G+M=G=a{W@<~=GOhn0cSg16 zI@qlK)OCW7V4gWx9WhkGZGo^|F?hNa?OlE2eW6FE>@!8HzzY(*D_6ZZ612bIiyO-( zeB-{*fsiv|tQnVsFk+uG9+h#+R~_i?nd*u@QICPvpL-l1C=9Gz;8Yln&so zQpTp(H~2Etb>xVBZBv7NbxVW2p{WJPn3HoIx$)x{KYsmtACo(iZhUX*#!Ei}9cJOo z3pXbIV&Uf#M{fRT;>MfbgUgL>{P^jc;THw$BX}3Jz3B)s=D8EG6>ID5t0BFmenpFm zWmk2quD7?WSY6+|%E{Ira~|ucU*l|MS-ZX6%rmCB&;n!JKcA+9{E%Hgm{_Svd< zrNhDYw>uny55CMj>=wEef(Cd67*+>{2`S~3*t?#tW8`ust_ZW0U|sF+c@jwLj@^5= zBL)XI+QIFB2OfU-5ce>k2<|#9h-?%YO#`{zv;hs29=HjDSaJo!t$7g&5=4^Z=8(ek zrbYQ^2qqT|3BLJiY!EF^f@cp}nz*+Syo;a#!Da;H%fON3;2w0)4G}bAMm+#twO;rf zH*)om0e_79F9F<^NhFfr%H9^WLYufh|uzH7ft5ENj&B%-XB*!wUxhuCws_$%;!yqzg8YOqQKtSs2*$%pg8$ zHihbR(XPdr#kn&p`|iA?oHB`YcQ|rf*uJXdQswwk`3Jn{M8>#ERRKv<{y0u@mFskW zB(G<8c9Cvf*j4GR?e2N~`t|GX*YEwh|I=zUBS;Mw|0m#dAoSn(LrY|)a-W6D6k<^a zVhNVyi4H<7$qq^_=?)r7ir4k)JM=`F$Ix%=FhQMWb-cOX(qVzRh1FjqIvCb)5p`Hu zBjh&L1i76xL+%(Mz07E>xmnfN?GtA6 zcYK3VPe^F+jP#q=u$paNLZMIjq@FbbzTm@px+fG42L}R2&vOHkpTbO;WP}ob-#<&M z^CAK$LPsbG_f%7_Hgk;trHrm-+K-?(ajqAkh)&A3_kyHHQ?KDs3P{muQqIB{5q-q4 zi40R78CXh2!-!EPS+cJZAwee_Sn50>5aXwSMyoW>Cekf=q#HF2LDC>d(*3_kdQ;Z- zTK{x3RA~C+Q$?D`=dqUQ~g;?`X$?OhTHj$EVjV+o!0vRX9D@{mpYjcrdN3*gSsW3~o zuojK}B#Kz2BCVx&t5(aEG9z0xZa8@i{^h=eGP>2`zg+~-ya3Cn9ci~9TF9`=ht_}X;f57n@L+e{mL1DaWY-H^4vb%7q zVX`67d(-WW8kP%-rrIalZx)s>6qY9gslt6Rb5s`}s4FUIN1IR~vuw=Wn-PX@C3WD=*I+U)*tUt`gJtd}b+r$MtT} zbkVyzr+3a;7E2Dz_1v<#C;DQ2iL#V!XOvoYxZ}-#YfO|(T0V0eOH#?EX~VnrX?x03 z1K;oa=gQ`~KCHOT|7+92Q^%sZ|FRdvdsaaE`pNpKLz9P+*4gseqB+C-{_mvRhoi=2 zi*=$tRzLAf?3qO6qNQy5#dW>Gw0F6nBv~~xm@0TOdUV-Y81G5ai_Y>H=dxqVlx5PA zIGU_kbd-NZA=mB|#u=}8t!>?l3ifYgsl~$Nlk& z%Y34Frs9UFcGmZK!H(#WCB{0@5^IScNjx!m{08IsJ%tK)f>3kays7r9A`m|BEdS$| zdgOTQ9wJS9mzctvOz{F!ocPN{#=8sywcM2CDBB#XR+Vp+!$80CpNsHM@Q3u0zIyq48GVi>61WYjF4Q`cL~ za=rIQBRB1c)R62Oz|)#-kqGEt3R%ol)bH0Op7UylVn>ega;9 zFC!G-I-Z#TunP%TD*;1B0WX}e4KhWCLyRC`5F}viB$Q$*C32G2q&j}plN-AH>Qn0YVGs&NlpHzo`Faa|AGr#VT)wwrbCLOpJ>1UT%iB`i!h3>18@#dXNW z(53$;!PR6ub>OCZ_t$%B@F`CBlwr~^#Y{4ZcJSejeNo*;XIQ>y@g)5-PyJor z?CCl0KfS!06W<=GqC_rC82ajy5;uNTh=shYz}jC-Oj)|O^jWXhJ9 zf{Bx{lZm6hWlGm~pn{4oJ;>&a7hOI(cI=kL9si4Y%l3JC`+b-*@?)%_rL0>@fQy(y z-_#vNHsj2hAR*x~)YPljYPk|$={3iqx+gM1$rMYe$1JZS!k7GOdJW{m0nxbgxE+>a z$pE?GFloH`oK5z?t1`*2)qu#OL7MxUX^`g4r@_W6LiUOehu74WK4+MwV#~E!r~x$M z0jYRNh3*Oth=88h0Ot?!Awi)4_$UT{NDu(ecnu0U0IBNN>;3Zqfw{bV2-kK)JP{uOZPj z(}Mdxv3cK@7U^AZpc(tva{_jb553x8Q&r=&=NlXhmbjKRvWH%FvYQCfG6_5~0<)yA z>8@s4;Xas&&+yuizX!qUS;N=#$aAQ)SoDx&?6@CE>_&sj>7c&RJV@kFK)e{7L1 zUdePklQ=WuzCl-iY2ILj8@)5$GSvt__(n#^k}RcdP=r(=COkCCBs_tDMF8x}dSaP4 zf+qBS;PI2^V7nuFSug7{(8MI`C&_V!hPFr+X28>7t~dJDy^XR#HsXhtH1re70Py93 zst^k@W{7=oUXE;J!A~&xrNCI3(eR_uW)kIxW~Om(m~D1MtpCFj$A3^8lpMyd%f<232pPx$uA&h|l{@B2CcZ$LOAn${l^N8Zg zIPncMp&M9Ldls;5DkR*Yse!?Mg*^GL;c}FiQ8!1K@slm!Yd$R5dPv# z$kKkhDpnQuC7g+-lzG=!^OCzTE<}%v9sAtojFQV%$3jV6%6S;_MA@u3*L8j5^|JYr zx&`Oql(k7^nBJLkHcsz^=DNAk>rcO4mfX4EY)o07iIPio_c=4^ZdfL zwj0dJbtkgB)?J8k#h*yH=PkwabnzeVIgzW0_=DnX6fqS2M{~2&{LeIGzc!hhx0ruj zKtt{&1nlnMg~HI;$%g!$ohpJ=bg-b|5p}18oxq?NFxKRQUFk;-XTMLv?gj|(B9L}G z=~DGc0*=q>3yS(UprTGSLaH7`UGslHYS77q(L?S{eGfzIP$mB#%)!tR literal 0 HcmV?d00001 diff --git a/contrast/utils/calsimi.py b/contrast/utils/calsimi.py new file mode 100644 index 0000000..a965707 --- /dev/null +++ b/contrast/utils/calsimi.py @@ -0,0 +1,216 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Mon Mar 31 16:25:43 2025 + +@author: wqg +""" +import numpy as np +from scipy.spatial.distance import cdist + + +def get_topk_percent(data, k): + """ + 获取数据中最大的 k% 的元素 + """ + # 将数据转换为 NumPy 数组 + if isinstance(data, list): + data = np.array(data) + + percentile = np.percentile(data, 100-k) + top_k_percent = data[data >= percentile] + + return top_k_percent +def cluster(data, thresh=0.15): + # data = np.array([0.1, 0.13, 0.7, 0.2, 0.8, 0.52, 0.3, 0.7, 0.85, 0.58]) + # data = np.array([0.1, 0.13, 0.2, 0.3]) + # data = np.array([0.1]) + + if isinstance(data, list): + data = np.array(data) + + data1 = np.sort(data) + cluter, Cluters, = [data1[0]], [] + for i in range(1, len(data1)): + if data1[i] - data1[i-1]< thresh: + cluter.append(data1[i]) + else: + Cluters.append(cluter) + cluter = [data1[i]] + Cluters.append(cluter) + + clt_center = [] + for clt in Cluters: + ## 是否应该在此处限制一个聚类中的最小轨迹样本数,应该将该因素放在轨迹分析中 + # if len(clt)>=3: + # clt_center.append(np.mean(clt)) + clt_center.append(np.mean(clt)) + + # print(clt_center) + + return clt_center + +def calsiml(feat1, feat2, topkp=75, cluth=0.15): + '''轨迹样本和标准特征集样本相似度的选择策略''' + matrix = 1 - cdist(feat1, feat2, 'cosine') + simi_max = [] + for i in range(len(matrix)): + sim = np.mean(get_topk_percent(matrix[i, :], topkp)) + simi_max.append(sim) + cltc_max = cluster(simi_max, cluth) + Simi = max(cltc_max) + + ## cltc_max为空属于编程考虑不周,应予以排查解决 + # if len(cltc_max): + # Simi = max(cltc_max) + # else: + # Simi = 0 #不应该走到该处 + + return Simi + + +def calsimi_vs_stdfeat_new(event, stdfeat): + '''事件与标准库的对比策略 + 该比对策略是否可以拓展到事件与事件的比对? + ''' + front_boxes = np.empty((0, 9), dtype=np.float64) ##和类doTracks兼容 + front_feats = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容 + for i in range(len(event.front_boxes)): + front_boxes = np.concatenate((front_boxes, event.front_boxes[i]), axis=0) + front_feats = np.concatenate((front_feats, event.front_feats[i]), axis=0) + + back_boxes = np.empty((0, 9), dtype=np.float64) ##和类doTracks兼容 + back_feats = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容 + for i in range(len(event.back_boxes)): + back_boxes = np.concatenate((back_boxes, event.back_boxes[i]), axis=0) + back_feats = np.concatenate((back_feats, event.back_feats[i]), axis=0) + + front_simi, back_simi = None, None + if len(front_feats): + front_simi = calsiml(front_feats, stdfeat) + if len(back_feats): + back_simi = calsiml(back_feats, stdfeat) + + '''前后摄相似度融合策略''' + if len(front_feats) and len(back_feats): + diff_simi = abs(front_simi - back_simi) + if diff_simi>0.15: + Similar = max([front_simi, back_simi]) + else: + Similar = (front_simi+back_simi)/2 + elif len(front_feats) and len(back_feats)==0: + Similar = front_simi + elif len(front_feats)==0 and len(back_feats): + Similar = back_simi + else: + Similar = None # 在event.front_feats和event.back_feats同时为空时 + + return Similar, front_simi, back_simi + + + + + +def calsimi_vs_stdfeat(event, stdfeat): + evtfeat = event.feats_compose + if isinstance(event.feats_select, list): + if len(event.feats_select) and len(event.feats_select[0]): + evtfeat = event.feats_select[0] + else: + return None, None, None + else: + evtfeat = event.feats_select + + if len(evtfeat)==0 or len(stdfeat)==0: + return None, None, None + + + evtfeat /= np.linalg.norm(evtfeat, axis=1)[:, None] + stdfeat /= np.linalg.norm(stdfeat, axis=1)[:, None] + + matrix = 1 - cdist(evtfeat, stdfeat, 'cosine') + matrix[matrix < 0] = 0 + + simi_mean = np.mean(matrix) + simi_max = np.max(matrix) + stdfeatm = np.mean(stdfeat, axis=0, keepdims=True) + evtfeatm = np.mean(evtfeat, axis=0, keepdims=True) + simi_mfeat = 1- np.maximum(0.0, cdist(stdfeatm, evtfeatm, 'cosine')) + + return simi_mean, simi_max, simi_mfeat[0,0] + + +def calsimi_vs_evts(evta, evtb, simType=1): + if simType==1: + if len(evta.feats_compose) and len(evtb.feats_compose): + feata = evta.feats_compose + featb = evtb.feats_compose + matrix = 1 - cdist(feata, featb, 'cosine') + similar = np.mean(matrix) + else: + similar = None + return similar + + if simType==2: + if len(evta.feats_compose) and len(evtb.feats_compose): + feata = evta.feats_compose + featb = evtb.feats_compose + matrix = 1 - cdist(feata, featb, 'cosine') + similar = np.max(matrix) + else: + similar = None + return similar + + if simType==3: + if len(evta.feats_compose) and len(evtb.feats_compose): + feata = evta.feats_compose + featb = evtb.feats_compose + similar = calsiml(feata, featb) + else: + similar = None + return similar + + + ##1. the front feats of evta, evtb + fr_feata = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容 + for i in range(len(evta.front_feats)): + fr_feata = np.concatenate((fr_feata, evta.front_feats[i]), axis=0) + + fr_featb = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容 + for i in range(len(evtb.front_feats)): + fr_featb = np.concatenate((fr_featb, evtb.front_feats[i]), axis=0) + + ##2. the back feats of evta, evtb + bk_feata = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容 + for i in range(len(evta.back_feats)): + bk_feata = np.concatenate((bk_feata, evta.back_feats[i]), axis=0) + + bk_featb = np.empty((0, 256), dtype=np.float64) ##和类doTracks兼容 + for i in range(len(evtb.back_feats)): + bk_featb = np.concatenate((bk_featb, evtb.back_feats[i]), axis=0) + + + front_simi, back_simi = None, None + if len(fr_feata) and len(fr_featb): + front_simi = calsiml(fr_feata, fr_featb) + + if len(bk_feata) and len(bk_featb): + back_simi = calsiml(bk_feata, bk_featb) + + '''前后摄相似度融合策略''' + if front_simi is not None and back_simi is not None: + diff_simi = abs(front_simi - back_simi) + if diff_simi>0.15: + similar = max([front_simi, back_simi]) + else: + similar = (front_simi+back_simi)/2 + elif front_simi is not None and back_simi is None: + similar = front_simi + elif front_simi is None and back_simi is not None: + similar = back_simi + else: + similar = None # 在event.front_feats和event.back_feats同时为空时 + + return similar + + diff --git a/contrast/utils/databits.py b/contrast/utils/databits.py new file mode 100644 index 0000000..9d59e2b --- /dev/null +++ b/contrast/utils/databits.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Tue Apr 1 16:43:04 2025 + +@author: wqg +""" +import os +import pickle +import numpy as np +from scipy.spatial.distance import cdist + + +def int8_to_ft16(arr_uint8, amin, amax): + arr_ft16 = (arr_uint8 / 255 * (amax-amin) + amin).astype(np.float16) + + return arr_ft16 + +def ft16_to_uint8(arr_ft16): + # pickpath = r"\\192.168.1.28\share\测试_202406\contrast\std_features_ft32vsft16\6902265587712_ft16.pickle" + + # with open(pickpath, 'rb') as f: + # edict = pickle.load(f) + + # arr_ft16 = edict['feats'] + + amin = np.min(arr_ft16) + amax = np.max(arr_ft16) + arr_ft255 = (arr_ft16 - amin) * 255 / (amax-amin) + arr_uint8 = arr_ft255.astype(np.uint8) + + arr_ft16_ = int8_to_ft16(arr_uint8, amin, amax) + + arrDistNorm = np.linalg.norm(arr_ft16_ - arr_ft16) / arr_ft16_.size + + return arr_uint8, arr_ft16_ + + +def data_precision_compare(stdfeat, evtfeat, evtMessage, similPath='', save=True): + evt, stdbcd, label = evtMessage + rltdata, rltdata_ft16, rltdata_ft16_ = [], [], [] + + matrix = 1 - cdist(stdfeat, evtfeat, 'cosine') + simi_mean = np.mean(matrix) + simi_max = np.max(matrix) + stdfeatm = np.mean(stdfeat, axis=0, keepdims=True) + evtfeatm = np.mean(evtfeat, axis=0, keepdims=True) + simi_mfeat = 1- np.maximum(0.0, cdist(stdfeatm, evtfeatm, 'cosine')) + rltdata = [label, stdbcd, evt, simi_mean, simi_max, simi_mfeat[0,0]] + + + ##================================================================= float16 + stdfeat_ft16 = stdfeat.astype(np.float16) + evtfeat_ft16 = evtfeat.astype(np.float16) + stdfeat_ft16 /= np.linalg.norm(stdfeat_ft16, axis=1)[:, None] + evtfeat_ft16 /= np.linalg.norm(evtfeat_ft16, axis=1)[:, None] + + + matrix_ft16 = 1 - cdist(stdfeat_ft16, evtfeat_ft16, 'cosine') + simi_mean_ft16 = np.mean(matrix_ft16) + simi_max_ft16 = np.max(matrix_ft16) + stdfeatm_ft16 = np.mean(stdfeat_ft16, axis=0, keepdims=True) + evtfeatm_ft16 = np.mean(evtfeat_ft16, axis=0, keepdims=True) + simi_mfeat_ft16 = 1- np.maximum(0.0, cdist(stdfeatm_ft16, evtfeatm_ft16, 'cosine')) + rltdata_ft16 = [label, stdbcd, evt, simi_mean_ft16, simi_max_ft16, simi_mfeat_ft16[0,0]] + + '''****************** uint8 is ok!!!!!! ******************''' + ##=================================================================== uint8 + # stdfeat_uint8, stdfeat_ft16_ = ft16_to_uint8(stdfeat_ft16) + # evtfeat_uint8, evtfeat_ft16_ = ft16_to_uint8(evtfeat_ft16) + + stdfeat_uint8 = (stdfeat_ft16*128).astype(np.int8) + evtfeat_uint8 = (evtfeat_ft16*128).astype(np.int8) + stdfeat_ft16_ = stdfeat_uint8.astype(np.float16)/128 + evtfeat_ft16_ = evtfeat_uint8.astype(np.float16)/128 + + absdiff = np.linalg.norm(stdfeat_ft16_ - stdfeat) / stdfeat.size + + matrix_ft16_ = 1 - cdist(stdfeat_ft16_, evtfeat_ft16_, 'cosine') + simi_mean_ft16_ = np.mean(matrix_ft16_) + simi_max_ft16_ = np.max(matrix_ft16_) + stdfeatm_ft16_ = np.mean(stdfeat_ft16_, axis=0, keepdims=True) + evtfeatm_ft16_ = np.mean(evtfeat_ft16_, axis=0, keepdims=True) + simi_mfeat_ft16_ = 1- np.maximum(0.0, cdist(stdfeatm_ft16_, evtfeatm_ft16_, 'cosine')) + rltdata_ft16_ = [label, stdbcd, evt, simi_mean_ft16_, simi_max_ft16_, simi_mfeat_ft16_[0,0]] + + if not save: + return + + + ##========================================================= save as float32 + rppath = os.path.join(similPath, f'{evt}_ft32.pickle') + with open(rppath, 'wb') as f: + pickle.dump(rltdata, f) + + rtpath = os.path.join(similPath, f'{evt}_ft32.txt') + with open(rtpath, 'w', encoding='utf-8') as f: + for result in rltdata: + part = [f"{x:.3f}" if isinstance(x, float) else str(x) for x in result] + line = ', '.join(part) + f.write(line + '\n') + + + ##========================================================= save as float16 + rppath_ft16 = os.path.join(similPath, f'{evt}_ft16.pickle') + with open(rppath_ft16, 'wb') as f: + pickle.dump(rltdata_ft16, f) + + rtpath_ft16 = os.path.join(similPath, f'{evt}_ft16.txt') + with open(rtpath_ft16, 'w', encoding='utf-8') as f: + for result in rltdata_ft16: + part = [f"{x:.3f}" if isinstance(x, float) else str(x) for x in result] + line = ', '.join(part) + f.write(line + '\n') + + + ##=========================================================== save as uint8 + rppath_uint8 = os.path.join(similPath, f'{evt}_uint8.pickle') + with open(rppath_uint8, 'wb') as f: + pickle.dump(rltdata_ft16_, f) + + rtpath_uint8 = os.path.join(similPath, f'{evt}_uint8.txt') + with open(rtpath_uint8, 'w', encoding='utf-8') as f: + for result in rltdata_ft16_: + part = [f"{x:.3f}" if isinstance(x, float) else str(x) for x in result] + line = ', '.join(part) + f.write(line + '\n') \ No newline at end of file diff --git a/contrast/utils/event.py b/contrast/utils/event.py index e65ff1d..02df620 100644 --- a/contrast/utils/event.py +++ b/contrast/utils/event.py @@ -5,19 +5,25 @@ Created on Tue Nov 26 17:35:05 2024 @author: ym """ import os +import sys import cv2 import pickle import numpy as np from pathlib import Path -import sys -sys.path.append(r"D:\DetectTracking") +FILE = Path(__file__).resolve() +ROOT = FILE.parents[2] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) + from tracking.utils.plotting import Annotator, colors from tracking.utils.drawtracks import drawTrack from tracking.utils.read_data import extract_data, read_tracking_output, read_similar from tracking.utils.read_data import extract_data_realtime, read_tracking_output_realtime + + # import platform # import pathlib # plt = platform.system() diff --git a/contrast/utils/tools.py b/contrast/utils/tools.py index 7abdb5e..f3214e7 100644 --- a/contrast/utils/tools.py +++ b/contrast/utils/tools.py @@ -4,8 +4,81 @@ Created on Thu Oct 31 15:17:01 2024 @author: ym """ +import os import numpy as np +import pickle +from pathlib import Path import matplotlib.pyplot as plt +from .event import ShoppingEvent + +def init_eventDict(sourcePath, eventDataPath, stype="data"): + ''' + stype: str, + 'source': 由 videos 或 images 生成的 pickle 文件 + 'data': 从 data 文件中读取的现场运行数据 + "realtime": 全实时数据,从 data 文件中读取的现场运行数据 + + sourcePath:事件文件夹,事件类型包含2种: + (1) pipeline生成的 pickle 文件 + (2) 直接采集的事件文件夹 + ''' + k, errEvents = 0, [] + for evtname in os.listdir(sourcePath): + bname, ext = os.path.splitext(evtname) + source_path = os.path.join(sourcePath, evtname) + + if stype=="source" and ext not in ['.pkl', '.pickle']: continue + if stype=="data" and os.path.isfile(source_path): continue + if stype=="realtime" and os.path.isfile(source_path): continue + + evt = bname.split('_') + condt = len(evt)>=2 and evt[-1].isdigit() and len(evt[-1])>=10 + if not condt: continue + + pickpath = os.path.join(eventDataPath, f"{bname}.pickle") + if os.path.isfile(pickpath): continue + + # event = ShoppingEvent(source_path, stype) + try: + event = ShoppingEvent(source_path, stype) + with open(pickpath, 'wb') as f: + pickle.dump(event, f) + print(evtname) + except Exception as e: + errEvents.append(source_path) + print(f"Error: {evtname}, {e}") + # k += 1 + # if k==1: + # break + + errfile = Path(eventDataPath).parent / 'error_events.txt' + with open(str(errfile), 'a', encoding='utf-8') as f: + for line in errEvents: + f.write(line + '\n') + + +def get_evtList(evtpath): + '''==== 0. 生成事件列表和对应的 Barcodes 集合 ===========''' + bcdList, evtpaths = [], [] + for evtname in os.listdir(evtpath): + bname, ext = os.path.splitext(evtname) + + ## 处理事件的两种情况:文件夹 和 Yolo-Resnet-Tracker 的输出 + fpath = os.path.join(evtpath, evtname) + if os.path.isfile(fpath) and (ext==".pkl" or ext==".pickle"): + evt = bname.split('_') + elif os.path.isdir(fpath): + evt = evtname.split('_') + else: + continue + + if len(evt)>=2 and evt[-1].isdigit() and len(evt[-1])>=10: + bcdList.append(evt[-1]) + evtpaths.append(fpath) + + bcdSet = set(bcdList) + + return evtpaths, bcdSet diff --git a/execute_pipeline.py b/execute_pipeline.py index 6e9fa4f..39ed7ae 100644 --- a/execute_pipeline.py +++ b/execute_pipeline.py @@ -5,27 +5,37 @@ Created on Fri Mar 28 11:35:28 2025 @author: ym """ -from pipeline_01 import execute_pipeline +from pipeline import execute_pipeline -execute_pipeline(evtdir = r"D:\datasets\ym\后台数据\unzip", - DataType = "raw", # raw, pkl - kk=1, - source_type = "video", # video, image, - save_path = r"D:\work\result_pipeline_V5", - yolo_ver = "V5", # V10, V5 - weight_yolo_v5 = r'./ckpts/best_cls10_0906.pt' , - weight_yolo_v10 = r'./ckpts/best_v10s_width0375_1205.pt', - saveimages = False - ) +def execute(datapath, savepath_v5, savepath_v10): + execute_pipeline(evtdir = datapath, + DataType = "raw", # raw, pkl + kk=None, + source_type = "video", # video, image, + save_path = savepath_v5, + yolo_ver = "V5", # V10, V5 + weight_yolo_v5 = r'./ckpts/best_cls10_0906.pt' , + weight_yolo_v10 = r'./ckpts/best_v10s_width0375_1205.pt', + saveimages = False + ) + execute_pipeline(evtdir = datapath, + DataType = "raw", # raw, pkl + kk=None, + source_type = "video", # video, image, + save_path = savepath_v10, + yolo_ver = "V10", # V10, V5 + weight_yolo_v5 = r'./ckpts/best_cls10_0906.pt' , + weight_yolo_v10 = r'./ckpts/best_v10s_width0375_1205.pt', + saveimages = False + ) + +datapath = r'/home/wqg/dataset/test_dataset/base_dataset/single_event/source/' +savepath_v5 = r'/home/wqg/dataset/pipeline/contrast/single_event_V5' +savepath_v10 = r'/home/wqg/dataset/pipeline/contrast/single_event_V10' +execute(datapath, savepath_v5, savepath_v10) -execute_pipeline(evtdir = r"D:\datasets\ym\后台数据\unzip", - DataType = "raw", # raw, pkl - kk=1, - source_type = "video", # video, image, - save_path = r"D:\work\result_pipeline_V10", - yolo_ver = "V10", # V10, V5 - weight_yolo_v5 = r'./ckpts/best_cls10_0906.pt' , - weight_yolo_v10 = r'./ckpts/best_v10s_width0375_1205.pt', - saveimages = False - ) \ No newline at end of file +datapath = r'/home/wqg/dataset/test_performence_dataset/' +savepath_v5 = r'/home/wqg/dataset/pipeline/contrast/performence_V5' +savepath_v10 = r'/home/wqg/dataset/pipeline/contrast/performence_V10' +execute(datapath, savepath_v5, savepath_v10) diff --git a/hands/__pycache__/hand_inference.cpython-312.pyc b/hands/__pycache__/hand_inference.cpython-312.pyc index bf54fe94e2d0c1fd3fb5299bd284268dc89f1c7c..35e1f47bac8707a16b87ce0a4bbb75767d3146d3 100644 GIT binary patch delta 21 bcmdm_y-AzrG%qg~0}!|cKTF@pvrH5KLE{D# delta 21 bcmdm_y-AzrG%qg~0}#}@ElS(SvrH5KL8Arv diff --git a/models/__pycache__/__init__.cpython-312.pyc b/models/__pycache__/__init__.cpython-312.pyc index 84d0122c4e9e366a9debdd62f5f413a7a19c5393..0c0f867ce767b9009456304e451a4a25770c6db8 100644 GIT binary patch delta 20 acmeBS>|x|N&CAQh00eHq&(bIIGyniEy#*Nn delta 20 acmeBS>|x|N&CAQh00gyei_#|YGyniEm<0X+ diff --git a/models/__pycache__/common.cpython-312.pyc b/models/__pycache__/common.cpython-312.pyc index c3173a8cd9fc81ad26a347f81efef5bb93666c07..b614dff12601299961fcea3cde615c1fccfeff79 100644 GIT binary patch delta 26 gcmey~2L84Z;EG-Ms$egmoqigf6?ryK#<%c31 zOe#*%2MPQXh6aV7gQAZTSqXvkAt8!B)t}J0o5xM*z&+1%p6B=bo#&kM+`H||9rksb z&4TFY>i-!V6kgi}0X9gvFlai9P|B!S$($g$uzqqFAvvVjG^jQb#bg`AW-+%yNHwlN z&Q}2!tr}MJxmC(EQ@)?o_g~hkaYe^Cswv@S%6W@TY>%6eGyqafnDfze!b|=L0q_x< zGjPPu@HA^?ib;P#4H84-Ew;pffat1L3h6wf%bkjufoW;w+R@1?r==mpq7%AZY^74g zqDl?(vaDaus-wj$lI9b&%+Fg@FW2p1DnN_pWLL9CDw2+4Ed^$VFU6NI4VT42*NxCYaj689b!LglF zn=kE_1eyCvCj+Y-wy_K#}+atR$neGgG%}K^~&&Ywx|i05TDL5ojXQ zzJpdi8ofR)Cn+HsU0d==0C&in(gDi?MR(IL`H1-a)$M%oS6=$WOG}2&eAPFx-Kd~vEoDY8|L;mNc0J0y4zo9jglm>p?U(p-1e?Vey nC0Pu_C2hACNG_p9_R?vKYnz_M*QUlh-&D? zn+62_A`` zf7K!U88ab^yP#t(9%^Ux0ygbi_3itG2G$_5tWkJ;iY(`&<1Ia=Mn%?D>}Jl_OjlA2 zA9l*}suphwT-P(cxhTHZvluc|sn$<;X`6Qx&Xe))TvC~JV7FmH4xffHK9<7~qgKg@ zi|o@L=Zg63k@)Z(+;+B5+3F{ZNt|D%u)w3rEDFj@F zMm&WF3A-v#?KJ9;=Y-b0tP*e_RO4!9xSHYec&_4v*#OQaPQf*Nou~y12TTLE5_+5? zkD7gb?|;S3Gz@dE4nM^7jH^`a(}*ZpQl^2%aM4Vgx~t^LvOMXVA(OswzI#QP>okh% zW>3<%Qt&pb#kUj8PqC>TPp9spmaN-2lk5kW!zZaRXvf{u$&KSy8lZ?>>7j6m zS6$}M{5^b;Zc0Usu^k;=@_)m>>9OV diff --git a/models/__pycache__/yolo.cpython-312.pyc b/models/__pycache__/yolo.cpython-312.pyc index 9a3919f6971ad6877af2734e78083c8647c2c49c..072f2b09edab1cda751eda4b972e1788bb4edb84 100644 GIT binary patch delta 23 dcmbR9oN>-`MxN8Wyj%=G;1>KWeIw6=VgO%12dV%7 delta 23 dcmbR9oN>-`MxN8Wyj%=GQ0ulRZ6nWwVgO$M2af;% diff --git a/pipeline.py b/pipeline.py index 8f63a4f..afdc6f0 100644 --- a/pipeline.py +++ b/pipeline.py @@ -60,48 +60,158 @@ def save_subimgs_1(imgdict, boxes, spath, ctype, simidict = None): cv2.imwrite(imgpath, img) +def show_result(event_tracks, yrtDict, savepath_pipe): + '''保存 Tracking 输出的运动轨迹子图,并记录相似度''' + + savepath_pipe_subimgs = savepath_pipe / Path("subimgs") + if not savepath_pipe_subimgs.exists(): + savepath_pipe_subimgs.mkdir(parents=True, exist_ok=True) + + + + + for CamerType, vts in event_tracks: + if len(vts.tracks)==0: continue + if CamerType == 'front': + # yolos = ShoppingDict["frontCamera"]["yoloResnetTracker"] + + yolos = yrtDict["frontyrt"] + ctype = 1 + if CamerType == 'back': + # yolos = ShoppingDict["backCamera"]["yoloResnetTracker"] + + yolos = yrtDict["backyrt"] + ctype = 0 + + imgdict, featdict, simidict = {}, {}, {} + for y in yolos: + imgdict.update(y["imgs"]) + featdict.update(y["feats"]) + simidict.update(y["featsimi"]) -def pipeline( - eventpath, - savepath, - SourceType, - weights, - YoloVersion="V5" - ): - ''' - eventpath: 单个事件的存储路径 + for track in vts.Residual: + if isinstance(track, np.ndarray): + save_subimgs(imgdict, track, savepath_pipe_subimgs, ctype, featdict) + else: + save_subimgs(imgdict, track.slt_boxes, savepath_pipe_subimgs, ctype, featdict) + + '''(3) 轨迹显示与保存''' + illus = [None, None] + for CamerType, vts in event_tracks: + if len(vts.tracks)==0: continue + + if CamerType == 'front': + edgeline = cv2.imread("./tracking/shopcart/cart_tempt/board_ftmp_line.png") + + h, w = edgeline.shape[:2] + # nh, nw = h//2, w//2 + # edgeline = cv2.resize(edgeline, (nw, nh), interpolation=cv2.INTER_AREA) + + img_tracking = draw_all_trajectories(vts, edgeline, savepath_pipe, CamerType, draw5p=True) + illus[0] = img_tracking + + plt = plot_frameID_y2(vts) + plt.savefig(os.path.join(savepath_pipe, "front_y2.png")) + + if CamerType == 'back': + edgeline = cv2.imread("./tracking/shopcart/cart_tempt/edgeline.png") + + h, w = edgeline.shape[:2] + # nh, nw = h//2, w//2 + # edgeline = cv2.resize(edgeline, (nw, nh), interpolation=cv2.INTER_AREA) + + img_tracking = draw_all_trajectories(vts, edgeline, savepath_pipe, CamerType, draw5p=True) + illus[1] = img_tracking - ''' - optdict = {} - optdict["weights"] = weights - - if SourceType == "video": - vpaths = get_video_pairs(eventpath) - elif SourceType == "image": - vpaths = get_image_pairs(eventpath) - event_tracks = [] + illus = [im for im in illus if im is not None] + if len(illus): + img_cat = np.concatenate(illus, axis = 1) + if len(illus)==2: + H, W = img_cat.shape[:2] + cv2.line(img_cat, (int(W/2), 0), (int(W/2), int(H)), (128, 128, 255), 3) + + trajpath = os.path.join(savepath_pipe, "trajectory.png") + cv2.imwrite(trajpath, img_cat) + + + +def pipeline(eventpath, + SourceType, + weights, + DataType = "raw", #raw, pkl: images or videos, pkl, pickle file + YoloVersion="V5", + savepath = None, + saveimages = True + ): + ## 构造购物事件字典 evtname = Path(eventpath).stem barcode = evtname.split('_')[-1] if len(evtname.split('_'))>=2 \ and len(evtname.split('_')[-1])>=8 \ and evtname.split('_')[-1].isdigit() else '' - '''事件结果存储文件夹''' + + '''事件结果存储文件夹: savepath_pipe, savepath_pkl''' if not savepath: savepath = Path(__file__).resolve().parents[0] / "events_result" + savepath_pipe = Path(savepath) / Path("yolos_tracking") / evtname - savepath_pipeline = Path(savepath) / Path("Yolos_Tracking") / evtname + savepath_pkl = Path(savepath) / "shopping_pkl" + if not savepath_pkl.exists(): + savepath_pkl.mkdir(parents=True, exist_ok=True) + pklpath = Path(savepath_pkl) / Path(str(evtname)+".pickle") - """ShoppingDict pickle 文件保存地址 """ - savepath_spdict = Path(savepath) / "ShoppingDict_pkfile" - if not savepath_spdict.exists(): - savepath_spdict.mkdir(parents=True, exist_ok=True) - pf_path = Path(savepath_spdict) / Path(str(evtname)+".pickle") + + + yrt_out = [] + if DataType == "raw": + ### 不重复执行已经过yolo-resnet-tracker + if pklpath.exists(): + print(f"Pickle file have saved: {evtname}.pickle") + return - # if pf_path.exists(): - # print(f"Pickle file have saved: {evtname}.pickle") - # return + if SourceType == "video": + vpaths = get_video_pairs(eventpath) + elif SourceType == "image": + vpaths = get_image_pairs(eventpath) + + + + for vpath in vpaths: + '''================= 2. 事件结果存储文件夹 =================''' + + + if isinstance(vpath, list): + savepath_pipe_imgs = savepath_pipe / Path("images") + else: + savepath_pipe_imgs = savepath_pipe / Path(str(Path(vpath).stem)) + + if not savepath_pipe_imgs.exists(): + savepath_pipe_imgs.mkdir(parents=True, exist_ok=True) + + optdict = {} + optdict["weights"] = weights + optdict["source"] = vpath + optdict["save_dir"] = savepath_pipe_imgs + optdict["is_save_img"] = saveimages + optdict["is_save_video"] = True + + + if YoloVersion == "V5": + yrtOut = yolo_resnet_tracker(**optdict) + elif YoloVersion == "V10": + yrtOut = yolov10_resnet_tracker(**optdict) + + yrt_out.append((vpath, yrtOut)) + + elif DataType == "pkl": + pass + + else: + return + + '''====================== 构造 ShoppingDict 模块 =======================''' ShoppingDict = {"eventPath": eventpath, @@ -112,16 +222,14 @@ def pipeline( "backCamera": {}, "one2n": [] # } - yrtDict = {} - - procpath = Path(eventpath).joinpath('process.data') if procpath.is_file(): SimiDict = read_similar(procpath) ShoppingDict["one2n"] = SimiDict['one2n'] - - for vpath in vpaths: + yrtDict = {} + event_tracks = [] + for vpath, yrtOut in yrt_out: '''================= 1. 构造相机事件字典 =================''' CameraEvent = {"cameraType": '', # "front", "back" "videoPath": '', @@ -140,34 +248,10 @@ def pipeline( CameraEvent["cameraType"] = "back" if bname.split('_')[0] == "1" or bname.find('front')>=0: CameraEvent["cameraType"] = "front" - - '''================= 2. 事件结果存储文件夹 =================''' - if isinstance(vpath, list): - savepath_pipeline_imgs = savepath_pipeline / Path("images") - else: - savepath_pipeline_imgs = savepath_pipeline / Path(str(Path(vpath).stem)) - if not savepath_pipeline_imgs.exists(): - savepath_pipeline_imgs.mkdir(parents=True, exist_ok=True) - savepath_pipeline_subimgs = savepath_pipeline / Path("subimgs") - if not savepath_pipeline_subimgs.exists(): - savepath_pipeline_subimgs.mkdir(parents=True, exist_ok=True) - - - '''================= 3. Yolo + Resnet + Tracker =================''' - optdict["source"] = vpath - optdict["save_dir"] = savepath_pipeline_imgs - optdict["is_save_img"] = True - optdict["is_save_video"] = True - - - if YoloVersion == "V5": - yrtOut = yolo_resnet_tracker(**optdict) - elif YoloVersion == "V10": - yrtOut = yolov10_resnet_tracker(**optdict) - - + '''2种保存方式: (1) no save subimg, (2) save img''' + ###(1) save images yrtOut_save = [] for frdict in yrtOut: fr_dict = {} @@ -177,6 +261,7 @@ def pipeline( yrtOut_save.append(fr_dict) CameraEvent["yoloResnetTracker"] = yrtOut_save + ###(2) no save images # CameraEvent["yoloResnetTracker"] = yrtOut '''================= 4. tracking =================''' @@ -219,108 +304,58 @@ def pipeline( yrtDict["frontyrt"] = yrtOut '''========================== 保存模块 =================================''' - '''(1) 保存 ShoppingDict 事件''' - with open(str(pf_path), 'wb') as f: + # 保存 ShoppingDict + with open(str(pklpath), 'wb') as f: pickle.dump(ShoppingDict, f) - - '''(2) 保存 Tracking 输出的运动轨迹子图,并记录相似度''' - for CamerType, vts in event_tracks: - if len(vts.tracks)==0: continue - if CamerType == 'front': - # yolos = ShoppingDict["frontCamera"]["yoloResnetTracker"] - - yolos = yrtDict["frontyrt"] - ctype = 1 - if CamerType == 'back': - # yolos = ShoppingDict["backCamera"]["yoloResnetTracker"] - - yolos = yrtDict["backyrt"] - ctype = 0 - - imgdict, featdict, simidict = {}, {}, {} - for y in yolos: - imgdict.update(y["imgs"]) - featdict.update(y["feats"]) - simidict.update(y["featsimi"]) - - for track in vts.Residual: - if isinstance(track, np.ndarray): - save_subimgs(imgdict, track, savepath_pipeline_subimgs, ctype, featdict) - else: - save_subimgs(imgdict, track.slt_boxes, savepath_pipeline_subimgs, ctype, featdict) - - '''(3) 轨迹显示与保存''' - illus = [None, None] - for CamerType, vts in event_tracks: - if len(vts.tracks)==0: continue - - if CamerType == 'front': - edgeline = cv2.imread("./tracking/shopcart/cart_tempt/board_ftmp_line.png") - - h, w = edgeline.shape[:2] - # nh, nw = h//2, w//2 - # edgeline = cv2.resize(edgeline, (nw, nh), interpolation=cv2.INTER_AREA) - - img_tracking = draw_all_trajectories(vts, edgeline, savepath_pipeline, CamerType, draw5p=True) - illus[0] = img_tracking - - plt = plot_frameID_y2(vts) - plt.savefig(os.path.join(savepath_pipeline, "front_y2.png")) - - if CamerType == 'back': - edgeline = cv2.imread("./tracking/shopcart/cart_tempt/edgeline.png") - - h, w = edgeline.shape[:2] - # nh, nw = h//2, w//2 - # edgeline = cv2.resize(edgeline, (nw, nh), interpolation=cv2.INTER_AREA) - - img_tracking = draw_all_trajectories(vts, edgeline, savepath_pipeline, CamerType, draw5p=True) - illus[1] = img_tracking - illus = [im for im in illus if im is not None] - if len(illus): - img_cat = np.concatenate(illus, axis = 1) - if len(illus)==2: - H, W = img_cat.shape[:2] - cv2.line(img_cat, (int(W/2), 0), (int(W/2), int(H)), (128, 128, 255), 3) - - trajpath = os.path.join(savepath_pipeline, "trajectory.png") - cv2.imwrite(trajpath, img_cat) + # 绘制并保存轨迹图 + show_result(event_tracks, yrtDict, savepath_pipe) + + def execute_pipeline(evtdir = r"D:\datasets\ym\后台数据\unzip", - source_type = "video", # video, image, + DataType = "raw", # raw, pkl save_path = r"D:\work\result_pipeline", + kk=1, + source_type = "video", # video, image, yolo_ver = "V10", # V10, V5 - weight_yolo_v5 = r'./ckpts/best_cls10_0906.pt' , weight_yolo_v10 = r'./ckpts/best_v10s_width0375_1205.pt', - k=0 + saveimages = True ): ''' 运行函数 pipeline(),遍历事件文件夹,每个文件夹是一个事件 ''' parmDict = {} - parmDict["SourceType"] = source_type + parmDict["DataType"] = DataType parmDict["savepath"] = save_path + parmDict["SourceType"] = source_type + parmDict["YoloVersion"] = yolo_ver if parmDict["YoloVersion"] == "V5": parmDict["weights"] = weight_yolo_v5 elif parmDict["YoloVersion"] == "V10": parmDict["weights"] = weight_yolo_v10 + + parmDict["saveimages"] = saveimages + evtdir = Path(evtdir) errEvents = [] + k = 0 for item in evtdir.iterdir(): if item.is_dir(): - item = evtdir/Path("20250310-175352-741") + # item = evtdir/Path("20241212-171505-f0afe929-fdfe-4efa-94d0-2fa748d65fbb_6907992518930") parmDict["eventpath"] = item pipeline(**parmDict) + # try: # pipeline(**parmDict) # except Exception as e: # errEvents.append(str(item)) + k+=1 - if k==1: + if kk is not None and k==kk: break errfile = os.path.join(parmDict["savepath"], 'error_events.txt') @@ -329,12 +364,20 @@ def execute_pipeline(evtdir = r"D:\datasets\ym\后台数据\unzip", f.write(line + '\n') if __name__ == "__main__": - execute_pipeline() + datapath = r'/home/wqg/dataset/test_dataset/base_dataset/single_event/source/' + savepath = r'/home/wqg/dataset/pipeline/test_result/single_event_V10' + + execute_pipeline(evtdir = datapath, + DataType = "raw", # raw, pkl + kk=1, + source_type = "video", # video, image, + save_path = savepath, + yolo_ver = "V10", # V10, V5 + weight_yolo_v5 = r'./ckpts/best_cls10_0906.pt' , + weight_yolo_v10 = r'./ckpts/best_v10s_width0375_1205.pt', + saveimages = False + ) - # spath_v10 = r"D:\work\result_pipeline_v10" - # spath_v5 = r"D:\work\result_pipeline_v5" - # execute_pipeline(save_path=spath_v10, yolo_ver="V10") - # execute_pipeline(save_path=spath_v5, yolo_ver="V5") diff --git a/realtime/__pycache__/event_time_specify.cpython-312.pyc b/realtime/__pycache__/event_time_specify.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0719985d581210d5ea93a7a0f2a3cc0b7a9db0bc GIT binary patch literal 13250 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 literal 0 HcmV?d00001 diff --git a/realtime/event_time_specify.py b/realtime/event_time_specify.py index 662bebb..a33531d 100644 --- a/realtime/event_time_specify.py +++ b/realtime/event_time_specify.py @@ -123,25 +123,28 @@ def devide_motion_state(tboxes, width): ''' - periods = [] - if len(tboxes) < width: - return periods - fboxes, frameTstamp = array2frame(tboxes) fnum = len(frameTstamp) - if fnum < width: return periods state = np.zeros((fnum, 2), dtype=np.int64) frameState = np.concatenate((frameTstamp, state), axis = 1).astype(np.int64) handState = np.concatenate((frameTstamp, state), axis = 1).astype(np.int64) + + + if fnum < width: + return frameState, handState + mtrackFid = {} handFid = {} '''frameState 标记由图像判断的购物车状态:0: 静止,1: 运动''' for idx in range(width, fnum+1): idx0 = idx-width + # if idx == 40: + # print("123") + lboxes = np.concatenate(fboxes[idx0:idx], axis = 0) md = MoveDetect(lboxes) md.classify() diff --git a/realtime/intrude_detect.py b/realtime/intrude_detect.py new file mode 100644 index 0000000..d9561b1 --- /dev/null +++ b/realtime/intrude_detect.py @@ -0,0 +1,420 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Tue Apr 8 10:07:17 2025 + +@author: wqg +""" + +import csv +import os +import platform +import sys +import pickle +import cv2 +import numpy as np +from pathlib import Path +import matplotlib.pyplot as plt +import matplotlib.pyplot as plt +from typing import List, Tuple +from scipy.spatial.distance import cdist +from scipy.spatial import ConvexHull +from shapely.geometry import Point, Polygon + +##################################################### for method: run_yrt() +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + +from track_reid import yolov10_resnet_tracker +from event_time_specify import devide_motion_state + + +def cross(o: Tuple[float, float], a: Tuple[float, float], b: Tuple[float, float]) -> float: + """ 计算向量 OA × OB 的叉积 """ + return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]) + +def compute_convex_hull(points: List[Tuple[float, float]]) -> List[Tuple[float, float]]: + """ 使用 Andrew's Monotone Chain 算法求二维点集的凸包 """ + points = sorted(set(points)) # 排序并去重 + if len(points) <= 1: + return points + + lower = [] + for p in points: + while len(lower) >= 2 and cross(lower[-2], lower[-1], p) <= 0: + lower.pop() + lower.append(p) + + upper = [] + for p in reversed(points): + while len(upper) >= 2 and cross(upper[-2], upper[-1], p) <= 0: + upper.pop() + upper.append(p) + + # 去掉重复的连接点 + return lower[:-1] + upper[:-1] + +def is_point_in_convex_hull(point: Tuple[float, float], hull: List[Tuple[float, float]]) -> bool: + """ 判断一个点是否在凸包(含边界)内 """ + n = len(hull) + if n < 3: + # 对于点或线段,直接判断是否共线或在线段上 + if n == 1: + return point == hull[0] + if n == 2: + a, b = hull + return abs(cross(a, b, point)) < 1e-10 and min(a[0], b[0]) <= point[0] <= max(a[0], b[0]) and min(a[1], b[1]) <= point[1] <= max(a[1], b[1]) + return False + + for i in range(n): + a = hull[i] + b = hull[(i + 1) % n] + if cross(a, b, point) < -1e-10: # 必须全部在左边或边上 + return False + return True + + + +def plot_convex_hull(points: List[Tuple[float, float]], hull: List[Tuple[float, float]], test_points: List[Tuple[float, float]] = None): + x_all, y_all = zip(*points) + fig, ax = plt.subplots() + + ax.set_xlim(0, 1024) + ax.set_ylim(1280, 0) + + ax.plot(x_all, y_all, 'o', label='Points') + + # 凸包闭环线 + hull_loop = hull + [hull[0]] + hx, hy = zip(*hull_loop) + ax.plot(hx, hy, 'r-', linewidth=2, label='Convex Hull') + + # 如果有测试点 + if test_points: + for pt in test_points: + color = 'green' if is_point_in_convex_hull(pt, hull) else 'black' + ax.plot(pt[0], pt[1], 's', color=color, markersize=8) + ax.text(pt[0] + 0.05, pt[1], f'{pt}', fontsize=9) + + ax.legend() + ax.grid(True) + plt.title("Convex Hull Visualization") + plt.show() + + +def convex_scipy(): + points = np.array([ + [0, 0], + [2, 0], + [1, 1], + [2, 2], + [0, 2], + [1, 0.5]]) + hull = ConvexHull(points) + + # 凸包顶点的索引 + print("凸包顶点索引:{}".format(hull.vertices)) + print("凸包顶点坐标:") + for i in hull.vertices: + print(points[i]) + + + # 将凸包坐标构造成 Polygon + hull_points = points[hull.vertices] + polygon = Polygon(hull_points) + + # 判断一个点是否在凸包内 + p = Point(1, 1) # 示例点 + print("是否在凸包内:", polygon.contains(p)) # True or False + + +def test_convex(): + # 测试数据 + sample_points = [(0, 0), (1, 1), (2, 2), (2, 0), (0, 2), (1, 0.5)] + convex_hull = compute_convex_hull(sample_points) + + # 测试点在凸包内 + test_point_inside = (1, 1) + test_point_outside = (3, 3) + test_point_on_edge = (1, 0) + + inside = is_point_in_convex_hull(test_point_inside, convex_hull) + outside = is_point_in_convex_hull(test_point_outside, convex_hull) + on_edge = is_point_in_convex_hull(test_point_on_edge, convex_hull) + + convex_hull, inside, outside, on_edge + + # 展示图像 + plot_convex_hull(sample_points, convex_hull, [test_point_inside, test_point_outside, test_point_on_edge]) + +def array2frame(tboxes): + "tboxes: [x1, y1, x2, y2, track_id, score, cls, frame_index, box_index]" + idx = np.where(tboxes[:, 6] != 0)[0] + bboxes = tboxes[idx, :] + frameID = np.sort(np.unique(bboxes[:, 7].astype(int))) + fboxes = [] + for fid in frameID: + idx = np.where(bboxes[:, 7] == fid)[0] + box = bboxes[idx, :] + fboxes.append(box) + return fboxes + +def convex_based(tboxes, width, TH=40): + fboxes = array2frame(tboxes) + fnum = len(fboxes) + + fids = np.array([i+1 for i in range(fnum)])[:, np.newaxis] + state = np.zeros((fnum, 1), dtype=np.int64) + frameState = np.concatenate((fids, state), axis = 1).astype(np.int64) + if fnum < width: + return frameState + + for idx1 in range(width, fnum+1): + idx0 = idx1 - width + idx = idx1 - width//2 - 1 + + iboxes = fboxes[:idx] + cboxes = fboxes[idx][:, 0:4] + + cur_xy = np.zeros((len(cboxes), 2)) + cur_xy[:, 0] = (fboxes[idx][:, 0]+fboxes[idx][:, 2])/2 + cur_xy[:, 1] = (fboxes[idx][:, 1]+fboxes[idx][:, 3])/2 + for i in range(width//2): + x1, y1, x2, y2 = iboxes[i][:, 0], iboxes[i][:, 1], iboxes[i][:, 2], iboxes[i][:, 3] + + boxes = np.array([(x1, y1), (x1, y2), (x2, y1), (x2, y2)]).transpose(0, 2, 1).reshape(-1, 2) + box1 = [(x, y) for x, y in boxes] + convex_hull = compute_convex_hull(box1) + + for pt in cur_xy: + inside = is_point_in_convex_hull(pt, convex_hull) + + if not inside: + break + if not inside: + break + + # Based on the distance between the four corners of the current frame boxes + # and adjacent frame boxes + iboxes = fboxes[idx0:idx] + fboxes[idx+1:idx1] + cboxes = fboxes[idx][:, 0:4] + cx1, cy1, cx2, cy2 = cboxes[:, 0], cboxes[:, 1], cboxes[:, 2], cboxes[:, 3] + cxy = np.array([(cx1, cy1), (cx1, cy2), (cx2, cy1), (cx2, cy2)]).transpose(0, 2, 1).reshape(-1, 2) + + iiboxes = np.concatenate(iboxes, axis=0) + ix1, iy1, ix2, iy2 = iiboxes[:, 0], iiboxes[:, 1], iiboxes[:, 2], iiboxes[:, 3] + ixy = np.array([(ix1, iy1), (ix1, iy2), (ix2, iy1), (ix2, iy2)]).transpose(0, 2, 1).reshape(-1, 2) + + Dist = cdist(cxy, ixy).round(2) + max_dist = np.max(np.min(Dist, axis=1)) + if max_dist > TH and not inside: + frameState[idx, 1] = 1 + # plot_convex_hull(boxes, convex_hull, [pt]) + frameState[idx, 1] = 1 + + return frameState + + +def single_point(tboxes, width, TH=60): + """width: window width, >=2""" + + + fboxes = array2frame(tboxes) + fnum = len(fboxes) + + fids = np.array([i+1 for i in range(fnum)])[:, np.newaxis] + state = np.zeros((fnum, 1), dtype=np.int64) + frameState = np.concatenate((fids, state), axis = 1).astype(np.int64) + + + if fnum < width: + return frameState + + for idx1 in range(width, fnum+1): + idx0 = idx1 - width + idx = idx1 - width//2 - 1 + + iboxe1 = fboxes[idx0:idx] + iboxe2 = fboxes[idx+1:idx1] + iboxes = fboxes[idx0:idx] + fboxes[idx+1:idx1] + + cboxes = fboxes[idx][:, 0:4] + cur_xy = np.zeros((len(cboxes), 2)) + cur_xy[:, 0] = (fboxes[idx][:, 0]+fboxes[idx][:, 2])/2 + cur_xy[:, 1] = (fboxes[idx][:, 1]+fboxes[idx][:, 3])/2 + Dist = np.empty((len(cboxes), 0)) + for i in range(width-1): + boxes = iboxes[i][:, 0:4] + + box_xy = np.zeros((len(boxes), 2)) + box_xy[:, 0] = (boxes[:, 0]+boxes[:, 2])/2 + box_xy[:, 1] = (boxes[:, 1]+boxes[:, 3])/2 + dist2 = cdist(cur_xy, box_xy).round(2) + + Dist = np.concatenate((Dist, dist2), axis=1) + + max_dist = np.max(np.min(Dist, axis=1)) + + if max_dist > TH: + frameState[idx, 1] = 1 + + return frameState + + + +def intrude(): + pkpath = Path("/home/wqg/dataset/small-goods/pkfiles") + savepath = Path("/home/wqg/dataset/small-goods/illustration_convex") + + if not savepath.exists(): + savepath.mkdir(parents=True, exist_ok=True) + + err_trail, err_single, err_all = [], [], [] + num = 0 + for pth in pkpath.iterdir(): + # item = r"69042386_20250407-145737_front_returnGood_b82d28427666_15_17700000001.pickle" + # pth = pkpath/item + + with open(str(pth), 'rb') as f: + yrt = pickle.load(f) + + evtname = pth.stem + + bboxes = [] + trackerboxes = np.empty((0, 10), dtype=np.float64) + for frameDict in yrt: + boxes = frameDict["bboxes"] + tboxes = frameDict["tboxes"] + tboxes = np.concatenate((tboxes, tboxes[:,7][:, None]), axis=1) + + bboxes.append(boxes) + + trackerboxes = np.concatenate((trackerboxes, np.array(tboxes)), axis=0) + + '''single-points based for intrusion detection''' + # wd =5 + # fstate1 = single_point(trackerboxes, wd) + + '''convex-based ''' + width = 5 + fstate = convex_based(trackerboxes, width, TH=60) + + # fstate = np.zeros(fstate1.shape) + # fstate[:, 0] = fstate1[:, 0] + # fstate[:, 1] = fstate1[:, 1] * fstate2[:, 1] + + '''trajectory based for intrusion detection + period: 0 1 2 3 + fid timestamp(fid) 基于滑动窗的tid扩展 滑动窗覆盖的运动区间 + ''' + win_width = 12 + period, handState = devide_motion_state(trackerboxes, win_width) + + num += 1 + if np.all(period[:,2:4]==0): + err_trail.append(evtname) + if np.all(fstate[:,1]==0): + err_single.append(evtname) + if np.all(period[:,2:4]==0) and np.all(fstate[:,1]==0): + err_all.append(evtname) + + fig, (ax1, ax2) = plt.subplots(2, 1) + ax1.plot(period[:, 1], period[:, 2], 'bo-', linewidth=1, markersize=4) + ax1.plot(period[:, 1], period[:, 3], 'rx-', linewidth=1, markersize=8) + + ax2.plot(fstate[:, 0], fstate[:, 1], 'rx-', linewidth=1, markersize=8) + plt.savefig(os.path.join(str(savepath), f"{evtname}.png")) + + + plt.close() + # if num==1: + # break + + rate_trail = 1 - len(err_trail)/num + rate_single = 1 - len(err_single)/num + rate_all = 1 - len(err_all)/num + + print(f"rate_trail: {rate_trail}") + print(f"rate_single: {rate_single}") + print(f"rate_all: {rate_all}") + + txtpath = savepath.parents[0] / "error.txt" + with open(str(txtpath), "w") as f: + f.write(f"rate_trail: {rate_trail}" + "\n") + f.write(f"rate_single: {rate_single}" + "\n") + f.write(f"rate_all: {rate_all}" + "\n") + + f.write("\n" + "err_trail" + "\n") + for line in err_trail: + f.write(line + "\n") + + f.write("\n" + "err_single" + "\n") + for line in err_single: + f.write(line + "\n") + + f.write("\n" + "err_all" + "\n") + for line in err_all: + f.write(line + "\n") + print("Done!") + + + + +def run_yrt(): + datapath = Path("/home/wqg/dataset/small-goods/videos/") + savepath = Path("/home/wqg/dataset/small-goods/result/") + pkpath = Path("/home/wqg/dataset/small-goods/pkfiles/") + + if not savepath.exists(): + savepath.mkdir(parents=True, exist_ok=True) + if not pkpath.exists(): + pkpath.mkdir(parents=True, exist_ok=True) + + + optdict = {} + optdict["weights"] = ROOT / 'ckpts/best_v10s_width0375_1205.pt' + optdict["is_save_img"] = False + optdict["is_save_video"] = True + + k = 0 + for pth in datapath.iterdir(): + item = "69042386_20250407-145819_back_returnGood_b82d28427666_15_17700000001.mp4" + pth = pth.parents[0] /item + + optdict["source"] = pth + optdict["save_dir"] = savepath + + # try: + yrtOut = yolov10_resnet_tracker(**optdict) + + pkpath_ = pkpath / f"{Path(pth).stem}.pickle" + with open(str(pkpath_), 'wb') as f: + pickle.dump(yrtOut, f) + + k += 1 + if k==1: + break + # except Exception as e: + # print("abc") + + + +if __name__ == '__main__': + # run_yrt() + + intrude() + + # test_convex() + + + + + + + + + + + diff --git a/realtime/time_devide.py b/realtime/time_devide.py index 2daaed9..d30bb1f 100644 --- a/realtime/time_devide.py +++ b/realtime/time_devide.py @@ -19,7 +19,18 @@ from collections import OrderedDict from event_time_specify import devide_motion_state #, state_measure import sys -sys.path.append(r"D:\DetectTracking") + + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH + + + + + + from imgs_inference import run_yolo from tracking.utils.read_data import read_weight_sensor diff --git a/track_reid.py b/track_reid.py index 06d158f..9dd39ee 100644 --- a/track_reid.py +++ b/track_reid.py @@ -128,6 +128,8 @@ def init_trackers(tracker_yaml = None, bs=1): """ # tracker_yaml = r"./tracking/trackers/cfg/botsort.yaml" + tracker_yaml = str(tracker_yaml) + TRACKER_MAP = {'bytetrack': BYTETracker, 'botsort': BOTSORT} cfg = IterableSimpleNamespace(**yaml_load(tracker_yaml)) @@ -149,7 +151,7 @@ def yolov10_resnet_tracker( is_save_img = True, is_save_video = True, - tracker_yaml = "./tracking/trackers/cfg/botsort.yaml", + tracker_yaml = ROOT / "tracking/trackers/cfg/botsort.yaml", line_thickness=3, # bounding box thickness (pixels) hide_labels=False, # hide labels ): @@ -157,7 +159,7 @@ def yolov10_resnet_tracker( ## load a custom model model = YOLOv10(weights) - custom = {"conf": 0.25, "batch": 1, "save": False, "mode": "predict"} + custom = {"conf": 0.1, "batch": 1, "save": False, "mode": "predict"} kwargs = {"save": True, "imgsz": 640, "conf": 0.1} args = {**model.overrides, **custom, **kwargs} predictor = model.task_map[model.task]["predictor"](overrides=args, _callbacks=model.callbacks) @@ -294,7 +296,7 @@ def yolo_resnet_tracker( is_save_img = True, is_save_video = True, - tracker_yaml = "./tracking/trackers/cfg/botsort.yaml", + tracker_yaml = ROOT / "tracking/trackers/cfg/botsort.yaml", imgsz=(640, 640), # inference size (height, width) conf_thres=0.25, # confidence threshold iou_thres=0.45, # NMS IOU threshold @@ -359,6 +361,7 @@ def yolo_resnet_tracker( # Process predictions for i, det in enumerate(pred): # per image im0 = im0s.copy() + annotator = Annotator(im0.copy(), line_width=line_thickness, example=str(names)) s += '%gx%g ' % im.shape[2:] # print string if len(det): @@ -438,7 +441,7 @@ def yolo_resnet_tracker( if dataset.mode == 'image': imgpath = save_path_img + ".png" else: - imgpath = save_path_img + f"_{frameId}.png" + imgpath = save_path_img + f"_{frameId}.png" cv2.imwrite(Path(imgpath), im0) # if dataset.mode == 'video' and is_save_video: @@ -461,6 +464,7 @@ def yolo_resnet_tracker( else: # stream fps, w, h = 25, im0.shape[1], im0.shape[0] ## for image rotating in dataloader.LoadImages.__next__() + w, h = im0.shape[1], im0.shape[0] vdieo_path = str(Path(vdieo_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos @@ -484,7 +488,7 @@ def run( project=ROOT / 'runs/detect', # save results to project/name name='exp', # save results to project/name - tracker_yaml = "./tracking/trackers/cfg/botsort.yaml", + tracker_yaml = ROOT / "tracking/trackers/cfg/botsort.yaml", imgsz=(640, 640), # inference size (height, width) conf_thres=0.25, # confidence threshold iou_thres=0.45, # NMS IOU threshold diff --git a/tracking/__pycache__/__init__.cpython-312.pyc b/tracking/__pycache__/__init__.cpython-312.pyc index a4dc3276d975a55cc352e358bf28a1dc1b8933df..e1f826c301435b6d66565e7dfc025dd1f286abda 100644 GIT binary patch delta 20 acmeBU>|^9P&CAQh00i#A&(bIIGywoG5(OXt delta 20 acmeBU>|^9P&CAQh00gyei_#|YGywoF<^==* diff --git a/tracking/dotrack/__pycache__/__init__.cpython-312.pyc b/tracking/dotrack/__pycache__/__init__.cpython-312.pyc index de6758e8fb271031ebc5abd159fc80578fe43001..ab597cfa48da483283381b9e5ebb0ec1b1c9c6a0 100644 GIT binary patch delta 20 acmbQnIE|6#G%qg~0}!|eKTDs;(**!AN(DFo delta 20 acmbQnIE|6#G%qg~0}#}@ElQin(**!A9t9i# diff --git a/tracking/dotrack/__pycache__/dotracks.cpython-312.pyc b/tracking/dotrack/__pycache__/dotracks.cpython-312.pyc index 590e9b290a1203b8352185e2aa3fb8b6781d7ac7..e26f6df7fada66bb1962661f1e7a4012a1086ae9 100644 GIT binary patch delta 23 dcmX@!$aK7siRUygFBbz4xCcK=-^jDO0RUFC2X6oX delta 23 dcmX@!$aK7siRUygFBbz4D0nVP+sL!K0RU5(2KfL0 diff --git a/tracking/dotrack/__pycache__/dotracks_back.cpython-312.pyc b/tracking/dotrack/__pycache__/dotracks_back.cpython-312.pyc index 2c9dac56ce2ab577a83b108471185a1bc4c22479..25d448a9fb75d3322f1399467c8bb08185bf8a8d 100644 GIT binary patch delta 1475 zcmZuwU1%It6rQ^~JF}V1W|Pcjvwz8Mewt(^ZBnbnN^6>=G)=W_tOiR*>#*6Gth1Tf zUG8iuDK$S-NFEcfsEA1kzi~>zDuM+CLsj%a@Sd3j5_KNFIrp6J z{N8h4y?Eo9@TcLhz|imdAHNjdUJECD*U?&ESIlPylz@gbzsXs=!Xw7V=)6u&#oEY? zOpsFqT`0y#Q&3!B6VzL&r}nU3zm6al!{~ux+LLzUWrREa-%`x%=6Ukoh&z!HL#qmy zjaHM=1ad^<%w|he#DA4Yg00bM4Y|cd-QuG=A(W^dEz18*sKhj03!1G~T!~u=B|*dU zTAi7+Qc4P!L+!N+x`mKHM*Od& zBUE>#MJtcy@-vf|f<2(BM#-qEYDaC$|G5vv$j98#P8b-D0y(yaT+pjVDWAjD1GNqw zb9FqWoRgwhByWZXQ6sq-ewT}ZuSl*mJdKW%jfNhSCVw_`qhqzU$oGCU{IV!{luj&?oR2%($+M6n%Y z;7KyyWzZr2)U_XdR%_{AMYOwj_T5DFn59gEp@=V$`Q8I^3q4D$Bjn4tRH5Okwp*g( zw`VPU1dIVM(Iok*chDQ#VIuUU&|jpd?`t$b{_Z=NaA!OTMX+OLu3*CgX0utGCSy`h zYmkoaemzw!GMka;3j19|TnS?IjFP7D1=l0#t_@cWdt$8toLL(RJ^mMmvrW!+W8 zXF(bP7y@_;;4t|>?oOttXj4CC7`yuf=`lc-{3ees4D1}GHiuVLt(;d?Cs3NTDs$cy zWr5&cj^CcM9lk=}k7-O{=*$VK>a=0%)P<*)RyHr|wC~erP67?OpAyq{o8dLCHaM@z9GXDjwQ{cqlp&DMiqNU?nF(#P?=ev2%Fy{`}tW zd+&YU`{La7vm>`gMidUd%BlC)q^*$x{|mQOug(jO^-5#uNT=TK_!o!s{C9*T7%#p%nF4~>@@DS@B)x>0-T_^=ySA_EkSx z2p)S3+_8MS+cv0Q9o~ykIUxgNNzKs=yO5eAY4&#NLphJR8Fnmvh8$<_q^C)V-AvcW zlf$3W_XN^nUuM+^^E7*qosz?&7TH9uOg7lj+$GW+evtcJB6Do3SQ(oGGL;V`@1oJS z0?G6@`xceix5XK9knI-N8cP5O#I|Gi={%~k(eGPbGZ1{+RQJ)anCG#g7uXx67Adf= zN|&QE7ua)?PmpWF?&Ky9hyJ$jv}j>J^b81<(3kPYQyzZzIk?wQd+4C&{}&9C&Vpl! zoYf$}_S)tikR*s2&P?H=v+f!_DR5(B{-xbz4HrRbm)cD+6qjqNbIRWFf0*st|F zq{%*44;I21uV4}4Nyq4T_)0643N5i%V|x4_uy*%=c%Azpox3XDO=qtrDQ50xcN-H> z=#@qzDd2!V2GnDbzaRp8_Fv?{OrwlXIDDG)Mbs8iETFi7;xOBosTGT$dXUF0((rjD zF@$1_eKvDqfAf*4jt4PaH+yYe52WtE?Qcd`R7SuuvuDdhU~kP%reS1oDSg-`$6lop zo1Y!O3?{W;WI?Pwpco3|$U~_U49E=t?T6Qu$GO0@Z delta 21 bcmdnsu)%@nG%qg~0}v>9E=t?TqoM!+K&1sv diff --git a/tracking/dotrack/dotracks_back.py b/tracking/dotrack/dotracks_back.py index 93cb7ed..81bc54d 100644 --- a/tracking/dotrack/dotracks_back.py +++ b/tracking/dotrack/dotracks_back.py @@ -7,9 +7,19 @@ Created on Mon Mar 4 18:36:31 2024 import numpy as np import cv2 import copy -from tracking.utils.mergetrack import track_equal_track -from scipy.spatial.distance import cdist +import sys from pathlib import Path + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[2] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) + +from tracking.utils.mergetrack import track_equal_track + + +from scipy.spatial.distance import cdist + curpath = Path(__file__).resolve().parents[0] curpath = Path(curpath) parpath = curpath.parent diff --git a/tracking/trackers/__pycache__/__init__.cpython-312.pyc b/tracking/trackers/__pycache__/__init__.cpython-312.pyc index e01f8017f26f28a400a7e361e0c4ad6ab7230967..b32cfce441d3ddf60b18eacd3bef57c58ce2616b 100644 GIT binary patch delta 21 bcmX@fbdrhZG%qg~0}w<7KTF@pW6KBtKOY5$ delta 21 bcmX@fbdrhZG%qg~0}#}@ElS(SW6KBtK0gIm diff --git a/tracking/trackers/__pycache__/basetrack.cpython-312.pyc b/tracking/trackers/__pycache__/basetrack.cpython-312.pyc index d28ee0d1927a393cd7fe4b02f6c83eea93e1f4dd..6233e5e140308f919d4e14529f9b001cfd6e5f68 100644 GIT binary patch delta 21 bcmX>nc211vG%qg~0}w<7KTF@pnc211vG%qg~0}#}@ElS(SQapR|F>x10mdV@_`jaCiJQ(#RFOtw> zzRDpt`K`nb#>UOdBpI0`Vu1Q?ah7M6WW*PxW~SU?Pt8ltPf0DByj8lNv30Yn%xNZW zkeZ@I5Ro)lT7Dwq#La8vg_#)hCm&Q)w<-XM7lH^RWgu=5h)@O*#UMf(NN92vNrKoV zAfj}#l9IYu1(11*FEuwQJ|(lbq&Pk|u{gV^Y;wGk1>@q)Gn9fE8A~R=QPyTWvROjq z4ysfBt0gj?+?=Q`!zdLGGB6iJRDy_l5aA3WdM8iUFkoe6wfLko`HaSWwp%R8`FUxR WH)tjZrZO@bc4U8L0MSK?K*a#)R9g@L delta 431 zcmdlOyfB3CG%qg~0}v>9E=oHmw~>!aoN>)$N%3r^8pg>7SwwV-L`%3q@*q&c1ECoh zRx?6aH4O3WFtJL;$t~h8j2x3sitEeY;w;ZB$%rpX%}gl*>A%I2oS&C=i#;_jIX@+} zXz~wn4@Qs4juLvZS2*MzaP#-ub=iI4V35&TqjFhVzr&^1=L07LkJRKMi5-mfo3$kw znfT&?#uUYXh&UiI*+sgav3c_q>C;TyNHUXG$xUSJ-)ti<%*0qQIY3d}st}~32t*($ z196K%gffUI0TJ3jLX)#d62vYA5oMD%DyoZB0-3k?Qgf5yQ!GGJxnJMW84Ed|GSI diff --git a/tracking/trackers/__pycache__/byte_tracker.cpython-312.pyc b/tracking/trackers/__pycache__/byte_tracker.cpython-312.pyc index 2e7389240fce65910b1d364094342fe83a11c333..730b2d53e5086664fb880ea37271d2454520d698 100644 GIT binary patch delta 23 dcmaEGgz>==geL$M$G%qg~0}w<7KTF@pvxOG`LT3gl delta 21 bcmX>geL$M$G%qg~0}#}?ElS(SvxOG`L5~Ie diff --git a/tracking/trackers/utils/__pycache__/__init__.cpython-312.pyc b/tracking/trackers/utils/__pycache__/__init__.cpython-312.pyc index 7c06304fd3b061ad4a303c53fda81ad74d21313a..e25dfd0b0599148d0fdc1625a2f0b585fe92379c 100644 GIT binary patch delta 20 acmbQsIG2&@loFBbz4WCcG<-^g>!6#!cE2Z{gy delta 23 dcmccA&3LJsk>@loFBbz4)VVE6+sJdw6#!YA2TT9} diff --git a/tracking/trackers/utils/__pycache__/matching.cpython-312.pyc b/tracking/trackers/utils/__pycache__/matching.cpython-312.pyc index 096ec4c84a0de318e75c8e67ed3193f43f83c70e..4eb6ef543f358c907d3bf614a81b0b3424c41a4e 100644 GIT binary patch delta 21 bcmX>Vc`B0UG%qg~0}x~dKTF@pvrh*AP2L9c delta 21 bcmX>Vc`B0UG%qg~0}#}?ElS(Svrh*AOoj%v diff --git a/tracking/tracking_pipeline.py b/tracking/tracking_pipeline.py index 4e2b9d7..54354b2 100644 --- a/tracking/tracking_pipeline.py +++ b/tracking/tracking_pipeline.py @@ -11,170 +11,222 @@ import pickle import numpy as np from pathlib import Path from scipy.spatial.distance import cdist +import copy -from .dotrack.dotracks_back import doBackTracks -from .dotrack.dotracks_front import doFrontTracks -from .utils.drawtracks import plot_frameID_y2, draw_all_trajectories -from .utils.read_data import read_similar +from dotrack.dotracks_back import doBackTracks +from dotrack.dotracks_front import doFrontTracks +from utils.drawtracks import plot_frameID_y2, draw_all_trajectories +from utils.read_data import read_similar +def get_trail(ShoppingDict, ppath): + + evtname = ShoppingDict["eventName"] + + back_yrt = ShoppingDict["backCamera"]["yoloResnetTracker"] + front_yrt = ShoppingDict["frontCamera"]["yoloResnetTracker"] + + back_vts = ShoppingDict["frontCamera"]["tracking"] + front_vts = ShoppingDict["backCamera"]["tracking"] + + + event_tracks = [("back", back_yrt, back_vts), ("front", front_yrt, front_vts)] + + + savepath = ppath / "alltrail" + if not savepath.exists(): + savepath.mkdir() + + savepath = str(savepath) + evtime = evtname[:15] + + illus = [None, None] + for camera_type, yrtOut, vts in event_tracks: + if len(vts.Residual)==1: continue + + if camera_type == 'front': + edgeline = cv2.imread("./shopcart/cart_tempt/board_ftmp_line.png") + + img_tracking = draw_all_trajectories(vts, edgeline, savepath, camera_type, draw5p=False) + illus[0] = img_tracking - -class CameraEvent_: - def __init__(self): - self.cameraType = '', # "front", "back" - self.videoPath = '', - self.imagePaths = [], - self.yoloResnetTracker =[], - self.tracking = None, - -class ShoppingEvent_: - def __init__(self): - self.eventPath = '' - self.eventName = '' - self.barcode = '' - self.eventType = '', # "input", "output", "other" - self.frontCamera = None - self.backCamera = None - self.one2n = [] + plt = plot_frameID_y2(vts) + plt.savefig(os.path.join(savepath, f"{evtime}_front.png")) + + if camera_type == 'back': + edgeline = cv2.imread("./shopcart/cart_tempt/edgeline.png") + + img_tracking = draw_all_trajectories(vts, edgeline, savepath, camera_type, draw5p=False) + illus[1] = img_tracking + + illus = [im for im in illus if im is not None] + if len(illus): + img_cat = np.concatenate(illus, axis = 1) + if len(illus)==2: + H, W = img_cat.shape[:2] + cv2.line(img_cat, (int(W/2), 0), (int(W/2), int(H)), (128, 128, 255), 3) + + trajpath = os.path.join(savepath, f"{evtime}.png") + cv2.imwrite(trajpath, img_cat) + + return evtime + + return None + + -def main(): + + + +def track_opt(ShoppingDict, ppath): ''' 将一个对象读取,修改其中一个属性 ''' + evtname = ShoppingDict["eventName"] + shopping = copy.deepcopy(ShoppingDict) - evt_pkfile = 'path.pickle' - with open(evt_pkfile, 'rb') as f: - ShoppingDict = pickle.load(f) - - savepath = "" - + ## only need to init item: tracking for each Camera + shopping["frontCamera"]["tracking"] = [] + shopping["backCamera"]["tracking"] = [] + back_camera = ShoppingDict["backCamera"]["cameraType"] back_yrt = ShoppingDict["backCamera"]["yoloResnetTracker"] front_camera = ShoppingDict["frontCamera"]["cameraType"] front_yrt = ShoppingDict["frontCamera"]["yoloResnetTracker"] yrts = [(back_camera, back_yrt), (front_camera, front_yrt)] - - shopping_event = ShoppingEvent_() - shopping_event.eventPath = ShoppingDict["eventPath"] - shopping_event.eventName = ShoppingDict["eventName"] - shopping_event.barcode = ShoppingDict["barcode"] - - yrtDict = {} event_tracks = [] - for camera_type, yrtOut in yrts: - ''' - inputs: - yrtOut - camera_type - outputs: - CameraEvent - ''' - - camera_event = CameraEvent_() - - - - '''================= 4. tracking =================''' + errtrail = '' + for camera_type, yrtOut in yrts: + '''================= 1. tracking =================''' '''(1) 生成用于 tracking 模块的 boxes、feats''' - bboxes = np.empty((0, 6), dtype=np.float64) + # bboxes = np.empty((0, 6), dtype=np.float64) trackerboxes = np.empty((0, 9), dtype=np.float64) trackefeats = {} for frameDict in yrtOut: tboxes = frameDict["tboxes"] ffeats = frameDict["feats"] - boxes = frameDict["bboxes"] - bboxes = np.concatenate((bboxes, np.array(boxes)), axis=0) + # boxes = frameDict["bboxes"] + # bboxes = np.concatenate((bboxes, np.array(boxes)), axis=0) trackerboxes = np.concatenate((trackerboxes, np.array(tboxes)), axis=0) for i in range(len(tboxes)): fid, bid = int(tboxes[i, 7]), int(tboxes[i, 8]) trackefeats.update({f"{fid}_{bid}": ffeats[f"{fid}_{bid}"]}) - '''(2) tracking, 后摄''' - if CameraEvent["cameraType"] == "back": + if camera_type == "back": vts = doBackTracks(trackerboxes, trackefeats) vts.classify() - event_tracks.append(("back", vts)) + shopping["backCamera"]["tracking"] = vts - - - camera_event.camera_type = camera_type - camera_event.yoloResnetTracker = yrtOut - camera_event.tracking = vts - camera_event.videoPath = ShoppingDict["backCamera"]["videoPath"] - camera_event.imagePaths = ShoppingDict["backCamera"]["imagePaths"] - shopping_event.backCamera = camera_event - - yrtDict["backyrt"] = yrtOut - - '''(2) tracking, 前摄''' - if CameraEvent["cameraType"] == "front": + if len(vts.Residual)!=1: + errtrail = evtname + + '''(3) tracking, 前摄''' + if camera_type == "front": vts = doFrontTracks(trackerboxes, trackefeats) vts.classify() - event_tracks.append(("front", vts)) + shopping["frontCamera"]["tracking"] = vts - camera_event.camera_type = camera_type - camera_event.yoloResnetTracker = yrtOut - camera_event.tracking = vts - camera_event.videoPath = ShoppingDict["frontCamera"]["videoPath"] - camera_event.imagePaths = ShoppingDict["frontCamera"]["imagePaths"] - shopping_event.backCamera = camera_event - - yrtDict["frontyrt"] = yrtOut + if len(vts.Residual)!=1: + errtrail = evtname + + event_tracks.append((camera_type, yrtOut, vts)) + + pckpath = ppath / "track_optim" + if not pckpath.exists(): + pckpath.mkdir() + + fpath = pckpath / "{}_new.pickle".format(evtname) + with open(str(fpath), 'wb') as f: + pickle.dump(shopping, f) + - name = Path(evt_pkfile).stem - pf_path = os.path.join(savepath, name+"_new.pickle") - with open(str(pf_path), 'wb') as f: - pickle.dump(shopping_event, f) - - + savepath = ppath / "yolos_tracking" / evtname illus = [None, None] - for CamerType, vts in event_tracks: + for camera_type, yrtOut, vts in event_tracks: if len(vts.tracks)==0: continue - if CamerType == 'front': - edgeline = cv2.imread("./tracking/shopcart/cart_tempt/board_ftmp_line.png") + if camera_type == 'front': + edgeline = cv2.imread("./shopcart/cart_tempt/board_ftmp_line.png") - h, w = edgeline.shape[:2] - # nh, nw = h//2, w//2 - # edgeline = cv2.resize(edgeline, (nw, nh), interpolation=cv2.INTER_AREA) - - img_tracking = draw_all_trajectories(vts, edgeline, savepath_pipeline, CamerType, draw5p=True) + img_tracking = draw_all_trajectories(vts, edgeline, savepath, camera_type, draw5p=False) illus[0] = img_tracking plt = plot_frameID_y2(vts) - plt.savefig(os.path.join(savepath_pipeline, "front_y2.png")) + plt.savefig(os.path.join(savepath, "front_y2_new.png")) - if CamerType == 'back': - edgeline = cv2.imread("./tracking/shopcart/cart_tempt/edgeline.png") - - h, w = edgeline.shape[:2] - # nh, nw = h//2, w//2 - # edgeline = cv2.resize(edgeline, (nw, nh), interpolation=cv2.INTER_AREA) - - img_tracking = draw_all_trajectories(vts, edgeline, savepath_pipeline, CamerType, draw5p=True) + if camera_type == 'back': + edgeline = cv2.imread("./shopcart/cart_tempt/edgeline.png") + + img_tracking = draw_all_trajectories(vts, edgeline, savepath, camera_type, draw5p=False) illus[1] = img_tracking + + illus = [im for im in illus if im is not None] + if len(illus): + img_cat = np.concatenate(illus, axis = 1) + if len(illus)==2: + H, W = img_cat.shape[:2] + cv2.line(img_cat, (int(W/2), 0), (int(W/2), int(H)), (128, 128, 255), 3) + + trajpath = os.path.join(savepath, "trajectory_new.png") + cv2.imwrite(trajpath, img_cat) + + return errtrail - - - - - - - +def main(): + # evttypes = ["single_event_V10", "single_event_V5", "performence_V10", "performence_V5"] + evttypes = ["single_event_V10"] + + k = 0 + error_trail = [] + for evttype in evttypes: + ppath = Path("/home/wqg/dataset/pipeline/yrt/{}".format(evttype)) + + pkpath = ppath / "shopping_pkl" + for fp in pkpath.iterdir(): + # fp = pkpath / "{}.pickle".format("20250305-152917-635_6970209860221_6970209860221") + print(fp) + + if fp.suffix != '.pickle': continue + with open(str(fp), 'rb') as f: + ShoppingDict = pickle.load(f) + + # errtrail = track_opt(ShoppingDict, ppath) + # error_trail.append(errtrail) + + errtrail = get_trail(ShoppingDict, ppath) + if errtrail is not None: + error_trail.append(errtrail) + + # k+=1 + # if k==100: + # break + + errfile = ppath / 'error_trail.txt' + with open(errfile, 'w', encoding='utf-8') as f: + for line in error_trail: + f.write(line + '\n') + + if __name__ == "__main__": - main() \ No newline at end of file + main() + + + + + + + \ No newline at end of file diff --git a/tracking/utils/__pycache__/__init__.cpython-312.pyc b/tracking/utils/__pycache__/__init__.cpython-312.pyc index 6600dc8053cc0ec05c36f8ac03282c121d513117..4a505fa6832f3d9310df020bc94a1b85caac3c75 100644 GIT binary patch delta 21 bcmbQrJe8T}G%qg~0}x~dKTF@p)5!<`I6Vb@ delta 21 bcmbQrJe8T}G%qg~0}#}?ElS(S)5!<`Hsu9B diff --git a/tracking/utils/__pycache__/annotator.cpython-312.pyc b/tracking/utils/__pycache__/annotator.cpython-312.pyc index 64a433e25a7de93515c6ce7464700333e75aae76..eb7fb91d4b9caa8c810d89ad615322e02e2e73f0 100644 GIT binary patch delta 21 bcmZpdXqVtQ&CAQh00ddV&(b&Y{N@G#IvEBB delta 21 bcmZpdXqVtQ&CAQh00au2i_$jo{N@G#HRc6w diff --git a/tracking/utils/__pycache__/drawtracks.cpython-312.pyc b/tracking/utils/__pycache__/drawtracks.cpython-312.pyc index 3fd62f6191f732811b6b97475b0450d46fd8b8a3..47a77d0c50dd7d163f9f4620493c46e13a2cb156 100644 GIT binary patch delta 23 dcmeBbW$bEY2BQD~ delta 23 dcmeBbW$bEYFMKlHX delta 21 bcmcaCb6JMxG%qg~0}#}?ElS(SFL(~Ph diff --git a/tracking/utils/__pycache__/read_data.cpython-312.pyc b/tracking/utils/__pycache__/read_data.cpython-312.pyc index 07b0c70c60d94e9b6065ecaed7a89e10b0992afd..ddd90b66546517c4713aa9201b0218219987a364 100644 GIT binary patch delta 23 dcmcceit)-TMxN8Wyj%=GkQMwaeIt)YDFA7-2mSy6 delta 23 dcmcceit)-TMxN8Wyj%=Gpy0VEZ6l9IDF9`G2W0>N diff --git a/tracking/utils/__pycache__/showtrack.cpython-312.pyc b/tracking/utils/__pycache__/showtrack.cpython-312.pyc index af4be9515eabd704a44cc991a335fd9fcc974f8c..85a1fbf07238476ff8a6fdf494c47f24dc7bdf32 100644 GIT binary patch delta 21 bcmX?}d_0-wG%qg~0}x~fKTF@pv)d2=PU!~( delta 21 bcmX?}d_0-wG%qg~0}#}?ElS(Sv)d2=O^F7@ diff --git a/ultralytics/__pycache__/__init__.cpython-312.pyc b/ultralytics/__pycache__/__init__.cpython-312.pyc index aebdf610dc1e6c9d118b10439197a4f39443d364..c4f39ae47add16916c568248a42e3c7bb2add0cd 100644 GIT binary patch delta 50 zcmZo+Yi8p<&CAQh00h~=&o*+`Gf5igXXNLm>X#R$>!+laq$Zb?6eT8SXXd3(Uc!_B E0A`91A^-pY delta 51 zcmZo>YhmL)&CAQh00bA}A8q8WXOc41&&bbB)h{nh*H1}JEyznP(XY(U$uBcBn7o)N F0RV$?5OM$j diff --git a/ultralytics/cfg/__pycache__/__init__.cpython-312.pyc b/ultralytics/cfg/__pycache__/__init__.cpython-312.pyc index bbf01000ff783dfed90eef59194545ea0b8c27e8..b9a6a30a356e9b3a518e00a7fbad65a5970b2bd0 100644 GIT binary patch delta 53 zcmdmffpOafM()$Ryj%=GkRAMNBllK*NfZ5y{M=Oi^1^iel+=>c6pOK%Ns$X81uAh=xlA2snQk0mSotc+DxsEX$ E0Dv_RZ~y=R delta 51 zcmcb@e3hB|G%qg~0}xz@f3%T1l2OV`KO;XkRlmG2T|Xr?wIDCGM87gWC%??lU~(;E FH~^gk5WD~Y diff --git a/ultralytics/data/__pycache__/augment.cpython-312.pyc b/ultralytics/data/__pycache__/augment.cpython-312.pyc index 0f50d861cd668bd5c58c5883d5268f283d84ba54..4a02210e9f16117b0b7ab76527ef11f312e52e76 100644 GIT binary patch delta 57 zcmeB}&eA@eh5IxwFBbz4c+jq%VlM()$Ryj%=GkRSYPBlkLHNi+S7{M=Oi^1^iel+=>c!jq&g_M()$Ryj%=Ga3TKDM(%aYQs(*@`MIh3<%Q|`DXFOid8sA(mH9dOWrhZu JFEJOm0|4@k67K*2 diff --git a/ultralytics/data/__pycache__/dataset.cpython-312.pyc b/ultralytics/data/__pycache__/dataset.cpython-312.pyc index c3334d900f8d261673a6778533bf7b7ca6a993aa..115fc378abec2326cef23cdb98113c69b1bf2008 100644 GIT binary patch delta 53 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 L|L|bLf&9M#TEm2} diff --git a/ultralytics/data/__pycache__/utils.cpython-312.pyc b/ultralytics/data/__pycache__/utils.cpython-312.pyc index d6e9800803b3f470b26a90864400e14408922b61..b9326f38bb4b99a6ef3a80a33e562e2588f49ef8 100644 GIT binary patch delta 53 zcmZ2_oN38%ChpU`yj%=GkRSYPBlmY!NhAG?{M=Oi^1^iel+=>c9Q1Ov+wABR@A)zq~MAKP5G_ATPBc6X*Z{ diff --git a/ultralytics/data/explorer/__pycache__/utils.cpython-312.pyc b/ultralytics/data/explorer/__pycache__/utils.cpython-312.pyc index 1303eee10fbdd0f0d8e394f6e2170d69f5e64676..7806bbf23f02be84c688f532a62b44b6d9041bc3 100644 GIT binary patch delta 51 zcmaD6_&kvNG%qg~0}$i~KikOd$Si5CpOK%Ns$X81uAh=xlA2snQk0mSotc-uIgPnV F6#%q~5qtmu delta 52 zcmaDJ_#%+|G%qg~0}xz@f3%U?ky*+{KO;XkRlmG2T|Xr?wIDCGM87gWC%??lU~?*S GlPUnxRuRYm diff --git a/ultralytics/data/loaders.py b/ultralytics/data/loaders.py index 4b89770..7d82e77 100644 --- a/ultralytics/data/loaders.py +++ b/ultralytics/data/loaders.py @@ -19,6 +19,8 @@ from ultralytics.data.utils import IMG_FORMATS, VID_FORMATS from ultralytics.utils import LOGGER, is_colab, is_kaggle, ops from ultralytics.utils.checks import check_requirements +import subprocess +import json @dataclass class SourceTypes: @@ -340,6 +342,12 @@ class LoadImagesAndVideos: if success: success, im0 = self.cap.retrieve() + ##====================== + '''判断视频是否含旋转信息''' + rotation = self.get_rotation(path) + if rotation == 270: + im0 = cv2.rotate(im0, cv2.ROTATE_90_COUNTERCLOCKWISE) + ###====================== if success: self.frame += 1 paths.append(path) @@ -355,6 +363,7 @@ class LoadImagesAndVideos: self.cap.release() if self.count < self.nf: self._new_video(self.files[self.count]) + else: self.mode = "image" im0 = cv2.imread(path) # BGR @@ -378,6 +387,23 @@ class LoadImagesAndVideos: raise FileNotFoundError(f"Failed to open video {path}") self.frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT) / self.vid_stride) + def get_rotation(self, filename): + cmd = [ + "ffprobe", # 注意是 ffprobe,不是 ffmpeg + "-v", "error", + "-select_streams", "v:0", + "-show_entries", "stream_tags=rotate", + "-of", "json", + filename + ] + result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if result.returncode == 0: + metadata = json.loads(result.stdout) + rotation = metadata.get("streams", [{}])[0].get("tags", {}).get("rotate", 0) + return int(rotation) + else: + return 0 + def __len__(self): """Returns the number of batches in the object.""" return math.ceil(self.nf / self.bs) # number of files diff --git a/ultralytics/engine/__pycache__/__init__.cpython-312.pyc b/ultralytics/engine/__pycache__/__init__.cpython-312.pyc index fdaad91bf92f6653ca07841d4a17e1af075d45e6..b4f938429d06bf261acc4de0b4825802f45b6046 100644 GIT binary patch delta 48 zcmbQqID?V!Vv&V CG7oS7 delta 49 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 literal 0 HcmV?d00001 diff --git a/ultralytics/engine/__pycache__/model.cpython-312.pyc b/ultralytics/engine/__pycache__/model.cpython-312.pyc index 06be6f0f4d4d2f9da58512cddbfb0d35b0379608..4ea6cac91fa73373684d59b8f29abb3d48033a36 100644 GIT binary patch delta 53 zcmdn|m}%2vChpU`yj%=GP!RlVBlj6ONfZ5y{M=Oi^1^iel+=>cccb8$Pa$Dk^7;bq=kM)er~FMd11PKN@_`Ja!E;1Vsdt7UixM> Hp(+Oe-EtB_ delta 54 zcmeyrgt1{MBll@uUM>b8xDfwnBlkl=DNFr~{M=Oi^1^iel+@IMywno?%KV)CGDCyS ItU^@|0R6rajsO4v diff --git a/ultralytics/hub/__pycache__/__init__.cpython-312.pyc b/ultralytics/hub/__pycache__/__init__.cpython-312.pyc index bef16036f08e36609d31997901b1f61d96060ea0..7b0f566f2dedd24d8cbb580e627601a742675840 100644 GIT binary patch delta 51 zcmX?Mdfb%zG%qg~0}x~fKikOtnN89}KO;XkRlmG2T|XtYBsICDq$n{tJ2NkRvjqDF FVF0pN5r6;y delta 52 zcmX?Zdcu_ZG%qg~0}xz@f3%VNGn@)6Jg diff --git a/ultralytics/hub/__pycache__/auth.cpython-312.pyc b/ultralytics/hub/__pycache__/auth.cpython-312.pyc index 203c243dbfe90976a41214a1adbf22758d5d4f2b..4b61c135b5886ff55dd370ec7b9fe84aa26d35b4 100644 GIT binary patch delta 51 zcmZ3hzebX#R$>!+laq$Zb?6eT8SXXd4EF659? F0RWVb5QhK& delta 52 zcmeB+?2qI=&CAQh00bA}A8q9J;gB-Y&&bbB)h{nh*H1}JEyznP(XY(U$uBcB*j&IN Grvd=7R}j|# diff --git a/ultralytics/models/__pycache__/__init__.cpython-312.pyc b/ultralytics/models/__pycache__/__init__.cpython-312.pyc index d0c12fb8ffa56cc11cfd1cd2c42e4ed9665ad99c..d9d13e59de4a48149207101f985a355497775af4 100644 GIT binary patch delta 49 zcmaFI^p=VHG%qg~0}$i{Kby$?RnlBPBR@A)zq~MAKP9y!HMyjuC^0!ZGcSFz6k`Yg DkrWWK delta 50 zcmaFM^p1)9G%qg~0}xz@e>9Q%tCWR)Mt*LpetBWKeoAU;L0)Q!er0}6ewm@cWJ$&l E0Ire|0ssI2 diff --git a/ultralytics/models/fastsam/__pycache__/__init__.cpython-312.pyc b/ultralytics/models/fastsam/__pycache__/__init__.cpython-312.pyc index 2851e2562c91aa518edcdcf88159829321affa6f..0a6570254fee13face8402d9e0a711537cf598a7 100644 GIT binary patch delta 49 zcmeyz^p}bIG%qg~0}$i{Kby$?SJGZTBR@A)zq~MAKP9y!HMyjuC^0!ZGcSFz5@QSi DnG_K7 delta 50 zcmey%^pA=AG%qg~0}xz@e>9Q%uatv+Mt*LpetBWKeoAU;L0)Q!er0}6ewm@cWJSgp E0Jg#rLI3~& diff --git a/ultralytics/models/fastsam/__pycache__/model.cpython-312.pyc b/ultralytics/models/fastsam/__pycache__/model.cpython-312.pyc index 05a4e0d40798fb5e39f3838434baf73ce2ae8440..2e8fb183aeac144623a3b839a330b5faf6295e13 100644 GIT binary patch delta 51 zcmbQiJDr#NG%qg~0}$i{KikON&n#)9pOK%Ns$X81uAh=xlA2snQk0mSotc-uc?OG%qg~0}xz@f3%TXg-yy{KO;XkRlmG2T|Xr?wIDCGM87gWC%??lV6z9C Gp#T8J(h&;) diff --git a/ultralytics/models/fastsam/__pycache__/prompt.cpython-312.pyc b/ultralytics/models/fastsam/__pycache__/prompt.cpython-312.pyc index 944eedbcba41902c0f02fe0a83ae817b7c46a0c9..eb26bcf46a36ffd807fb46083b613386c0749191 100644 GIT binary patch delta 53 zcmeC($k?-yk^3|+FBbz4S_=G%qg~0}xz@f3%Uig-Oa*KO;XkRlmG2T|Xr?wIDCGM87gWC%??lVDk#5 GKkNXi_YtcA diff --git a/ultralytics/models/fastsam/__pycache__/val.cpython-312.pyc b/ultralytics/models/fastsam/__pycache__/val.cpython-312.pyc index ea2a82ca08999d9e2a625c15ad14c1e8983aa62e..0b69c37bb8a7398c7d6eee3e3cd94cab5077f251 100644 GIT binary patch delta 51 zcmZn?ZWQJ|&CAQh00cR~&o*)|W0$nj&&bbB)h{nh*H1|;Nlh*(DN0Pv&df{Se42eb FBLIWZ5fcCa delta 52 zcmZn^ZW87`&CAQh00bA}A8q7b#x7;8pOK%Ns$X81uAh>cT9B7oqF9Q%kd%#nMt*LpetBWKeoAU;L0)Q!er0}6ewm@c#Al%Z DhW`;d diff --git a/ultralytics/models/nas/__pycache__/model.cpython-312.pyc b/ultralytics/models/nas/__pycache__/model.cpython-312.pyc index b7b209ce50cdfa542ed233bdc5e7412fc0e99e20..903852b3cfab34516ba4d934f00e7f742713417d 100644 GIT binary patch delta 51 zcmcbocvq48G%qg~0}$i}KikNy%O+`|pOK%Ns$X81uAh=xlA2snQk0mSotc-uIf$)? F3jmuM5YPYs delta 52 zcmcbscu$f0G%qg~0}xz@f3%TXmrcr2KO;XkRlmG2T|Xr?wIDCGM87gWC%??lU~?c_ G4;KKqsu3Ol diff --git a/ultralytics/models/nas/__pycache__/predict.cpython-312.pyc b/ultralytics/models/nas/__pycache__/predict.cpython-312.pyc index 243864e44ab8e17027b0bbb6897debcea738dc97..ef003d293e2600e75f7108ec54d4b6922ee5ea58 100644 GIT binary patch delta 51 zcmeB{=#t<*&CAQh00gX#R$>!+laq$Zb?6eT8SXXd4E4&>a$ F1ORvt5JUg~ delta 52 zcmeB@=$7C<&CAQh00bA}A8q8;;gqu0&&bbB)h{nh*H1}JEyznP(XY(U$uBcB*c`yQ GiwOXf>=2Rw diff --git a/ultralytics/models/nas/__pycache__/val.cpython-312.pyc b/ultralytics/models/nas/__pycache__/val.cpython-312.pyc index ca819a2bc82f26868802be1275124b636a973777..d58c3d6cc418d9901c2978e646068b9b9b5e3fd1 100644 GIT binary patch delta 51 zcmdlhv`2{hG%qg~0}$i}KikNy#x7~5pOK%Ns$X81uAh=xlA2snQk0mSotc-u*_-_n FBLIjW5WfHb delta 52 zcmdlZv{#7xG%qg~0}xz@f3%TXja|xIKO;XkRlmG2T|Xr?wIDCGM87gWC%??lV6zwd GCq@9JM-dGG diff --git a/ultralytics/models/rtdetr/__pycache__/__init__.cpython-312.pyc b/ultralytics/models/rtdetr/__pycache__/__init__.cpython-312.pyc index dc53474c1a772e0fdfe6f41539fea6168be108da..6bab8acbc964441e2538de764950851a4880a167 100644 GIT binary patch delta 48 zcmX@XbexI%G%qg~0}$i}Kby#XTGCEGBR@A)zq~MAKP9y!HMyjuC^0!ZGcSGOhX??0 CWf2?z delta 49 zcmX@kbb^WdG%qg~0}xz@e>9Q%w3NMmMt*LpetBWKeoAU;L0)Q!er0}6ewm@c#P<;Z DjRFyB diff --git a/ultralytics/models/rtdetr/__pycache__/model.cpython-312.pyc b/ultralytics/models/rtdetr/__pycache__/model.cpython-312.pyc index 7713b7b4a3a9d4876f3cf34e40beb1d442099c79..61f42c4573d5d50dadbfcc66175939c80b6bcfe9 100644 GIT binary patch delta 51 zcmca8d_kD|G%qg~0}$i}KikOtn^n?UKO;XkRlmG2T|XtYBsICDq$n{tJ2NkRvjW>j FW&o<~5mo>I delta 52 zcmca0d{LPDG%qg~0}xz@f3%VNH>;G5enx(7s(yK4x_(M(YC&FViGF2%PJWr8!De~3 Gjm!Ya7ZIcY diff --git a/ultralytics/models/rtdetr/__pycache__/predict.cpython-312.pyc b/ultralytics/models/rtdetr/__pycache__/predict.cpython-312.pyc index 20225e138881d3cbe65d15c20e08d9fd474c4980..319b9e047e61c7e99d264f122447ee9266ab1f7f 100644 GIT binary patch delta 51 zcmbQCI$f3fG%qg~0}$i}KikOthg;HCKO;XkRlmG2T|XtYBsICDq$n{tJ2NkRvm#G9 F8vvY75a9p- delta 52 zcmbQPIzyHFG%qg~0}xz@f3%VN54V(^enx(7s(yK4x_(M(YC&FViGF2%PJWr8!Da=X Gay9_EG!ZWV diff --git a/ultralytics/models/rtdetr/__pycache__/train.cpython-312.pyc b/ultralytics/models/rtdetr/__pycache__/train.cpython-312.pyc index 87bec8de8faaa96be47a9fb032cec7d4357c5911..57ed3214482ca9cea21cab4f5a188e3bdb33ec90 100644 GIT binary patch delta 51 zcmZ3iwn&ZpG%qg~0}$i}KikMH&Ms-KpOK%Ns$X81uAh=xlA2snQk0mSotc-u*@pc& FHvohF5Sah~ delta 52 zcmZ3awpfk(G%qg~0}xz@f3%TXoL$OBKO;XkRlmG2T|Xr?wIDCGM87gWC%??lV6!#* Gb8Y~k5D@18 diff --git a/ultralytics/models/rtdetr/__pycache__/val.cpython-312.pyc b/ultralytics/models/rtdetr/__pycache__/val.cpython-312.pyc index da53777567ccec7dc85fe55ddf9de5b99d68e798..6352f6a5347e0cebae1bf2f989d93b0f7e52d1ab 100644 GIT binary patch delta 51 zcmca_e$SlyG%qg~0}$i}KikNi!Ypa2pOK%Ns$X81uAh=xlA2snQk0mSotc-uxsy3e F0syNt5kCL` delta 52 zcmca-e&3w?G%qg~0}xz@f3%T1g;~lm^ Gm;?aHClQSR diff --git a/ultralytics/models/sam/__pycache__/__init__.cpython-312.pyc b/ultralytics/models/sam/__pycache__/__init__.cpython-312.pyc index 8b41d71f676c0e6ad3ccf9901150c726d045b6e1..d2a7d8a5f651928a8317c9af0248da2d3b582fe3 100644 GIT binary patch delta 48 zcmeBX>SE$P&CAQh00gSp3T&CAQh00bA}A5G+*B4wkWk)NBYUtXB5pOTtdke6DbUzwkiUuI}9aYqmU DZmtk{ diff --git a/ultralytics/models/sam/__pycache__/amg.cpython-312.pyc b/ultralytics/models/sam/__pycache__/amg.cpython-312.pyc index 06b5fc46a5f3cd12627a990674705c1176a6804a..b934393fdfffa20700cd9a35772b437d3d26c9ce 100644 GIT binary patch delta 51 zcmX>Re>|T1G%qg~0}$i}KikNi#U^Q{pOK%Ns$X81uAh=xlA2snQk0mSotc-uxu4Ba F69BSI5o7=W delta 52 zcmX>ee!WRHg Cun(R9 delta 49 zcmZ3&xRjCmG%qg~0}xz@e>9QXSjt5|BR@A)zq~MAKP5G_ATPBG%qg~0}$i}KikM%z$@vjpOK%Ns$X81uAh=xlA2snQk0mSotc-uc`EM< FNdUzq5^?|l delta 52 zcmez4_t%g6G%qg~0}xz@f3%UifLF>zKO;XkRlmG2T|Xr?wIDCGM87gWC%??lVDl8- G7m@(uq7uLW diff --git a/ultralytics/models/sam/modules/__pycache__/encoders.cpython-312.pyc b/ultralytics/models/sam/modules/__pycache__/encoders.cpython-312.pyc index 75a377c80650dc823e0bab9f88443e43a7e0bcb5..f3ad2cccdd0ef084ed81cc7446f17b8c2b64cf17 100644 GIT binary patch delta 53 zcmZ47#I&f1iTgA!FBbz4wNi@vG%qg~0}xz@f3%U?kxR;6KO;XkRlmG2T|Xr?wIDCGM87gWC%??lU~?+h GVI}~jco7Q# diff --git a/ultralytics/models/sam/modules/__pycache__/tiny_encoder.cpython-312.pyc b/ultralytics/models/sam/modules/__pycache__/tiny_encoder.cpython-312.pyc index b5ca8ae79de53a0b77ea60291c531a66b5c276b9..0e80feafe2730fe517d242679f3fce13ac69255f 100644 GIT binary patch delta 53 zcmeyklIg=rChpU`yj%=GkQ@ALBX<^?q`Q7ber~FMd11PKN@_`Ja!E;1Vsdt7Ui#*K Hwxm7)=I#>h delta 54 zcmeyclIi10ChpU`yj%=Ga3TKDM(!*&DG&XO{M=Oi^1^iel+@IMywno?%KV)CGDCyS IeQZg600t5hI{*Lx diff --git a/ultralytics/models/sam/modules/__pycache__/transformer.cpython-312.pyc b/ultralytics/models/sam/modules/__pycache__/transformer.cpython-312.pyc index c22df5f83963dbb939bab781b6d008f3d0ede10f..8ad5fdc4f075346a5f9cecf08c93982257ef0946 100644 GIT binary patch delta 51 zcmeB5>rCT5&CAQh00gq_H3&CAQh00bA}A8q8m$R*{jpOK%Ns$X81uAh>cT9B7oqFqK FB>=Ld5##^> delta 52 zcmdlTuqS}~G%qg~0}xz@f3%T%1*?>^enx(7s(yK4x_(M(YC&FViGF2%PJWr8!R9lp G`APuLtP(K* diff --git a/ultralytics/models/yolo/classify/__pycache__/val.cpython-312.pyc b/ultralytics/models/yolo/classify/__pycache__/val.cpython-312.pyc index b8e1706470ee16395b88c1b9889e7523c23577dc..ec159346a5c22c26392d1b8e48d47e5414c0e44a 100644 GIT binary patch delta 51 zcmZ2tx7d#RG%qg~0}$i|KikNy$SUcepOK%Ns$X81uAh=xlA2snQk0mSotc-u*^Tv{ FBmj?g5as{? delta 52 zcmZ2%x5SS7G%qg~0}xz@f3%TXkyXl3KO;XkRlmG2T|Xr?wIDCGM87gWC%??lV6!Xh GJxKtpp%F6x diff --git a/ultralytics/models/yolo/detect/__pycache__/__init__.cpython-312.pyc b/ultralytics/models/yolo/detect/__pycache__/__init__.cpython-312.pyc index 6374723f52c16a8d441cbca8b8657acd53979fc3..a9a96f6b72722ad6d44ccf2a0b23f75cb4c491ae 100644 GIT binary patch delta 48 zcmcc1bcc!iG%qg~0}$i|Kby#XThduSBR@A)zq~MAKP9y!HMyjuC^0!ZGcSD-V=Mr8 C)DUw3 delta 49 zcmcb^beD9Q%wv>y0Mt*LpetBWKeoAU;L0)Q!er0}6ewm@c#Q(7X DmxvL* diff --git a/ultralytics/models/yolo/detect/__pycache__/predict.cpython-312.pyc b/ultralytics/models/yolo/detect/__pycache__/predict.cpython-312.pyc index 7ea333e15807945537c73d4ded7083a1f912c0d5..6f78b2ea5cdbe1c7d37f5078e25d97745f58155a 100644 GIT binary patch delta 51 zcmdlav{8urG%qg~0}$i|KikMXflbm$KO;XkRlmG2T|XtYBsICDq$n{tJ2NkR^H#Q6 FCIFMC5flIb delta 52 zcmdlev`L8jG%qg~0}xz@f3%T%0-Kbxenx(7s(yK4x_(M(YC&FViGF2%PJWr8!R9S& GwM+o92oYfb diff --git a/ultralytics/models/yolo/detect/__pycache__/train.cpython-312.pyc b/ultralytics/models/yolo/detect/__pycache__/train.cpython-312.pyc index 786811e747a3d963b0ffc8eec8d97dc7584bb384..6db7aadc63fddc22658e61f5036d9217eebd983b 100644 GIT binary patch delta 51 zcmezA_QQ?)G%qg~0}$i|KikM1#U|;XpOK%Ns$X81uAh=xlA2snQk0mSotc-uxt{Hp F3;?`U5;Fh* delta 52 zcmez2_S22~G%qg~0}xz@f3%T1icQK9Q%q?Dt6Mt*LpetBWKeoAU;L0)Q!er0}6ewm@c#J5oZ DjQkO5 diff --git a/ultralytics/models/yolo/obb/__pycache__/predict.cpython-312.pyc b/ultralytics/models/yolo/obb/__pycache__/predict.cpython-312.pyc index fb46f2fdb8a2efe3a79bcf6022ad3a30aa04c256..baecc6f9c94f614159cc09c97bf08f8c4cb550fb 100644 GIT binary patch delta 51 zcmdlaxlxk)G%qg~0}$i|KikN?g;~;GKO;XkRlmG2T|XtYBsICDq$n{tJ2NkR^G)WP F8~~ey5yJog delta 52 zcmdlexk-}yG%qg~0}xz@f3%T%3$v7ienx(7s(yK4x_(M(YC&FViGF2%PJWr8!R8yx GH#q>g5fTsp diff --git a/ultralytics/models/yolo/obb/__pycache__/train.cpython-312.pyc b/ultralytics/models/yolo/obb/__pycache__/train.cpython-312.pyc index 4e86ac5d70dc398b88a9e23207230e2d6f79f5bb..3e596751ae69dc6a91e13879422d804c6f4234f6 100644 GIT binary patch delta 51 zcmZ1{v{s1wG%qg~0}$i|KikONz$|I2pOK%Ns$X81uAh=xlA2snQk0mSotc-uc`0)z FD*%q;5byv1 delta 52 zcmZ20v`&coG%qg~0}xz@f3%UifmzB9Q%jFgjpMt*LpetBWKeoAU;L0)Q!er0}6ewm@c#1GK` Dj{OmO diff --git a/ultralytics/models/yolo/pose/__pycache__/predict.cpython-312.pyc b/ultralytics/models/yolo/pose/__pycache__/predict.cpython-312.pyc index d4f16cc219cea62d49ee3c78741f17db4dc03f8f..901b7c310e476bf272fd1c2ed2f91c98cc1909b5 100644 GIT binary patch delta 51 zcmZ22w@QxtG%qg~0}$i|KikM{%_`}jpOK%Ns$X81uAh=xlA2snQk0mSotc-uIf3;w FCjg0l5XArh delta 52 zcmZ1_w_1+-G%qg~0}xz@f3%U?npMhCKO;XkRlmG2T|Xr?wIDCGM87gWC%??lU~@d{ GX-)v9kr5IA diff --git a/ultralytics/models/yolo/pose/__pycache__/train.cpython-312.pyc b/ultralytics/models/yolo/pose/__pycache__/train.cpython-312.pyc index 38c449327caeb05b8f1c8b4025a87c4079925b1c..7289f01fcb4c9e0d1e17c35a5189dfe6d17044d8 100644 GIT binary patch delta 51 zcmbQDG+BxJG%qg~0}$i|KikM1&njuBpOK%Ns$X81uAh=xlA2snQk0mSotc-uxrKEC FHvoo?5Ucj_TKO;XkRlmG2T|Xr?wIDCGM87gWC%??lU~@C; G1a1JMoe=o| diff --git a/ultralytics/models/yolo/pose/__pycache__/val.cpython-312.pyc b/ultralytics/models/yolo/pose/__pycache__/val.cpython-312.pyc index 5276eff122fc5939cf8af40c0efefe72628af3fa..59d7a76cc9b18018dd086aa4ff408920540a3c6c 100644 GIT binary patch delta 51 zcmcame7>0bG%qg~0}$i|KikMXolVk4KO;XkRlmG2T|XtYBsICDq$n{tJ2NkR^By)4 FV*tc25#j&< delta 52 zcmX?Ke4&{8G%qg~0}xz@f3%T%I-8WOenx(7s(yK4x_(M(YC&FViGF2%PJWr8!RFm; GBE|sXj}k8c diff --git a/ultralytics/models/yolo/segment/__pycache__/__init__.cpython-312.pyc b/ultralytics/models/yolo/segment/__pycache__/__init__.cpython-312.pyc index a9bf2744fececc20c816f4263daf0ce79d967663..c19ecf4ad641d967d210b293c9a65b2306b922e6 100644 GIT binary patch delta 49 zcmaFP^o)u7G%qg~0}$i}Kby$?MAAh+BR@A)zq~MAKP9y!HMyjuC^0!ZGcSEICu1A{ DjoA>J delta 50 zcmaFH^qh(NG%qg~0}xz@e>9Q%iIl5;Mt*LpetBWKeoAU;L0)Q!er0}6ewm@cWDdqS E0IMMo=>Px# diff --git a/ultralytics/models/yolo/segment/__pycache__/predict.cpython-312.pyc b/ultralytics/models/yolo/segment/__pycache__/predict.cpython-312.pyc index 64e90a983417902bd80299b02113ef77a996a6e4..45d023d2bf705c360baff315faa74a82b65f414d 100644 GIT binary patch delta 51 zcmZ1{w^ok(G%qg~0}$i}KikNCfmza7KO;XkRlmG2T|XtYBsICDq$n{tJ2NkR^H*j| FZUCPD5n})V delta 52 zcmZ20w@!}xG%qg~0}xz@f3%VN0<)Bhenx(7s(yK4x_(M(YC&FViGF2%PJWr8!R9Z_ GmfQfm)Df`& diff --git a/ultralytics/models/yolo/segment/__pycache__/train.cpython-312.pyc b/ultralytics/models/yolo/segment/__pycache__/train.cpython-312.pyc index acedd4071080702279de381837d1b1b279043c3e..a237882f40b8bd41d91108d197405e679e7d7522 100644 GIT binary patch delta 51 zcmZ1|y+E4#G%qg~0}$i}KikOth*{E6KO;XkRlmG2T|XtYBsICDq$n{tJ2NkRGds&H FP5_tY5XArh delta 52 zcmZ1=y-=F_G%qg~0}xz@f3%VN5wnz&enx(7s(yK4x_(M(YC&FViGF2%PJWr8!Dcp= GS)2g1s}U0b diff --git a/ultralytics/models/yolo/segment/__pycache__/val.cpython-312.pyc b/ultralytics/models/yolo/segment/__pycache__/val.cpython-312.pyc index 7cf7781ee9c6f0958e907f245ecc3c764850b929..d53c48033ab6a5a4eb99831b136d2df12b5c9b4b 100644 GIT binary patch delta 53 zcmcc8#CW-hk^3|+FBbz4pp7$%hD2X delta 54 zcmccI#CWBNk^3|+FBbz4T!??Pk-Lyp%0WLPKQ~psyf9rqB{j7mFSSI!GCwE3%+O%- IRMvgg0P0&3z5oCK diff --git a/ultralytics/models/yolov10/__pycache__/__init__.cpython-312.pyc b/ultralytics/models/yolov10/__pycache__/__init__.cpython-312.pyc index 4ad531bcc0d418928dfe60cb0496ac269fcd259c..64581141201b76d1793c968cb9f126d789dd58bd 100644 GIT binary patch delta 49 zcmcb^beoC$G%qg~0}$i{Kby$?K+;}6BR@A)zq~MAKP9y!HMyjuC^0!ZGcSEID`PkS Dh;9Q%fs})OMt*LpetBWKeoAU;L0)Q!er0}6ewm@cWERG7 E0HwkZzW@LL diff --git a/ultralytics/models/yolov10/__pycache__/card.cpython-312.pyc b/ultralytics/models/yolov10/__pycache__/card.cpython-312.pyc index 6c5ae8a5f3a1a6c4f37925d5a7f50b849b1014ea..05627f5b71fd2454ba560dbb6bbe8f879a94d7f4 100644 GIT binary patch delta 50 zcmX@kdyJR+G%qg~0}$i{KikOd!6s>~pOK%Ns$X81uAh=xlA2snQk0mSotc+DIhQR8 E0DUbGRsaA1 delta 51 zcmX@cdz_d1G%qg~0}xz@f3%U?gH6gtKO;XkRlmG2T|Xr?wIDCGM87gWC%??lU~&#y F6aboB5TyVB diff --git a/ultralytics/models/yolov10/__pycache__/model.cpython-312.pyc b/ultralytics/models/yolov10/__pycache__/model.cpython-312.pyc index 6f88e238cdc6fec7028a883e3a25884b401de2bf..cb48aff4e9834d7ac5141ab31344bafa68544385 100644 GIT binary patch delta 51 zcmeyz|CgWpG%qg~0}$i{KikMXl}XY@KO;XkRlmG2T|XtYBsICDq$n{tJ2NkR^DZVA FRsgQ=5o!Pc delta 52 zcmey%|Bs*hG%qg~0}xz@f3%T%DwCA0enx(7s(yK4x_(M(YC&FViGF2%PJWr8!RDPz GF025}DG|8< diff --git a/ultralytics/models/yolov10/__pycache__/predict.cpython-312.pyc b/ultralytics/models/yolov10/__pycache__/predict.cpython-312.pyc index 509badceea444b14bee73b300c3ddb264f52f2ec..54cc277c10ccc05741fac92f405865c43fd88c96 100644 GIT binary patch delta 51 zcmdldwpWb%G%qg~0}$i{KikON!7gd1pOK%Ns$X81uAh=xlA2snQk0mSotc-uc`f@y FW&oH!5j6k+ delta 52 zcmdlhwoi=vG%qg~0}xz@f3%UigI&sAKO;XkRlmG2T|Xr?wIDCGM87gWC%??lVDlRG GiOc}D0TF}% diff --git a/ultralytics/models/yolov10/__pycache__/train.cpython-312.pyc b/ultralytics/models/yolov10/__pycache__/train.cpython-312.pyc index e3fb6c1003aa113871bf7d6f458515ca5fa9d191..778f84f0cb6160e18294b177ea4aca46740728c5 100644 GIT binary patch delta 51 zcmeC->E_`+&CAQh00cR~&o*+eV3M@a&&bbB)h{nh*H1|;Nlh*(DN0Pv&df{Se3r?c F832Ry5T5`5 delta 52 zcmeC?>EYo%&CAQh00bA}A8q7b!6ap?pOK%Ns$X81uAh>cT9B7oqFw}y}VG%qg~0}$i{KikNCm{HP7KO;XkRlmG2T|XtYBsICDq$n{tJ2NkR^9x2- FRsfYU5gz~m delta 52 zcmZ3(x0a9lG%qg~0}xz@f3%VNFr$>Uenx(7s(yK4x_(M(YC&FViGF2%PJWr8!RF_T GuB-sE^ATxuK4H7%$Tcp;%bv5y5yhG}KJmRP6^Lj8t5RXiXV z;f{|HBWJ}T4D$vnZ;11F+@B*`Na?HAOd&1Eyw3=hPPPxlM2Hd6gX}>Y>Fz2_HpUY- zF}S0Z3v#60ms%{CYI37pro_XtInIQnsA2Lw!?-!~ziK&y@h+<|@@qyW z$^5;^_MOSrRWW0-FIcQcTRK|0HVyBcFwa_cb#Oo3o0+u~y~F)(hO}}-o(q>7_98mC z%~1Gj%}P#&dkP$MLpn`mB}{)QS60BDbLc2PU!X24)}G(41zw`B$Y3w%%Cr@!?8Q`d zMTXM+ak~aRNd6o?fKCwC$m=LX7Dt{%J;X7Zj{3;cqxqUsbUiGqw2eNg&O1pt{t&=J zi{VcJK7wH{uqA*H9ah>c80^yD9Wy2LLwo>WkYtW!Jw61q^Iv@>uzG-D2tc}>$KAkp z11v!(YTrZZ$9Aeep_7}HFUHOp(N1#c(un>vsLoIzyDn`-&k$*10ELyTuk;8VCplk_ zXZO=@#GgiO)>oMIcII2__Ha`u``GR-?)VGgra$lm;U)*rAQ_#UM5Cnb@{4FlnZG=X zlE%UL2dMuhz>xDJ%M%M5eZ)3&b!jpmGIIAJe6MNp%r*vs5cJM$ooO90K(jl08?5 z&MGg>*$|o`!Fl_}HPGq2V!-K_#kxphgV%GwBMMHRORmOupx8K>n9o9|mF0O8=ehzj zvyfvfrGEy`YYnnkfw6>f)JWqOUD#cXIjD9QWa=s`HTdWe=IbOutd04C)(<}en+@*+ z={nc~Oe_1Y+O&uxf$J^kHu>#(FWrQr%f)6Lm17P-55NOx$jb7PCe{*}x?x2_tu)<)jKWKpTL_KKfMnuXzO$DiW(Hlm^Ee~2|?%5wFrOh+u^ijxK9Y|M7I=`T4gM)cA9N(R|on!RY{sTY>YcP@FJyKk24^3S44 zwyw)UZo$c#6E&YIpS!L)t3RxJm`&~)Tpy{kzXII8Cvf;}JqPPY2YgiMqu*hkv6;zsTI#llGj6}Ru0p(6VXWJtZ;JJppcGGy?}vUgBo4t@Je+t9 z`fxFk4Q%cB&e zNwYBySetOw4iYO)uHL_s8pt|8aGnCB;jyyQWWP$VLZMV*ALdN#GJe6GPwIh*X&LIV z?9#a90)RpnDmtWM7*pHwW~3rsqINyXGd^VM z? zPSjsWmf*7f@Op_E448l8AlyN`F$iP$?9Jz0CQfGt0y9AtfrQ6yu9(s-VQAIOCv|+a zvSNY6{?S1=z_bY4Ms<2Pc%<|5R;1k1YV)*k?ix^!o&0c^N!?Tupk{#k;6 l?vbsL#BG99zcGxh6+*r~yS5XI+ad1(L-}qQsOY=9`7aG79(H9Z< delta 54 zcmbPrpK= '2.6': + ckpt = torch.load(file, map_location="cpu", weights_only=False) + else: + ckpt = torch.load(file, map_location="cpu") + + except ModuleNotFoundError as e: # e.name is missing module name if e.name == "models": diff --git a/ultralytics/utils/__pycache__/__init__.cpython-312.pyc b/ultralytics/utils/__pycache__/__init__.cpython-312.pyc index 0951c2a17e89708ec1f153c458b730158bfe0f87..5a45360e59b97a25d5f684be84480a5c61a6933a 100644 GIT binary patch delta 53 zcmX@y$$Y4jnfo*^FBbz46a+up$o-O2(o8=iKQ~psyf9rqCAB0qxum2hF*!RkFMTr~ H*VbJC);to) delta 54 zcmX@q$$Yqznfo*^FBbz4T!??Pk^3d5l(~LJer~FMd11PKN@{9BUTTScWqwY6nW4dE IUaqaX0Q9yK6aWAK diff --git a/ultralytics/utils/__pycache__/autobatch.cpython-312.pyc b/ultralytics/utils/__pycache__/autobatch.cpython-312.pyc index e198f39f41595ca310a72ca28dcb5c7cd2017105..ed761cc9a27ce284c59c108873b66eeffeeff055 100644 GIT binary patch delta 51 zcmX@3d0LbEG%qg~0}vDhKikOtj#<)NKO;XkRlmG2T|XtYBsICDq$n{tJ2NkRvoOm} F0RXR65pDng delta 52 zcmX@Dc}A1_G%qg~0}xz@f3%VN9kY~$enx(7s(yK4x_(M(YC&FViGF2%PJWr8!Db delta 54 zcmZpk&(t!XiTgA!FBbz4T!??Pk$V}Zl&OA3er~FMd11PKN@{9BUTTScWqwY6nW4ev IQ=B_n0o?Qx1^@s6 diff --git a/ultralytics/utils/__pycache__/dist.cpython-312.pyc b/ultralytics/utils/__pycache__/dist.cpython-312.pyc index 84659f26a8a3b709fbe746529c0b3abcb76bd27a..d4882b04e1abef6a84c21431e525945156692fe0 100644 GIT binary patch delta 51 zcmZ20y+)e*G%qg~0}vDhKikNCj7ic+KO;XkRlmG2T|XtYBsICDq$n{tJ2NkR^J}I< FTmYM85x)Qc delta 52 zcmZ1@y;hq0G%qg~0}xz@f3%VN7?YH-enx(7s(yK4x_(M(YC&FViGF2%PJWr8!RA*? GhqwT^q!J1M diff --git a/ultralytics/utils/__pycache__/downloads.cpython-312.pyc b/ultralytics/utils/__pycache__/downloads.cpython-312.pyc index b40e6d8d2b72184dc33bcecc143c500b6a79b444..2cba1b4fbbb1276ab6699c5a829d4ead5a2b02a8 100644 GIT binary patch delta 53 zcmcb9iSgPcM()$Ryj%=GP!RlVBlj~-Npt;-{M=Oi^1^iel+=>cPw0RR91 diff --git a/ultralytics/utils/__pycache__/files.cpython-312.pyc b/ultralytics/utils/__pycache__/files.cpython-312.pyc index 7f4ff2632dd2e60c43af9c070aff150afafc34f9..7216264b2f3256b0ce9d12576eb52f2d54ae2658 100644 GIT binary patch delta 51 zcmbR1F~@`ZG%qg~0}vDhKikN?nMu-EKO;XkRlmG2T|XtYBsICDq$n{tJ2NkR^9?3f FMF67P5pDng delta 52 zcmbQ^G1r6pG%qg~0}xz@f3%T%Gn15wenx(7s(yK4x_(M(YC&FViGF2%PJWr8!RG5s Gu8IJ_LJ_$D diff --git a/ultralytics/utils/__pycache__/instance.cpython-312.pyc b/ultralytics/utils/__pycache__/instance.cpython-312.pyc index 6f3eddfdc056735d64a4ac519527bc362fdf78da..8c42fe03dda8f21398d48cf6b2ae2ec965e4616a 100644 GIT binary patch delta 53 zcmbQef^pUgM()$Ryj%=GP!RlVBX>QMq?vw3er~FMd11PKN@_`Ja!E;1Vsdt7Ui#)G HOyz+9#A*^L delta 54 zcmbQWf^qf=M()$Ryj%=Ga3TKDM(%nhDRcdd{M=Oi^1^iel+@IMywno?%KV)CGDCyS IiccQfB%Y`MIh3<%Q|`DXFOid8sA(mH9dOWrhaL N@7cG%XJ=I50{}hb6a4@H diff --git a/ultralytics/utils/__pycache__/ops.cpython-312.pyc b/ultralytics/utils/__pycache__/ops.cpython-312.pyc index 48b67ce03d468ebddf029b9e338b4bd7760ec494..68fb216a5e1437fc47e705a54c44266083afc947 100644 GIT binary patch delta 53 zcmZp>!PI(#iTgA!FBbz46a+up$lcE>X{eu(pPQ;*UYM?*l3J3QTvAe$n4F!Nm%e!m HYtS+P(RdQF delta 54 zcmZp@!PItxiTgA!FBbz4T!??Pk-MK&%1A#WKQ~psyf9rqB{j7mFSSI!GCwE3%+O%- IX4ar(0PnF9{Qv*} diff --git a/ultralytics/utils/__pycache__/patches.cpython-312.pyc b/ultralytics/utils/__pycache__/patches.cpython-312.pyc index a60046a9116c936db92a03ec77608a716b303ba9..5f69eedb2e3310f0721720fc1d4d057093c5e76e 100644 GIT binary patch delta 51 zcmeB`?vds`&CAQh00afW&o*-FGfSH4XXNLm>X#R$>!+laq$Zb?6eT8SXXd4E4q>+B F0swe@56u7o delta 52 zcmeB??v>^~&CAQh00bA}A8q8;XO=S4&&bbB)h{nh*H1}JEyznP(XY(U$uBcB*c{Ak G$prwE=@1wI diff --git a/ultralytics/utils/__pycache__/plotting.cpython-312.pyc b/ultralytics/utils/__pycache__/plotting.cpython-312.pyc index 836736994d69e1be09fa1aae6e060390546ef31a..a811d623071287234e96cb1658519c834d68dc90 100644 GIT binary patch delta 53 zcmZ4cfO*XWX71Cxyj%=GP!RlVBey%Jq?vw3er~FMd11PKN@_`Ja!E;1Vsdt7Ui#)7 H&V$bY+>8@G delta 54 zcmZ4UfO+i$X71Cxyj%=Ga3TKDMs9abDRcdd{M=Oi^1^iel+@IMywno?%KV)CGDCyS J*_;QT0RZ~u6Nvx- diff --git a/ultralytics/utils/__pycache__/tal.cpython-312.pyc b/ultralytics/utils/__pycache__/tal.cpython-312.pyc index 6c9ad96330adbf4df06ff62801e46d0d9fd69218..c4300797be6f78241433158a3d7e32f7d5dc77b6 100644 GIT binary patch delta 53 zcmX>&pYgzaM()$Ryj%=GP!RlVBlkg8NkjdN{M=Oi^1^iel+=>cwpYh;)M()$Ryj%=Ga3TKDM(%^GQbzh2`MIh3<%Q|`DXFOid8sA(mH9dOWrhZu JpR(Te1OWK46ORA@ diff --git a/ultralytics/utils/__pycache__/torch_utils.cpython-312.pyc b/ultralytics/utils/__pycache__/torch_utils.cpython-312.pyc index 35db9da593c16d9ff047394da31d933b587f9d07..bef6c24b17e885344256999820cfd33014a864d4 100644 GIT binary patch delta 53 zcmaF8jOo=fChpU`yj%=GP!RlVBliwgNlX2V{M=Oi^1^iel+=>c9PMla!-=Mt*LpetBWKeoAU;L0)Q!er0}6ewm@c#A^`% DfTIxz diff --git a/ultralytics/utils/callbacks/__pycache__/base.cpython-312.pyc b/ultralytics/utils/callbacks/__pycache__/base.cpython-312.pyc index 02e8cd17c291daf16a09177e55a692030e380fd0..d7e9f2b2f830c98cb96d3b9f28a4cbfac2c656a8 100644 GIT binary patch delta 51 zcmZ2%xX6(EG%qg~0}vDhKikNy#UyE?pOK%Ns$X81uAh=xlA2snQk0mSotc-u*`Fyy F3;>C_5Jvz2 delta 52 zcmZ2vxY&^UG%qg~0}xz@f3%TXi%H5>KO;XkRlmG2T|Xr?wIDCGM87gWC%??lV6z`n Gh!_B-eh`uX diff --git a/ultralytics/utils/callbacks/__pycache__/hub.cpython-312.pyc b/ultralytics/utils/callbacks/__pycache__/hub.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b7c103c824775276906f5af34267ef2288981b4f GIT binary patch literal 4638 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 delta 5719 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 diff --git a/utils/__pycache__/metrics.cpython-312.pyc b/utils/__pycache__/metrics.cpython-312.pyc index 9ec43d2bd33e315fdde09e744268a6ca7c3ed275..98032a5530ac3446884f6c0d9bca2510ec21dece 100644 GIT binary patch delta 23 dcmcb)fbr%6MxN8Wyj%=GP!RkqeIt)=003Ub2U-9C delta 23 dcmcb)fbr%6MxN8Wyj%=GQ0KNNZ6l9w003P+2NnPT diff --git a/utils/__pycache__/plots.cpython-312.pyc b/utils/__pycache__/plots.cpython-312.pyc index 3a777654a9ae01514137bcec4406309a8767e274..6863a11d1e07f372ac2d4183e6212de296ab70c9 100644 GIT binary patch delta 23 dcmezSjq&d{MxN8Wyj%=GP#F9yeIrj{H2`xH2%Z1{ delta 23 dcmezSjq&d{MxN8Wyj%=GQ0KNNZ6i-%H2`sg2w4CC diff --git a/utils/__pycache__/torch_utils.cpython-312.pyc b/utils/__pycache__/torch_utils.cpython-312.pyc index 371d1870fd8fabd579f83eb02b2259f25ff1d62f..deea80dbe938f8c1566e31acfecddacc9cdfb9e6 100644 GIT binary patch delta 23 dcmZpE%h>#uk>@loFBbz46a+s@-^f#51^`_n2bcf= delta 23 dcmZpE%h>#uk>@loFBbz4)VVE6+sIR11^`=|2UGw6 diff --git a/utils/__pycache__/triton.cpython-312.pyc b/utils/__pycache__/triton.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a7b2aa5c6231d9680136db9dd09d3f292ea239c8 GIT binary patch literal 5645 zcmdT|eQZd`W@E$q2LwV5*gbc-uDuIZJiRLqvv4An&+Eb!aZtiCmFQNHd9X^Cup`)5d|mRu&S3MB*WwU(*H)OV$g9hKejPBE zdc6wHuhkt_(BP^>wZ~~S*k5`YhodGw5!G=h`Mz>c86#ROhKUk|k5)7#ObLoXb)YNf z6JMnwuX4;(d|Je*Ks%2WUo_$m495v91Wo&*;cz?>@M$Kt_da_1)FCBGly40ToMKBg zpAW}OLm7w?--t4RBSw@MY%|S(i;BffMT_VP!DgI9;PysvSOH2jZUV{hGEPf?+wm2z zo2iN#jR3#GG|aw+UXv%0$uSCaDehKroaR$}aOt`ti_Tqm93k=x9WIa>SXu~+-S@Vc|EoHxuB0PRP4aupo~bMK;lx;!=!!;$<6#^zjqWlDjJ;dwjfX-B z z^RL&5uuGbQRU%z=tH=cuFHnRumqz`-!7;8ed&FkP(2R7_k{R|GmKf2(*piG9EruedKZlWGQIS{rxifXh_cwg|kE9Ol0)l(Aeh!w>H6jI5d`d`Rw)MH!e;!-%QLs zHTRw0bmuyH-|3#!Zf~Ey_^VxW-Pw-byWHK5-__n<{q4-q*k^3r0^%AH+?Q5I@0SHO zQCI_~{HXEZD*2a<2df+BYGL$#wFEt(c<}#k9RxBIM5s{{8m-IMOejc__0avBcLkP@ z2*p{l0lJf(210Guk_{gOKWsJF=Hg?{=w<#|O_`bH$q{UVF<7!qwpxd=sj_gc5*&*f zkmisCn2nBKv1B%HuxqiLHWRb<#>GV?BPTRoSTfi?n5`u~7ck6af{d7E%-Wzn(gIa~ z#8XA6D-s$ZEhkH-bQREyQ2DL;WpZabK3eRllt>wWX> zo8G!~^HRS3NVfe*uKj4n<(_Zz=G%5=+jh=s*|y#Jww`QT53oKz?^fRGyV;j_cW2$* zb35KW@XmqEz?qD@JLi50=qDCLzBa+#9=&sE<`Vc&SMT2tomfzi_b4|m-gk6-(SmB9 zsA^^k@QXAHaeiYj22{6zxrx=BAu^OvUSSTy6MArPRyLhclKmE zd**_<&SSZ{;~B?s;stg>L%#PRtx@BoNnN2EM3|&WVntn~xByD=Kj(hHr3K)qkah+o z*kxG*&T>MzNJI#0e<^NtZK-)Ojavd4j4w_ zVMrciTEl^t2q7HtIG9sdB2|MW+oIbdI3Q1qMI#2L37ZiQnU-t|1@LZ{U(}GO3TZ3D zE#!+KRjmxSHtlIxX1oC%xRet$Zn?HP->^B`uz5<)H0+%AXB&2o%kxbwlY6i4%{Oh% zHf^32e_i)>-Ca4;v^m%G{J3Mjp$RyeTPMTU!&ApTX!efxK3LN_sa{v7&g8f3%5K>; zJ38lo`@6XMp)XPQXt6WMTKqX75<<&q%mHfP1 z0!pwtloFPlT=ts_pkcCp$(a?o-h_-dB|tCzq`dM~&ZH>CT1tXExrjc13;={@;VmtL zN6SGPiI=rhRj`a3i=>jgL7L$&Yb9FA-vJ4Bh|I@R5}df7o|fX_G@3~*YZMRutCBop zOX87FCYw&u|AOfM2xXA)Cc6%4kx0~3j2QL>{0SRh=wA>e_cs}27~tdzjZVqxBd-9f z322b4EpFGT48sl<=LI+Hfe*4=r|nR7gpep9H0)SHG7z(x3`oyt5uy4?G+gv!!552L z67y*W6GdMppf^Mg(6tWg)hf8T<+P<@W7pDpfkFp-nI(;Cp*S{HxHO^Onk@eDwdC(0 z@53;37`TkTLU$QGXn$;K$D4`Uo2LD@p19UA?)b2-<)_XEjcu9s9l6Gx8Q0DaYnpD_ z6Q^>GFJxRVeAKc&-?As$vM1NFciaW!`MQ=LZ@-bst?#^7*ZH9Nv8k7C8?*azUC(5^ z2jAOp_m#WB%$b)mn+9{uFK6msexPicdTw^}AC#xByRJ#s;`8-u^7Wo3)QvU3bpNzi0~(2jbafuXyCKIH|;vEXc% zj&e5+6%c(cJj)?@)u%i!^>GCOh6`-C;HZ)IOz*n0Z)V?|^seh2*L(iohTacl`p@M1 z)oj0-(ezBep6$h%-8lP%zkqt-pjIfR*