Instructions to use aseylys/Outflock with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- ultralytics
How to use aseylys/Outflock with ultralytics:
from ultralytics import YOLOvv8 model = YOLOvv8.from_pretrained("aseylys/Outflock") source = 'http://images.cocodataset.org/val2017/000000039769.jpg' model.predict(source=source, save=True) - Notebooks
- Google Colab
- Kaggle
Upload folder using huggingface_hub (part 4)
Browse files- train/datasets/camera_obb/labels/val.cache +0 -0
- train/datasets/camera_obb/labels/val/4835158c093e3ffd52342a423809364754226b2b.txt +2 -0
- train/datasets/camera_obb/labels/val/53a01ff48d650b43cf17cc5fe1bf494aee25616c.txt +3 -0
- train/datasets/camera_obb/labels/val/56c28acf11c5decc8d221f1ca2e3df6bd2d049d4.txt +2 -0
- train/datasets/camera_obb/labels/val/5c0d510a70c11ec736e414189db16f45ddb5fc9d.txt +4 -0
- train/datasets/camera_obb/labels/val/60768f20302a19d26b68b54686dd00207ec16ab1.txt +2 -0
- train/datasets/camera_obb/labels/val/68044adadc1f99dd2d091ac5c8f107c595d3dfe4.txt +3 -0
- train/datasets/camera_obb/labels/val/80fdea1b6d692db74f3904623dad229289fc654c.txt +2 -0
- train/datasets/camera_obb/labels/val/91dd2d6c11a95a8ab1fde7038ce8beeca2563f85.txt +3 -0
- train/datasets/camera_obb/labels/val/94e8132cb5b3d9c7a7db2e4c01358c7ce0a1ba2d.txt +3 -0
- train/datasets/camera_obb/labels/val/a474b6a2458d7036c7b1e4858a320feb77cd1d15.txt +3 -0
- train/datasets/camera_obb/labels/val/a529352554ef426512417388797069bce2d7ae61.txt +3 -0
- train/datasets/camera_obb/labels/val/aca23d3803f305e35173fffd661249cbeb86f282.txt +2 -0
- train/datasets/camera_obb/labels/val/b1627e6fc85ec2548deaaaa92a440f0b33e2569b.txt +2 -0
- train/datasets/camera_obb/labels/val/c0a2be2294bc04ece2457da1ce96e0d8e0bbab34.txt +3 -0
- train/datasets/camera_obb/labels/val/c1e1a508068bf406d5f8d5352888a7ddef501ea6.txt +2 -0
- train/datasets/camera_obb/labels/val/cb82349e33740e07c907a4de3efe22ea32558d52.txt +3 -0
- train/datasets/camera_obb/labels/val/e3bfd3635dbc0efcab18a5f251a641039481d7c9.txt +4 -0
- train/datasets/camera_obb/labels/val/e65982052a28bb225c41129bf520b636d3f5c993.txt +2 -0
- train/datasets/camera_obb/labels/val/ecd391135d962276d9695a3b92ca5bc99ab47472.txt +1 -0
- train/datasets/camera_obb/labels/val/eee25dbb6e5acfd232f3b06d2634622146508cff.txt +3 -0
- train/datasets/camera_obb/labels/val/f292d8e2973ceb973a7b69a22289e8615128ec1a.txt +3 -0
- train/datasets/camera_obb/labels/val/f927b4372f85162d0bad7059228d3490ffb48f79.txt +3 -0
- train/datasets/camera_obb/labels/val/fc0f3cdc42d1af9b05a1ff82f53147d3b9133b1c.txt +3 -0
- train/datasets/camera_obb/labels/val/ff05ed7bd591f1f3c07d87d9a50491eb5c28d36c.txt +1 -0
- train/requirements.txt +6 -0
- train/testObbOpenCv.py +311 -0
- train/trainObbModel.py +197 -0
train/datasets/camera_obb/labels/val.cache
ADDED
|
Binary file (16.8 kB). View file
|
|
|
train/datasets/camera_obb/labels/val/4835158c093e3ffd52342a423809364754226b2b.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.2634105936686198 0.1935646791811343 0.2954395548502604 0.1943834997106481 0.2945770772298177 0.3010044578269676 0.2625481160481771 0.3001856372974537
|
| 2 |
+
2 0.2549540456136068 0.06895374439380787 0.3694180043538411 0.06842640064380787 0.3703617095947266 0.7157927336516203 0.2558977508544922 0.7163200774016204
|
train/datasets/camera_obb/labels/val/53a01ff48d650b43cf17cc5fe1bf494aee25616c.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.3857922770182292 0.2871536327199348 0.5518802490234375 0.2918396719259108 0.5474978434244792 0.7824607957595897 0.3814098714192709 0.7777747565536137
|
| 2 |
+
1 0.4630966389973958 0.3610527797897845 0.5125653889973958 0.3584376692206939 0.5143194580078125 0.463243638169709 0.4648507080078125 0.4658587487387996
|
| 3 |
+
2 0.3695952555338541 0.9195484324089159 0.3863800048828125 0 0.9585496419270834 0.01745386372245318 0.9417649739583334 0.9520072756220379
|
train/datasets/camera_obb/labels/val/56c28acf11c5decc8d221f1ca2e3df6bd2d049d4.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.6469535827636719 0.007856623145532119 0.7689152956008911 0.01588265682907439 0.7596372365951538 0.3327922011189719 0.6376755237579346 0.3247661674354296
|
| 2 |
+
1 0.6916757822036743 0.1198771464178887 0.6943172216415405 0.05089098258737589 0.7366292476654053 0.05453261658876567 0.7339878082275391 0.123518791589695
|
train/datasets/camera_obb/labels/val/5c0d510a70c11ec736e414189db16f45ddb5fc9d.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.7914837837219239 0.5136481391059028 0.8466664314270019 0.5115435282389323 0.8488089561462402 0.6890873379177518 0.7936263084411621 0.6911919487847222
|
| 2 |
+
0 0.1983717083930969 0.2643807093302409 0.3806298494338989 0.2605639775594076 0.383868956565857 0.7494202507866754 0.2016108274459839 0.7532369825575087
|
| 3 |
+
1 0.2537240982055664 0.3423541598849826 0.3012538909912109 0.3068993462456597 0.3272118091583252 0.4168797810872396 0.2796820163726806 0.4523345947265625
|
| 4 |
+
2 0.7366658210754394 0.2537775039672852 0.9560970306396485 0.2454183154635959 0.9623207092285156 0.7617679172092013 0.7428895950317382 0.7701271057128907
|
train/datasets/camera_obb/labels/val/60768f20302a19d26b68b54686dd00207ec16ab1.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
1 0.6274074009486608 0.2644444329398019 0.6637037004743304 0.3488888876778739 0.6451851981026786 0.4922222137451172 0.6022222246442522 0.4033333369663784
|
| 2 |
+
2 0.3651851835704985 0.9755555289132255 0.4014814830961682 0.04777777876172747 0.7362962995256697 0.192222227369036 0.6488888695126488 0.9922222682407924
|
train/datasets/camera_obb/labels/val/68044adadc1f99dd2d091ac5c8f107c595d3dfe4.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.6829468308833607 0.2528458712811403 0.7991093685752467 0.2554823805501048 0.7967449522854989 0.5849879795973089 0.6805824145936129 0.5823514703283443
|
| 2 |
+
1 0.7417603074458607 0.3047691976038416 0.7694990726939419 0.3023852082012968 0.7712760523745888 0.3677826165781006 0.7435372871265077 0.3701666059806455
|
| 3 |
+
2 0.4695597330729167 0.7637564767727428 0.4879421301055373 0.006196005667985508 0.8794279399671052 0.03624256687491621 0.8610455429344847 0.7938030082238445
|
train/datasets/camera_obb/labels/val/80fdea1b6d692db74f3904623dad229289fc654c.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.1839114129543304 0.5449801146529103 0.3442055881023407 0.5420456747972329 0.3473124802112579 0.9568405966722329 0.1870182752609253 0.9597750365279103
|
| 2 |
+
2 0.1401884853839874 0.7399712715440124 0.1541937291622162 0 0.6873822212219238 0 0.7646484375 0.9709923664122138
|
train/datasets/camera_obb/labels/val/91dd2d6c11a95a8ab1fde7038ce8beeca2563f85.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.5491292953491211 0.005036898858532934 0.7265292485555013 0 0.7365162531534831 0.6719988246163923 0.5591162999471029 0.6857598036349176
|
| 2 |
+
1 0.6448446273803711 0.07216061346545191 0.7101897557576498 0.08525005957323634 0.7039388656616211 0.2502416919091505 0.6385937372843424 0.237152245801366
|
| 3 |
+
2 0.4242466608683268 0.9442284132906062 0.4336291631062826 0 0.7486366907755534 0 0.7392541885375976 0.9604403741345434
|
train/datasets/camera_obb/labels/val/94e8132cb5b3d9c7a7db2e4c01358c7ce0a1ba2d.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.43832794825236 0.4956274032592773 0.5842595100402832 0.4910593032836914 0.5907653172810873 0.8605449464586046 0.4448337554931641 0.8651130464341905
|
| 2 |
+
1 0.4882832368214925 0.6242245038350424 0.4909009138743083 0.5528739823235406 0.5458494822184244 0.5564578904045953 0.5432318051656088 0.627808411916097
|
| 3 |
+
2 0.3541666666666667 0.9565972222222222 0.1888020833333333 0.05034722222222222 0.81640625 0.5052083333333334 0.6666666666666666 0.9565972222222222
|
train/datasets/camera_obb/labels/val/a474b6a2458d7036c7b1e4858a320feb77cd1d15.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.4371829986572265 0.3666340611441721 0.6163790130615234 0.3680316860635554 0.6148435211181641 0.8115530962344629 0.4356475067138672 0.8101554713150797
|
| 2 |
+
1 0.5193661117553711 0.438187704748329 0.5729095077514649 0.437737441644436 0.5732589340209961 0.5313378883347503 0.5197155380249023 0.5317881514386433
|
| 3 |
+
2 0.1617824935913086 0.7529763513389717 0.178365592956543 0 0.7620236206054688 0 0.7454405212402344 0.7802020389635612
|
train/datasets/camera_obb/labels/val/a529352554ef426512417388797069bce2d7ae61.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.445787607828776 0.3697650372540509 0.5501012674967448 0.3702049424913195 0.5496566263834636 0.7034872775607639 0.4453429667154948 0.7030473723234953
|
| 2 |
+
1 0.4792294311523437 0.4853821252893519 0.4809566243489583 0.4248517975983797 0.5169183349609375 0.4280949797453704 0.5151911417643229 0.4886253074363426
|
| 3 |
+
2 0.2923527018229167 1 0.1658333333333333 0.3022222222222222 0.6783333333333333 0.07851851851851852 0.7097437540690105 1
|
train/datasets/camera_obb/labels/val/aca23d3803f305e35173fffd661249cbeb86f282.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.5129395167032877 0.07099106400101274 0.7655488967895507 0.06353409378616898 0.7728203455607097 0.8420400548864294 0.5202109654744466 0.8494970251012731
|
| 2 |
+
1 0.6076282501220703 0.3633958604600694 0.6105879465738933 0.2010808874059606 0.7084142049153646 0.2067185013382523 0.7054545084635416 0.3690334743923611
|
train/datasets/camera_obb/labels/val/b1627e6fc85ec2548deaaaa92a440f0b33e2569b.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.4356682002544403 0.06801519791285197 0.7278732657432556 0.06890211502710979 0.7268820405006409 0.6495235761006674 0.4346769154071808 0.6486366589864095
|
| 2 |
+
2 0.1624999940395355 0.5711111227671305 0.2783333361148834 0.1555555562178294 0.7056892514228821 0.07034533719221751 0.6966195702552795 0.5922128359476725
|
train/datasets/camera_obb/labels/val/c0a2be2294bc04ece2457da1ce96e0d8e0bbab34.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.4466235160827637 0.528122091293335 0.5309912681579589 0.5309156894683837 0.5293543179829915 0.9758451461791993 0.4449865659077962 0.973051643371582
|
| 2 |
+
1 0.476533317565918 0.6769670963287353 0.4775744756062826 0.5851541042327881 0.5057493845621744 0.5880296230316162 0.5047082265218099 0.6798426151275635
|
| 3 |
+
2 0.1989908377329508 0.9435964584350586 0.2131631374359131 0 0.5646679560343425 0.02329319417476654 0.5504956563313802 0.9899763107299805
|
train/datasets/camera_obb/labels/val/c1e1a508068bf406d5f8d5352888a7ddef501ea6.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
1 0.3092448276756084 0.2622222128965496 0.2800708061825913 0.04000000138856524 0.7312959654141317 0.06000000015428503 0.6496086728256361 0.2988888824432034
|
| 2 |
+
0 0.09335693089307937 0.03666666568952817 0.9121750553097345 0.04000000138856524 0.760470013913855 0.9788888713346815 0.114751225024198 0.9644444603529448
|
train/datasets/camera_obb/labels/val/cb82349e33740e07c907a4de3efe22ea32558d52.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.4388638973236084 0.4919513702392578 0.58342604637146 0.4872781117757162 0.5902125835418701 0.8604966481526692 0.4456504344940185 0.865169906616211
|
| 2 |
+
1 0.4875132560729981 0.6265329996744792 0.4890247344970703 0.5556292215983073 0.5451711654663086 0.5577570597330729 0.5436596870422363 0.6286608378092448
|
| 3 |
+
2 0.2868754386901856 0.9090583165486653 0.1350000023841858 0.02666666706403097 0.7983333110809326 0.4422222137451172 0.7233333110809326 0.9622222264607747
|
train/datasets/camera_obb/labels/val/e3bfd3635dbc0efcab18a5f251a641039481d7c9.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.3613726615905762 0.4235392570495605 0.4915069580078125 0.4217455863952637 0.4937459945678711 0.7105350494384766 0.3636117458343506 0.7123287200927735
|
| 2 |
+
0 0.7856846332550049 0.9481299718221029 0.825963020324707 0.9478384017944336 0.8262105941772461 1 0.785932207107544 1
|
| 3 |
+
1 0.3884547710418701 0.4672733306884765 0.4202221393585205 0.4679524103800456 0.4195156574249267 0.526711908976237 0.3877482414245605 0.526032829284668
|
| 4 |
+
2 0.283979082107544 0.795031992594401 0.3017405986785889 0.1728111267089844 0.8135955810546875 0.1987864176432292 0.7958340167999267 0.8210072835286458
|
train/datasets/camera_obb/labels/val/e65982052a28bb225c41129bf520b636d3f5c993.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.3148372904459635 0.09865843757750496 0.560060780843099 0.09010159931485615 0.5677359517415365 0.8881268213665675 0.322512461344401 0.8966835627480159
|
| 2 |
+
1 0.3833293151855469 0.3840068756587922 0.3866056823730469 0.2127370440770709 0.4801041158040364 0.2192262437608507 0.4768277486165365 0.3904960753425719
|
train/datasets/camera_obb/labels/val/ecd391135d962276d9695a3b92ca5bc99ab47472.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
0 0.5728878021240235 0.430283440483941 0.6786713600158691 0.4347163730197482 0.6739102363586426 0.7937912835015191 0.5681266784667969 0.7893583509657118
|
train/datasets/camera_obb/labels/val/eee25dbb6e5acfd232f3b06d2634622146508cff.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.5491292953491211 0.005036898858532934 0.7265292485555013 0 0.7365162531534831 0.6719988246163923 0.5591162999471029 0.6857598036349176
|
| 2 |
+
1 0.6448446273803711 0.07216061346545191 0.7101897557576498 0.08525005957323634 0.7039388656616211 0.2502416919091505 0.6385937372843424 0.237152245801366
|
| 3 |
+
2 0.4242466608683268 0.9442284132906062 0.4336291631062826 0 0.7486366907755534 0 0.7392541885375976 0.9604403741345434
|
train/datasets/camera_obb/labels/val/f292d8e2973ceb973a7b69a22289e8615128ec1a.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.5153091152106047 0.5150942690737612 0.5948823692832467 0.5121440165751689 0.5971620880807873 0.7062115093609235 0.5175888340081453 0.7091617618595157
|
| 2 |
+
1 0.5268022951199607 0.6156268695453265 0.5286383019499556 0.5505234726914414 0.5675753889412716 0.5539892798071508 0.5657393821112766 0.6190926766610361
|
| 3 |
+
2 0.3210640804762773 0.8932733209283502 0.3354901667782549 0 0.8460694597410624 0 0.8316433734390847 0.918549023877393
|
train/datasets/camera_obb/labels/val/f927b4372f85162d0bad7059228d3490ffb48f79.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.4444444675901237 0.2533333396911621 0.5142207227062446 0.2511111068725586 0.5036025844743227 0.33 0.4535456842936754 0.3266666793823242
|
| 2 |
+
1 0.4629607737674648 0.2924523162841797 0.464551645741121 0.2645793914794922 0.5033547984048368 0.2657676696777344 0.5017639264311807 0.2936405944824219
|
| 3 |
+
2 0.2411971889665102 0.4442596054077149 0.2634520026197206 0.03292970418930054 0.7079076148544156 0.04583231449127197 0.6856528012012052 0.4571622085571289
|
train/datasets/camera_obb/labels/val/fc0f3cdc42d1af9b05a1ff82f53147d3b9133b1c.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
0 0.3746675252914429 0.5141487121582031 0.4425457715988159 0.5148464441299438 0.4416691859563192 0.7067247629165649 0.3737909396489461 0.7060270309448242
|
| 2 |
+
1 0.384706695874532 0.5441105365753174 0.407295028368632 0.543700098991394 0.4076470136642456 0.5872790813446045 0.3850586811701457 0.5876895189285278
|
| 3 |
+
2 0.3042814135551453 1 0.3256328304608663 0.2897551953792572 0.6319967110951742 0.3097002804279327 0.6106452941894531 1
|
train/datasets/camera_obb/labels/val/ff05ed7bd591f1f3c07d87d9a50491eb5c28d36c.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
0 0.4927224245938388 0.5001363153148957 0.5120611364191229 0.500320252608603 0.5118539636785334 0.5492714877022998 0.4925152518532493 0.5490875504085925
|
train/requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Training
|
| 2 |
+
ultralytics
|
| 3 |
+
torch
|
| 4 |
+
ddgs
|
| 5 |
+
numpy
|
| 6 |
+
opencv-python
|
train/testObbOpenCv.py
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import math
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
|
| 5 |
+
import cv2
|
| 6 |
+
import numpy as np
|
| 7 |
+
|
| 8 |
+
REPO_DIR = Path(__file__).parent.parent
|
| 9 |
+
DEFAULT_MODEL = REPO_DIR / "model" / "best.onnx"
|
| 10 |
+
|
| 11 |
+
CLASSES = {
|
| 12 |
+
0: "Body",
|
| 13 |
+
1: "Lens",
|
| 14 |
+
2: "System",
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
COLORS = {
|
| 18 |
+
0: (76, 175, 80),
|
| 19 |
+
1: (33, 150, 243),
|
| 20 |
+
2: (255, 152, 0),
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def letterbox(
|
| 25 |
+
image: np.ndarray,
|
| 26 |
+
imageSize: int,
|
| 27 |
+
fillColor: tuple[int, int, int] = (114, 114, 114),
|
| 28 |
+
) -> tuple[np.ndarray, float, int, int]:
|
| 29 |
+
height, width = image.shape[:2]
|
| 30 |
+
scale = min(imageSize / width, imageSize / height)
|
| 31 |
+
|
| 32 |
+
resizedWidth = int(round(width * scale))
|
| 33 |
+
resizedHeight = int(round(height * scale))
|
| 34 |
+
|
| 35 |
+
resized = cv2.resize(
|
| 36 |
+
image,
|
| 37 |
+
(resizedWidth, resizedHeight),
|
| 38 |
+
interpolation=cv2.INTER_LINEAR,
|
| 39 |
+
)
|
| 40 |
+
|
| 41 |
+
padX = (imageSize - resizedWidth) // 2
|
| 42 |
+
padY = (imageSize - resizedHeight) // 2
|
| 43 |
+
|
| 44 |
+
canvas = np.full(
|
| 45 |
+
(imageSize, imageSize, 3),
|
| 46 |
+
fillColor,
|
| 47 |
+
dtype=np.uint8,
|
| 48 |
+
)
|
| 49 |
+
canvas[
|
| 50 |
+
padY : padY + resizedHeight,
|
| 51 |
+
padX : padX + resizedWidth,
|
| 52 |
+
] = resized
|
| 53 |
+
|
| 54 |
+
return canvas, scale, padX, padY
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def parseOutput(
|
| 58 |
+
output: np.ndarray,
|
| 59 |
+
confidenceThreshold: float,
|
| 60 |
+
scale: float,
|
| 61 |
+
padX: int,
|
| 62 |
+
padY: int,
|
| 63 |
+
imageShape: tuple[int, int, int],
|
| 64 |
+
) -> tuple[
|
| 65 |
+
list[tuple[tuple[float, float], tuple[float, float], float]], list[float], list[int]
|
| 66 |
+
]:
|
| 67 |
+
if output.ndim == 3:
|
| 68 |
+
output = output[0]
|
| 69 |
+
|
| 70 |
+
if output.shape[0] < output.shape[1]:
|
| 71 |
+
predictions = output.T
|
| 72 |
+
else:
|
| 73 |
+
predictions = output
|
| 74 |
+
|
| 75 |
+
classCount = len(CLASSES)
|
| 76 |
+
expectedValues = 5 + classCount
|
| 77 |
+
if predictions.shape[1] != expectedValues:
|
| 78 |
+
raise ValueError(
|
| 79 |
+
f"Expected {expectedValues} ONNX outputs per prediction, "
|
| 80 |
+
f"got {predictions.shape[1]}"
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
imageHeight, imageWidth = imageShape[:2]
|
| 84 |
+
boxes = []
|
| 85 |
+
scores = []
|
| 86 |
+
classIds = []
|
| 87 |
+
|
| 88 |
+
for prediction in predictions:
|
| 89 |
+
classScores = prediction[4 : 4 + classCount]
|
| 90 |
+
classId = int(np.argmax(classScores))
|
| 91 |
+
score = float(classScores[classId])
|
| 92 |
+
if score < confidenceThreshold:
|
| 93 |
+
continue
|
| 94 |
+
|
| 95 |
+
centerX, centerY, width, height = prediction[:4]
|
| 96 |
+
angleRadians = float(prediction[4 + classCount])
|
| 97 |
+
|
| 98 |
+
centerX = (float(centerX) - padX) / scale
|
| 99 |
+
centerY = (float(centerY) - padY) / scale
|
| 100 |
+
width = float(width) / scale
|
| 101 |
+
height = float(height) / scale
|
| 102 |
+
|
| 103 |
+
centerX = min(max(centerX, 0.0), float(imageWidth - 1))
|
| 104 |
+
centerY = min(max(centerY, 0.0), float(imageHeight - 1))
|
| 105 |
+
width = max(width, 1.0)
|
| 106 |
+
height = max(height, 1.0)
|
| 107 |
+
|
| 108 |
+
boxes.append(
|
| 109 |
+
(
|
| 110 |
+
(centerX, centerY),
|
| 111 |
+
(width, height),
|
| 112 |
+
math.degrees(angleRadians),
|
| 113 |
+
)
|
| 114 |
+
)
|
| 115 |
+
scores.append(score)
|
| 116 |
+
classIds.append(classId)
|
| 117 |
+
|
| 118 |
+
return boxes, scores, classIds
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
def runRotatedNms(
|
| 122 |
+
boxes: list[tuple[tuple[float, float], tuple[float, float], float]],
|
| 123 |
+
scores: list[float],
|
| 124 |
+
classIds: list[int],
|
| 125 |
+
confidenceThreshold: float,
|
| 126 |
+
nmsThreshold: float,
|
| 127 |
+
) -> list[int]:
|
| 128 |
+
keptIndexes = []
|
| 129 |
+
|
| 130 |
+
for classId in sorted(set(classIds)):
|
| 131 |
+
localIndexes = [
|
| 132 |
+
index for index, boxClassId in enumerate(classIds) if boxClassId == classId
|
| 133 |
+
]
|
| 134 |
+
localBoxes = [boxes[index] for index in localIndexes]
|
| 135 |
+
localScores = [scores[index] for index in localIndexes]
|
| 136 |
+
|
| 137 |
+
selected = cv2.dnn.NMSBoxesRotated(
|
| 138 |
+
localBoxes,
|
| 139 |
+
localScores,
|
| 140 |
+
confidenceThreshold,
|
| 141 |
+
nmsThreshold,
|
| 142 |
+
)
|
| 143 |
+
|
| 144 |
+
if len(selected) == 0:
|
| 145 |
+
continue
|
| 146 |
+
|
| 147 |
+
for selectedIndex in np.array(selected).flatten():
|
| 148 |
+
keptIndexes.append(localIndexes[int(selectedIndex)])
|
| 149 |
+
|
| 150 |
+
return keptIndexes
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
def drawDetections(
|
| 154 |
+
image: np.ndarray,
|
| 155 |
+
boxes: list[tuple[tuple[float, float], tuple[float, float], float]],
|
| 156 |
+
scores: list[float],
|
| 157 |
+
classIds: list[int],
|
| 158 |
+
indexes: list[int],
|
| 159 |
+
) -> np.ndarray:
|
| 160 |
+
output = image.copy()
|
| 161 |
+
|
| 162 |
+
for index in indexes:
|
| 163 |
+
classId = classIds[index]
|
| 164 |
+
color = COLORS.get(classId, (255, 255, 255))
|
| 165 |
+
label = f"{CLASSES.get(classId, classId)} {scores[index]:.2f}"
|
| 166 |
+
|
| 167 |
+
points = cv2.boxPoints(boxes[index])
|
| 168 |
+
points = np.intp(points)
|
| 169 |
+
|
| 170 |
+
cv2.polylines(output, [points], True, color, 2, cv2.LINE_AA)
|
| 171 |
+
|
| 172 |
+
labelX = int(points[:, 0].min())
|
| 173 |
+
labelY = int(points[:, 1].min()) - 8
|
| 174 |
+
labelY = max(labelY, 20)
|
| 175 |
+
|
| 176 |
+
textSize, baseline = cv2.getTextSize(
|
| 177 |
+
label,
|
| 178 |
+
cv2.FONT_HERSHEY_SIMPLEX,
|
| 179 |
+
0.6,
|
| 180 |
+
2,
|
| 181 |
+
)
|
| 182 |
+
textWidth, textHeight = textSize
|
| 183 |
+
|
| 184 |
+
cv2.rectangle(
|
| 185 |
+
output,
|
| 186 |
+
(labelX, labelY - textHeight - baseline),
|
| 187 |
+
(labelX + textWidth + 6, labelY + baseline),
|
| 188 |
+
color,
|
| 189 |
+
-1,
|
| 190 |
+
)
|
| 191 |
+
cv2.putText(
|
| 192 |
+
output,
|
| 193 |
+
label,
|
| 194 |
+
(labelX + 3, labelY),
|
| 195 |
+
cv2.FONT_HERSHEY_SIMPLEX,
|
| 196 |
+
0.6,
|
| 197 |
+
(255, 255, 255),
|
| 198 |
+
2,
|
| 199 |
+
cv2.LINE_AA,
|
| 200 |
+
)
|
| 201 |
+
|
| 202 |
+
return output
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
def getOutputPath(imagePath: Path, outputPath: Path | None) -> Path:
|
| 206 |
+
if outputPath:
|
| 207 |
+
return outputPath
|
| 208 |
+
|
| 209 |
+
return imagePath.with_name(f"{imagePath.stem}_obb{imagePath.suffix}")
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
def parseArgs() -> argparse.Namespace:
|
| 213 |
+
parser = argparse.ArgumentParser()
|
| 214 |
+
parser.add_argument("image", type=Path, help="Image to run inference on.")
|
| 215 |
+
parser.add_argument(
|
| 216 |
+
"--model",
|
| 217 |
+
type=Path,
|
| 218 |
+
default=DEFAULT_MODEL,
|
| 219 |
+
help="Path to the exported YOLO OBB ONNX model.",
|
| 220 |
+
)
|
| 221 |
+
parser.add_argument(
|
| 222 |
+
"--output",
|
| 223 |
+
type=Path,
|
| 224 |
+
default=None,
|
| 225 |
+
help="Path to save the image with bounding box overlays.",
|
| 226 |
+
)
|
| 227 |
+
parser.add_argument(
|
| 228 |
+
"--imgsz",
|
| 229 |
+
type=int,
|
| 230 |
+
default=960,
|
| 231 |
+
help="Input image size used when exporting the ONNX model.",
|
| 232 |
+
)
|
| 233 |
+
parser.add_argument(
|
| 234 |
+
"--conf",
|
| 235 |
+
type=float,
|
| 236 |
+
default=0.25,
|
| 237 |
+
help="Confidence threshold for detections.",
|
| 238 |
+
)
|
| 239 |
+
parser.add_argument(
|
| 240 |
+
"--iou",
|
| 241 |
+
type=float,
|
| 242 |
+
default=0.45,
|
| 243 |
+
help="Rotated NMS IoU threshold.",
|
| 244 |
+
)
|
| 245 |
+
return parser.parse_args()
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
def main() -> None:
|
| 249 |
+
args = parseArgs()
|
| 250 |
+
imagePath = args.image
|
| 251 |
+
modelPath = args.model
|
| 252 |
+
outputPath = getOutputPath(imagePath, args.output)
|
| 253 |
+
|
| 254 |
+
if not imagePath.exists():
|
| 255 |
+
raise FileNotFoundError(f"Image not found: {imagePath}")
|
| 256 |
+
|
| 257 |
+
if not modelPath.exists():
|
| 258 |
+
raise FileNotFoundError(f"ONNX model not found: {modelPath}")
|
| 259 |
+
|
| 260 |
+
image = cv2.imread(str(imagePath))
|
| 261 |
+
if image is None:
|
| 262 |
+
raise ValueError(f"Could not read image: {imagePath}")
|
| 263 |
+
|
| 264 |
+
inputImage, scale, padX, padY = letterbox(image, args.imgsz)
|
| 265 |
+
blob = cv2.dnn.blobFromImage(
|
| 266 |
+
inputImage,
|
| 267 |
+
scalefactor=1 / 255.0,
|
| 268 |
+
size=(args.imgsz, args.imgsz),
|
| 269 |
+
mean=(0, 0, 0),
|
| 270 |
+
swapRB=True,
|
| 271 |
+
crop=False,
|
| 272 |
+
)
|
| 273 |
+
|
| 274 |
+
net = cv2.dnn.readNetFromONNX(str(modelPath))
|
| 275 |
+
net.setInput(blob)
|
| 276 |
+
output = net.forward()
|
| 277 |
+
|
| 278 |
+
boxes, scores, classIds = parseOutput(
|
| 279 |
+
output,
|
| 280 |
+
args.conf,
|
| 281 |
+
scale,
|
| 282 |
+
padX,
|
| 283 |
+
padY,
|
| 284 |
+
image.shape,
|
| 285 |
+
)
|
| 286 |
+
keptIndexes = runRotatedNms(
|
| 287 |
+
boxes,
|
| 288 |
+
scores,
|
| 289 |
+
classIds,
|
| 290 |
+
args.conf,
|
| 291 |
+
args.iou,
|
| 292 |
+
)
|
| 293 |
+
|
| 294 |
+
result = drawDetections(
|
| 295 |
+
image,
|
| 296 |
+
boxes,
|
| 297 |
+
scores,
|
| 298 |
+
classIds,
|
| 299 |
+
keptIndexes,
|
| 300 |
+
)
|
| 301 |
+
|
| 302 |
+
outputPath.parent.mkdir(parents=True, exist_ok=True)
|
| 303 |
+
if not cv2.imwrite(str(outputPath), result):
|
| 304 |
+
raise ValueError(f"Could not write output image: {outputPath}")
|
| 305 |
+
|
| 306 |
+
print(f"Detections: {len(keptIndexes)}")
|
| 307 |
+
print(f"Saved: {outputPath}")
|
| 308 |
+
|
| 309 |
+
|
| 310 |
+
if __name__ == "__main__":
|
| 311 |
+
main()
|
train/trainObbModel.py
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import random
|
| 3 |
+
import shutil
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
import torch
|
| 7 |
+
import yaml
|
| 8 |
+
from ultralytics import YOLO
|
| 9 |
+
|
| 10 |
+
classes = {
|
| 11 |
+
0: "Body",
|
| 12 |
+
1: "Lens",
|
| 13 |
+
2: "System",
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
# ~/Outflock
|
| 17 |
+
REPO_DIR = Path(__file__).parent.parent
|
| 18 |
+
IMAGES_DIR = REPO_DIR / "train/data/images"
|
| 19 |
+
LABELS_DIR = REPO_DIR / "train/data/labels"
|
| 20 |
+
DATASET_DIR = REPO_DIR / "train/datasets/camera_obb"
|
| 21 |
+
RUNS_DIR = REPO_DIR / "train/runs"
|
| 22 |
+
|
| 23 |
+
ONNX_DIR = REPO_DIR / "model"
|
| 24 |
+
|
| 25 |
+
valRatio = 0.2
|
| 26 |
+
seed = 42
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def hasValidLabel(imagePath: Path) -> bool:
|
| 30 |
+
labelPath = LABELS_DIR / f"{imagePath.stem}.txt"
|
| 31 |
+
if not labelPath.exists():
|
| 32 |
+
return False
|
| 33 |
+
|
| 34 |
+
lines = labelPath.read_text().strip().splitlines()
|
| 35 |
+
if not lines:
|
| 36 |
+
return False
|
| 37 |
+
|
| 38 |
+
for line in lines:
|
| 39 |
+
parts = line.split()
|
| 40 |
+
if len(parts) != 9:
|
| 41 |
+
return False
|
| 42 |
+
|
| 43 |
+
classId = int(parts[0])
|
| 44 |
+
if classId not in classes:
|
| 45 |
+
return False
|
| 46 |
+
|
| 47 |
+
coords = [float(value) for value in parts[1:]]
|
| 48 |
+
if any(value < 0 or value > 1 for value in coords):
|
| 49 |
+
return False
|
| 50 |
+
|
| 51 |
+
return True
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def copyExample(imagePath: Path, split: str) -> None:
|
| 55 |
+
labelPath = LABELS_DIR / f"{imagePath.stem}.txt"
|
| 56 |
+
|
| 57 |
+
imageOut = DATASET_DIR / "images" / split / imagePath.name
|
| 58 |
+
labelOut = DATASET_DIR / "labels" / split / labelPath.name
|
| 59 |
+
|
| 60 |
+
imageOut.parent.mkdir(parents=True, exist_ok=True)
|
| 61 |
+
labelOut.parent.mkdir(parents=True, exist_ok=True)
|
| 62 |
+
|
| 63 |
+
shutil.copy2(imagePath, imageOut)
|
| 64 |
+
shutil.copy2(labelPath, labelOut)
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def prepareDataset() -> Path:
|
| 68 |
+
if DATASET_DIR.exists():
|
| 69 |
+
shutil.rmtree(DATASET_DIR)
|
| 70 |
+
|
| 71 |
+
imagePaths = sorted(
|
| 72 |
+
path
|
| 73 |
+
for path in IMAGES_DIR.iterdir()
|
| 74 |
+
if path.suffix.lower() in {".jpg", ".jpeg", ".png", ".webp"}
|
| 75 |
+
and hasValidLabel(path)
|
| 76 |
+
)
|
| 77 |
+
|
| 78 |
+
random.Random(seed).shuffle(imagePaths)
|
| 79 |
+
|
| 80 |
+
valCount = max(1, int(len(imagePaths) * valRatio))
|
| 81 |
+
valImages = set(imagePaths[:valCount])
|
| 82 |
+
trainImages = imagePaths[valCount:]
|
| 83 |
+
|
| 84 |
+
for imagePath in trainImages:
|
| 85 |
+
copyExample(imagePath, "train")
|
| 86 |
+
|
| 87 |
+
for imagePath in valImages:
|
| 88 |
+
copyExample(imagePath, "val")
|
| 89 |
+
|
| 90 |
+
dataYaml = DATASET_DIR / "data.yaml"
|
| 91 |
+
dataYaml.write_text(
|
| 92 |
+
yaml.safe_dump(
|
| 93 |
+
{
|
| 94 |
+
"path": str(DATASET_DIR.resolve()),
|
| 95 |
+
"train": "images/train",
|
| 96 |
+
"val": "images/val",
|
| 97 |
+
"names": classes,
|
| 98 |
+
},
|
| 99 |
+
sort_keys=False,
|
| 100 |
+
)
|
| 101 |
+
)
|
| 102 |
+
|
| 103 |
+
print(f"Prepared {len(trainImages)} train and {len(valImages)} val images")
|
| 104 |
+
return dataYaml
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def trainModel(dataYaml: Path, onnx: bool = False) -> None:
|
| 108 |
+
print(f"CUDA available: {torch.cuda.is_available()}")
|
| 109 |
+
if torch.cuda.is_available():
|
| 110 |
+
print(f"GPU: {torch.cuda.get_device_name(0)}")
|
| 111 |
+
|
| 112 |
+
model = YOLO("yolov8m-obb.pt")
|
| 113 |
+
model.train(
|
| 114 |
+
data=str(dataYaml),
|
| 115 |
+
epochs=50,
|
| 116 |
+
imgsz=960,
|
| 117 |
+
project=str(RUNS_DIR),
|
| 118 |
+
name="flockOBB",
|
| 119 |
+
task="obb",
|
| 120 |
+
batch=16,
|
| 121 |
+
device=0,
|
| 122 |
+
workers=8,
|
| 123 |
+
patience=20,
|
| 124 |
+
pretrained=True,
|
| 125 |
+
optimizer="auto",
|
| 126 |
+
amp=True,
|
| 127 |
+
# Detection-specific defaults worth making explicit.
|
| 128 |
+
single_cls=False,
|
| 129 |
+
rect=False,
|
| 130 |
+
cache=False,
|
| 131 |
+
# Augmentation. Conservative for real camera detection.
|
| 132 |
+
degrees=5,
|
| 133 |
+
translate=0.08,
|
| 134 |
+
scale=0.4,
|
| 135 |
+
shear=0.0,
|
| 136 |
+
perspective=0.0005,
|
| 137 |
+
flipud=0.0,
|
| 138 |
+
fliplr=0.5,
|
| 139 |
+
mosaic=0.7,
|
| 140 |
+
mixup=0.05,
|
| 141 |
+
copy_paste=0.0,
|
| 142 |
+
)
|
| 143 |
+
|
| 144 |
+
if not onnx:
|
| 145 |
+
return
|
| 146 |
+
|
| 147 |
+
# Optional: export to ONNX and weights for OpenCV later.
|
| 148 |
+
bestWeights = Path(model.trainer.best)
|
| 149 |
+
if not bestWeights.exists():
|
| 150 |
+
saveDir = Path(model.trainer.save_dir)
|
| 151 |
+
bestWeights = saveDir / "weights" / "best.pt"
|
| 152 |
+
|
| 153 |
+
if not bestWeights.exists():
|
| 154 |
+
raise FileNotFoundError(f"Could not find trained best weights at {bestWeights}")
|
| 155 |
+
|
| 156 |
+
print(f"Best weights saved to: {bestWeights}")
|
| 157 |
+
|
| 158 |
+
exportModel = YOLO(str(bestWeights))
|
| 159 |
+
onnxPath = Path(
|
| 160 |
+
exportModel.export(
|
| 161 |
+
format="onnx",
|
| 162 |
+
imgsz=960,
|
| 163 |
+
opset=12,
|
| 164 |
+
simplify=True,
|
| 165 |
+
dynamic=False,
|
| 166 |
+
)
|
| 167 |
+
)
|
| 168 |
+
|
| 169 |
+
ONNX_DIR.mkdir(parents=True, exist_ok=True)
|
| 170 |
+
targetPath = ONNX_DIR / onnxPath.name
|
| 171 |
+
shutil.copy2(onnxPath, targetPath)
|
| 172 |
+
print(f"ONNX model copied to: {targetPath}")
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
def parseArgs() -> argparse.Namespace:
|
| 176 |
+
parser = argparse.ArgumentParser()
|
| 177 |
+
parser.add_argument(
|
| 178 |
+
"--onnx",
|
| 179 |
+
action="store_true",
|
| 180 |
+
help="Export the trained best weights to ONNX after training.",
|
| 181 |
+
)
|
| 182 |
+
parser.add_argument(
|
| 183 |
+
"--clean",
|
| 184 |
+
action="store_true",
|
| 185 |
+
help="Clean Non-ONNX model directories.",
|
| 186 |
+
)
|
| 187 |
+
return parser.parse_args()
|
| 188 |
+
|
| 189 |
+
|
| 190 |
+
if __name__ == "__main__":
|
| 191 |
+
args = parseArgs()
|
| 192 |
+
dataYaml = prepareDataset()
|
| 193 |
+
trainModel(dataYaml, onnx=args.onnx)
|
| 194 |
+
|
| 195 |
+
if args.clean:
|
| 196 |
+
shutil.rmtree(RUNS_DIR)
|
| 197 |
+
print(f"Removed Non-ONNX model directory: {RUNS_DIR}")
|