czech english

OAK-D Pro

chytrá 3D OpenCV kamera

Co když zkombinujete stereo-kameru s malým počítačem s podporou pro výpočet neuronek? Přidáte-li možnost nasvícení scény a vše to zabalíte do malé krabičky tak dostanete OAK-D od firmy Luxonis. Ale to rozhodně není vše … Blog update: 18/3/2024 — Debugging DepthAI pipeline

Obsah



Blog

22. březen 2022 — Měsíc čekání

Jak začít? O OAK-D jsem poprvé slyšel od týmu Sĺňava (Robotour 2021). Pak jsem se cca před měsícem dozvěděl o existenci firmy Luxonis a rozhodl si udělat představu „z první ruky”. Doporučení jsem dostal na novou kameru OAK-D Pro, která je zatím zařazena v beta programu. Byl jsem i varován, že doručení bude nějaký čas trvat (expeduje se z Hong Kongu).
Vlastně mne velmi potešilo, když objednávka byla ještě ten den potvrzena a druhý den expedována … tak to třeba nebude tak dlouho trvat? Ale trvalo. Přes týden to viselo v Belgii na celnici (to je ta „výhoda” online sledování — člověk se může permanentně nervovat, místo aby počítal s dlouhou dobou a pak byl překvapen) a vrchol byl pak v Čechách. Z adresy vypadly všechny znaky s diakritikou (na rovinu bych jí nepoužíval, ale mám pocit, že tam byla nějaká nápověda pro dohledání adresy, ale už je to dlouho, takže ani tím si nejsem jist). V každém případě „tracking number” není to samé v ČR a pokud ho nemáte, tak se dohledává podle adresy. Zkrátím to, skončilo to v koši „nedoručitelné”, ale po dvou dnech telefonování a „intervencí” se balíček na depu v Praze našel. Doporučení: odmažte diakritiku.
A když už jsem měl krabičku doma, tak jsem se zase nemohl rozhoupat jí vůbec otevřít. Začal jsem totiž pořádně „listovat” dokumentací a narazil jsem na: Due to the large power consumption of dot projector/illumination LED, a Y-adapter is required when using these functions! F-slovo. Znamená to, že teď budu muset objednávat nějaky Y-adaptér, abych si mohl kameru vůbec pustit?! To mi asi vzalo trošku vítr z plachet. Pak jsem alespoň otevřel krabičku a našel jsem tam toto:
Obsah krabičky
Obsah krabičky
Vlastně tedy dobrá a špatná zpráva:
  • Y-adaptér je součástí balení
  • trošku to vypadá, že tam něco chybí, třeba kabel?
Kabel tam byl — pod krabičkou. Ale jestli tam má být takto poloprázdná krabička úplně nevím. Na druhou stranu i druhý kus vypadal stejně.
A teď dobré zprávy — First steps with DepthAI … prostě návod co udělat od zapojení nové kamery do USB konektoru. A fungovalo to bezchybně!
p.s. a ano, na extra přísvit a extra zdroj dojde někdy později … tj. na první pokusy nebyl nutný.

25. březen 2022 — Druhý krok

První krok byl snadný, ale co bude druhý krok? Napsal bych si nějaky mini-prográmek, ale jaký? Konečně jsem začal více koukat do dokumentace API a užitečný mi přijde tento obrázek:

Host je váš počítač a OAK Device je „chytrá kamera” … stále nevím, co OAK (v překladu dub) znamená? Node, connection a pipeline připomíná klasický robotický systém, jenom to vše běží přímo na „kameře” a nejspíše se to musí připravit předem. XLink pak zajišťuje komunikaci tam a zpět.
Kameru mám zatím zapojenou přímo do notebooku a tak její chytrost úplně nevyužiji. Co by mi ale přišlo zajímavé vyzkoušet je, co když se XLink přeruší? Jede pipeline vesele dál? Pak by paradoxně Y-adaptér, na který jsem ještě nedávno „nadával”, byl přesně ten kousek HW, který by mi průběžné odpojování od počítače umožnil. Možná.
Koukal jsem tedy na standalone mode a chyba lávky: Standalone mode is only possible on OAKs that have on-board flash memory, which are currently OAK IOT and OAK POE camera models. Je tady asi na místě zdůraznit, že Luxonis nabízí několik řad zařízení a tak bych doporučil si to předem nastudovat a volit podle plánované aplikace.
A co by to „offline” resp. „nezávisle” dělalo? Může si kamera po začátek pamatovat několik obrázků nebo dokonce video? Podle příkladu RAM usage: All OAK devices have 512 MiB (4 Gbit) on-board RAM, which is used for firmware (about 15MB), assets (a few KB up to 100MB+, eg. NN models), and other resources, such as message pools where messages are stored. … teď jsem si říkal, co je ten 4 Gbit? Rychlost? Jiný model? Well … 8x 512MB = 4G bitu … asi.
Vypadá to, že můžu rovnou použít demo system_information.py:
Ddr used / total - 0.13 / 339.99 MiB
Cmx used / total - 2.06 / 2.50 MiB
LeonCss heap used / total - 7.54 / 78.28 MiB
LeonMss heap used / total - 2.95 / 41.54 MiB
Chip temperature - average: 24.12, css: 25.67, mss: 23.69, upa: 23.44, dss: 23.69
Cpu usage - Leon CSS: 10.64%, Leon MSS: 1.98 %
Kód je kratký, jen si teď neumím představit, jak otevřít dai.Device bez pipeline, která pro nastartování obsahuje dva uzly: dai.node.SystemLogger a dai.node.XLinkOut. I to prolinkování sysLog.out.link(linkOut.input) vypadá přímočaře.
p.s. tak schválně, jestli mi někdo poradí: Reconnection to running OAK device?

28. březen 2022 — Standalone mode

Na odpověď jsem nemusel dlouho čekat — Hussain psal: What I understood is that you want to run the OAK in standalone mode. If that was the case, check this documentation.
A pak se ještě ozval Erik: ... that's not possible, after you terminate the connection with the device, the device will remove the pipeline/assets to be ready for the next connection. As Hussain mentioned, if you would like to run pipeline in standalone mode, check the docs page he linked. This still wouldn't allow you to do exactly what you want, but you could eg. stream results via WiFi (OAK IoT) or ethernet (OAK PoE) to the server.
Nešlo by to nějak obejít, když OAK IoT ani PoE nemám? Mimochodem „test komunity” bych považoval za úspěšný. Mám v plánu někdy revidovat úvodní odstavec a doplnit tam, např. že Luxonis má za sebou úspěšnou Kickstarterovou kampaň opencv-ai-kit-lite ($1,136,926 USD by 8,640 backers) [je tam takové množství projektů, až na mne zase padá depka a jestli se mám vůbec o něco snažit ] Také přemýšlím, jestli O=OpenCV, A=Ai, K=Kit??
No nic, zpět k Standalone modeyou first need to remove all XLinkOut and XLinkIn nodes. No jo, ale co dál? SPIOut nepoužiji, protože nemám SPI, a script node jede přes ten Ethernet.
Koukám, že OAK-D Pro má přímo dedikované issue … hledal jsem, jak se vypíná/zapíná podsvícení. Asi vyjímečně nemá cenu hledat přes Google, a je rychlejší proklikat dokumentaci, tj. v Device jsou funkce setIrFloodLightBrightness() a setIrLaserDotProjectorBrightness().
Ale to jsem se „trošku” odchýlil od tématu, ke kterému vlastně nemám více jak „tudy ne”.

29. březen 2022 — IMU a SLAM

Teď je ráno, na rozdíl od včerejšího zápisu, tak je naděje, že budu mít více optimismu než po práci. Navíc téma je snad přímočaré a měly by k tomu být rovnou funkční příklady. Motivace je náhrada Realsense T264 tracking kamery (Limited Lifetime Product) za OAK-D.
Ještě co jsem o víkendu (?) tak narychlo procházel, tak IMU do SLAMu zatím integrovaná není, tak to může být takový self-test, jak jsou oba výstupy konzistentní. No asi jsem zase naivní, ale uvidíme.
Nejprve tedy IMU (Inertial Measurement Unit). K dispozici jsou hned dva příklady:
První bych viděl na raw data a druhý jako integraci. Píšou tam nějaké „nezdravé” Herzy (500Hz a 400Hz), ale to se může časem hodit.
Tak jo, první příklad fungoval bez problémů:
Accelerometer timestamp: 5613.242 ms
Accelerometer [m/s^2]: x: 5.200206 y: 0.019154 z: -8.820239
Gyroscope timestamp: 5613.925 ms
Gyroscope [rad/s]: x: 0.014914 y: 0.003196 z: -0.008522
Accelerometer timestamp: 5615.379 ms
Accelerometer [m/s^2]: x: 5.190629 y: 0.000000 z: -8.820239
Gyroscope timestamp: 5616.424 ms
Gyroscope [rad/s]: x: 0.009587 y: 0.001065 z: -0.005326
a druhý stejně tak:
Rotation vector timestamp: 2707.787 ms
Quaternion: i: 0.000305 j: -0.964600 k: -0.001465 real: 0.263672
Accuracy (rad): 3.141602
Rotation vector timestamp: 2709.946 ms
Quaternion: i: 0.000305 j: -0.964600 k: -0.001465 real: 0.263672
Accuracy (rad): 3.141602
SLAM (Simultaneous Localization And Mapping) jsem na stejné stránce mezi příklady nenašel, ale byl „hned vedle” na stránce věnované Spatial AI:
  • SLAM with OAK … tak to asi nebude jen „copy and paste”: We plan on creating our own visual-inertial SLAM project that would use on-device feature tracking (using FeatureTracker node) and intertial data (using IMU node), if the device has an IMU sensor onboard.
Jsou tam ale odkazy na community projects: OAK-D ORB_SLAM3 Experiment a deptha-slam … (ještě tam byl ArduCam SLAM). Hmm, tak asi zatím nic. Nevýhoda „ranního hraní” spočívá v tom, že v tom nejlepším toho člověk musí nechat a „jít do práce”. V tomto experimentu alespoň vidím jistou naději. To be continued

7. září 2022 — FollowMe a USB kabel (Jirka)

Tentokrát blog posunul Jirka …
Jirka si koupil OAK-D W (Wide), tedy verzi s širokým záběrem a jako demo aplikaci si vymyslel starý dobrý FollowMe co před 10+ lety vylepšil (resp. udělal použitelný) na Eduru (viz staré video z Floriade … takže tady to bylo 10 let). Je sranda jak ty děti dokážou poměrně rychle dostat robota do neřešitelné situace.
Jinak v tomto demo je OAK-D kamera použita pouze jako zdroj hloubkových dat (podobně jako dřive byl RealSense) a veškerý processing probíhá na hlavním počítači. Bude-li ver2, tak možná zkombinuje i detekci osob a alternativní výběr objektu pro sledování, uvidíme … Jirka si určítě něco vymyslí.
Další info od Jirky bylo o GPS (možná dodá i extra článk o stereo-GPS pro získání absolutního směru robota). Vše prý fungovalo krásně až do okamžiku, kdy k robotovi připojil kameru. A ano, problém byl „klasicky” USB 3, tentokrát ale řešitelný kabelem:
Zdar, kdybyste potřebovali k OAK-D kabel, kolem kterého může fungovat GPS, mám teď dobrou zkušenost s: https://www.delock.com/produkt/84007/merkmale.html Koukám, že má i další sourozence: 83718, 84017, 84019]. Ty ale vyzkoušené nemám. Myšlenkový pochod byl: Vysoká přenosová rychlost nejspíš potřebuje lepší stínění, šrouby lépe utáhnou kontakt, s kratším kabelem bude méně potíží. Pořád bych pak nedával GPS přímo ke kameře, ale v mém případě, kdy je anténa necelý metr od kamery, výměna kabelu, se kterou kamera přišla, za tenhle, převedla GPS ze stavu "při puštěné kameře vůbec nefunguje" do "funguje perfektně, bez výpadků".
… třeba se to bude někomu hodit např. na Robotour.

8. října 2022 — SLAM na 6 řádek

Na posledním robotickém callu Jirka zmínil, že jen tak mimochodem se mu podařilo pustit SLAM na OAK-D kameře bez velkých problémů … cože?!
Tak nejprve oprava, že „obrázek je pouze ilustrativní” a „reklama je zavádějící” … není to úplně SLAM (Simultaneous Localization and Mapping, tj. současná lokalizace a mapování), ale visual odometry, tj. odometrie z kamery. Jirka to asi říkal, ale já si zapamatoval SLAM, pardón. A těch řádků je o něco více, ale to by se dalo okecat:
import depthai
import spectacularAI
import time

pipeline = depthai.Pipeline()

vio_pipeline = spectacularAI.depthai.Pipeline(pipeline)
# optional config args: vio_pipeline = spectacularAI.depthai.Pipeline(pipeline, config, useStereo=False)

with depthai.Device(pipeline) as device, \
    vio_pipeline.startSession(device) as vio_session:

    while True:
        out = vio_session.waitForOutput()
        print(out.asJson())
Rozchození bylo přímočaré, ještě než mi vystydlo kafe:
mkvirtualenv slam
workon slam
pip install depthai
pip install spectacularAI
a pak už puštění skriptu výše:
(slam) md@md-ThinkPad-P50:~/git/slam$ python vio_slam.py
Traceback (most recent call last):
  File "vio_slam.py", line 10, in 
    with depthai.Device(pipeline) as device, \
RuntimeError: No available devices
Já vlastně nevím, proč to dělám … prostě zvyk, aneb co se stane, když tam žádná kamera není? BTW kam jsem jí sakra dal?! Ano, už je lehce „zaprášená”…
Na druhý pokus (s připojenou OAK-D PRO kamerou přes USB) už to vypadalo lépe:
(slam) md@md-ThinkPad-P50:~/git/slam$ python vio_slam.py
Spectacular AI SDK: WARN: unrecoginzed OAK board name 'OAK-D-PRO'
you may need to manually set IMU-to-camera extrinsics (configuration.imuToCameraLeft)
{
  "acceleration":{"x":3.1929334554640985e-06,"y":-1.8542926966551022e-06,"z":-4.7221780476648234e-07},
  "angularVelocity":{"x":0.0015828333562240005,"y":0.012700891122221947,"z":0.00035301301977597177},
  "orientation":{"w":0.20955791688410802,"x":0.6385671367191919,"y":-0.7166392482573564,"z":-0.18640114051633144},
  "position":{"x":0.006880179754191055,"y":-0.02585324999779014,"z":-0.0037064156909441524},
  "status":"TRACKING","time":343134.285796941,
  "velocity":{"x":-0.1518426175218836,"y":0.050841540677380274,"z":0.0363924090447811}
}
…
Pak jsem si nechal vypisovat jen pozice a trošku mával kamerou nad stolem:
{'x': -9.319226940036552, 'y': 1.5651737606558058, 'z': -5.689111896116633}
{'x': -9.724962378082667, 'y': 1.683750553335214, 'z': -5.987711949231651}
{'x': -10.173431395097694, 'y': 1.8181065640771044, 'z': -6.323567343157043}
{'x': -10.596265664774739, 'y': 1.947684970617886, 'z': -6.645771182786724}
{'x': -11.028292374467366, 'y': 2.0827255306275148, 'z': -6.980379856466121}
{'x': -11.50425102807769, 'y': 2.2345457195224334, 'z': -7.355377866839724}
{'x': -11.956292577500529, 'y': 2.3815888137119883, 'z': -7.717576736330567}
hmm, to moc nevypadá jako v metrech?! No asi je třeba udělat ten první krok pořádně a nastudovat si readme. Jak znám Jirku, tak u tohoto povrchního pokusu rozhodně nezůstal a více to prozkoumal. Konkrétně ještě posílal link na vio_gnss.py, což by měla být kombinace GPS s vizuální odometrii a to má to blízko k jeho článku o Ardusimple RTK3B.

22. ledna 2024 — OSGAR driver

V rámci vytahování „kostlivců ze skříně”, aneb co vše by se hodilo na nového robota, došlo znova na OAK-D kamery. Chěl jsem si napsat driver pro OSGARa, ale Jakub mne minulý týden dostal, že už přece dávno existuje!
Ano, je tam nějaký config/test-oak-camera.json, ale uvnitř jsem viděl IP adresu, tak jsem předpokládal, že bude fungovat pouze na PoE kamery, co Jakub na ČZU používá. A není tomu tak.
(osgar) md@md-ThinkPad-P50:~/git/osgar$ cat config/test-oak-camera.json
{
  "version": 2,
  "robot": {
    "modules": {
      "app": {
          "driver": "osgar.drivers.oak_camera:OakCamera",
          "init": {
            "fps": 10,
            "is_color": true,
            "is_depth": true,
            "laser_projector_current": 1200,
            "is_imu_enabled": true,
            "number_imu_records": 10,
            "disable_magnetometer_fusion": false,
            "cam_ip": "169.254.1.222",

            "mono_resolution": "THE_400_P",
            "color_resolution": "THE_1080_P",
            "color_manual_focus": 130,

            "stereo_median_filter": "KERNEL_3x3",
            "stereo_mode": "HIGH_ACCURACY",
            "stereo_extended_disparity": false,
            "stereo_subpixel": false,
            "stereo_left_right_check": true
          }
      }
    },
    "links": []
  }
}
po spuštění:
(osgar) md@md-ThinkPad-P50:~/git/osgar$ python -m osgar.record –duration 10 config/test-oak-camera.json
2024-01-17 23:10:13,192 __main__   INFO     /home/md/git/osgar/test-oak-camera-240117_221013.log
2024-01-17 23:10:13,230 __main__   INFO     SIGINT handler installed
2024-01-17 23:10:13,752 osgar.drivers.oak_camera WARNING  IP 169.254.1.222 was not found!
2024-01-17 23:10:13,752 osgar.drivers.oak_camera INFO     Found devices: 1.6
2024-01-17 23:10:13,752 osgar.drivers.oak_camera INFO     Used the first available device.
a následně:
(osgar) md@md-ThinkPad-P50:~/git/osgar$ python -m osgar.logger test-oak-camera-240117_221013.log
 k                 name    bytes | count | freq Hz
----------
 0                  sys      803 |  5 |   0.5Hz
 1            app.depth 36361514 | 71 |   6.7Hz
 2            app.color 25732424 | 71 |   6.7Hz
 3 app.orientation_list    38570 | 70 |   6.6Hz

Total time 0:00:10.574191
Na první pohled to vypadá, že je tam vše … tak asi není co dělat.
p.s. přidám si sem ještě poznámku, že na druhém počítači to tak snadné nebylo:
[2024-01-26 16:19:36.660] [depthai] [warning] Insufficient permissions to communicate with X_LINK_UNBOOTED
                                              device having name "1.3". Make sure udev rules are set

RuntimeError: No available devices
a hodí se použít instalační skript, který obsahuje:
# Allow all users to read and write to Myriad X devices
    echo "Installing udev rules…"
    echo 'SUBSYSTEM"usb", ATTRS{idVendor}"03e7", MODE="0666"' |
                 sudo tee /etc/udev/rules.d/80-movidius.rules > /dev/null
    sudo udevadm control –reload-rules && sudo udevadm trigger
… případně viz instalační návod
p.s.2 ještě úplně výhra to není, protože na Patovi to teď funguje, jen když nejprve připojím kameru a pak PCAN

10. února 2024 — Two Towers

Dnes jsem si konečně chvíli hrál s Patem, jenom jízda 1 metr tam a zpět. Vpředu má teď namontovanou OAK-D kameru s úhlem 20 stupňů dolů (viz Multi Angle Joint). Další úloha je vcelku triviální: jezdi tam a zpět, ale pokud bude v cestě překážka, tak zastav. A to, že je cesta blokovaná překážkou má program zjistit z hloubkových OAK-D dat.
A teď se už pomalu dostáváme k zápletce o „Dvou věžích”. Do cesty jsem si dal dopravní kužel (to je zase jiná hra, který z robotů Pat nebo Rocker první dokáže 30 minut jezdit od kuželu ke kuželu, přímá viditelnost). A když se koukám na nasbíraná data, tak vidím toto:
Hmm, je to očekávané?? Možná ano, ale mne to minimálně překvapilo.

26. února 2024 — Staronoví manažeři a přehrávání videa

Bude to už pomalu 14 dní, co jsem zkoušel následující kód z luxonis webu:
from depthai_sdk import OakCamera
with OakCamera(replay='https://www.youtube.com/watch?v=Y1jTEyb3wiI') as oak:
    oak.replay.set_loop(True)  # <— Enable looping of the video, so it will never end
    color = oak.create_camera('color')
    nn = oak.create_nn('vehicle-detection-0202', color)
    oak.visualize(nn, fps=True)
    oak.start(blocking=True)
Tenkrát mi to padalo na oak.replay.set_loop(True), ale když jsem tento řádek zakomentoval, tak to na připojené OAK-D kameře v reálném čase detekovalo autíčka z YouTube videa.
A dnes jsem řešil detekci kuželu (na PC fungovala, na OAK-D zatím stále nikoliv) a narazil v dokumentaci na výměnu manažerů:
vs.
Stará detekce kuželů dále odkazovala na Yolov7 Luxonis Detection (asi fork) a tam v main.py půlka importů nefungovala. Vysvětlení je částečně na diskusním fóru cca před rokem.
A co bylo tedy špatně na mém kódu? Verze depthai-sdk. Používal jsem github DepthAI, ale fakticky jsem měl i balíček nainstalovaný (verze 1.9.4). Po upgrade na nejnovější (verze 1.13.1) už set_loop() funguje a stejně tak třeba nastavení konfigurace kamery … ale to snad příště.

4. března 2024 — Detekce kuželu pomocí YoloV7

Trošku se děsím, že se dostávám do vývojové fáze mých studentů před dvaceti lety, kteří, když dostali úkol, tak místo aby se nad ním zamysleli, rovnou hledali řešení na webu. S tou „moji” detekcí kuželů je to stejné! Vycházel jsem z modelu Coneslayer, který mi fungoval na PC, ale odkazovaná OAK-D varianta už ne (viz Staronoví manažeři ...).
Možná bych ještě udělal jednu odbočku pro ty, kdo jsou na tom jako já — nazval bych to Slon zahradníkem, aneb kříženec Slona v porcelanu s Kozlem zahradníkem. NNeurotickému světu dominuje několik firmem a z toho vyplývají nejrůznější důsledky. Vycházím s „vtipného” popisu, kterak snadno a rychle konvertovat pytorch model na Movidius/OAK-D. To je skoro na tabulku:
Firma Nástroj Fromát souborů
Facebook Pytorch *.pt a *.pth
Microsoft ONNX *.onnx
Intel OpenVino *.bin, *.xml, *.blob
Google Tensorflow *.tf, *.tflite, …
NVidia TensorRT ??
Jako ve správném kapitalistickém světě se ty firmy nemají rády a tak přechod od jednoho k druhému je dost kostrbatý, pokud vůbec jde (jsou tam i technické rozdíly, ale o nich zatím nejsem schopen nic říci). Typicky to vyžaduje nějakou obskurní verzi, nejlépe v dockeru, která ale zase funguje pouze pro některé verze modelů (?).
Co jsem to chtěl? Jo pointa této předehry je v tom, že YOLO je postaveno na Pytorchi.
Přemmýšlím, jestli Cimrmanovsky neprozradit konec celé detektivky? Asi jo, oni nám jinak diváci zůstavají sedět …
git clone https://github.com/luxonis/depthai-experiments.git
cd depthai-experiments/gen2-yolo/device-decoding
python main.py -config ~/git/Coneslayer/coneslayer.json -recording ~/git/osgar/follow-path.mp4
(zase pozor u configu mají být dvě pomlčky! staré TODO web parser, aby to nebylo interpretováno jako škrtnutý text)
Přiběh začíná tak, že PavelJ řešil rychlost neuronky na Robotour. A právě kvůli zmiňovaným konverzním problémům to dal na github, jestli není problém jen u něj. Já jsem pro model coneslayer_openvino_2021.4_6shave.blob nemohl přímo pustit původní skript, tak jsme to na pravidelném callu zkoušeli v Pavlově prostředí. Nekreslilo to žádné detekce (ano, má rozpoznávací schopnost zda něco funguje je dost chabá) a tak došlo na ladění a tím jsem call zcela zabil a všem účastníkům se ještě jednou omlouvám.
Na výstupu sítě bylo 48672 floatů — co to je? Resp. na výstupu nebylo nic, ale když člověk zavolal in_nn.getAllLayerNames(), tak získal nápovědu, že výstup není output, ale jedna z variant ['output1_yolov7', 'output2_yolov7', 'output3_yolov7']. Dobře, takže to neni jen 48672 floatů, ale 18*52*52 floatů. Lepší? Když je to celé na hromadě, tak není jasné, zda 18 je ta první dimenze nebo poslední (ano, mohla by být i prostřední, ale to by nám snad neudělali). Yolo jede na „mřízce detekcí”, tj. těch 52x52 bude ta mřížka a 18 budou detekce. Jsou to bounding boxy, tj. pozice x, y, velikost w, h a pak důvěryhodnost detekce, ale že by tam měli 14 typů kuželů??
Další den Jirka doporučil si udělat vlastní blob konverzi: Vezmi ten onnx model a zkonvertuj si ho pomocí Luxonis blobconverteru sám https://blobconverter.luxonis.com/. Nastav -mean_values=[0,0,0] -scale_values=[255,255,255]. Tak vznikl nový blob. Jirka lehce naznačil „co se všechno může pokazit”, resp. co vše může být jinak. Barvy nejsou 0 až 255, ale třeba 0 až 1 nebo -0.5 až +0.5. Uspořádané jsou buď RGB nebo BRG. Obrázek může vyžadovat jistou velikost např. 416x416. Data obrázku jsou buď 3x416x416 nebo 416x416x3. Ještě jsem na něco zapomněl? Jirku nic nezastaví, takže odpověď byla
img = cv2.imread(str(args.input_image), cv2.IMREAD_COLOR)  # BGR, HWC
img = cv2.resize(img, (args.width, args.height))
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # RGB, HWC
img = img.transpose(2, 0, 1)  # RGB, CHW
img = numpy.expand_dims(img, 0)  # NCHW, i.e. including a "batch" dimension.
img = (img / 255.).astype(numpy.float32)  # [0..1] range
… no mne to tenkrát přišlo skoro vtipné, že tam byly úplně „všechny věci co se pokazit můžou” — Murphy by byl spokojený.
Ještě psal, že ta síť, resp. ONNX varianta dává nahlédnout pod … jak se to dnes korektně říká? … kapotu:
Zajimave je, ze kdyz si zobrazim ONNX variantu modelu v http://netron.app, vypadaji vystupy jinak, nez co jsme videli v tom xml.
1. Jsou ctyri. Tri nepojmenovane, ktere vypadaji (skoro, ne uplne!) jako ty v tom xml. A jeden "agregovany", ktery z tech tri vznike preskalovanim a slepenim a ktery se jmenuje "output".
2. Ty tri nepojmenovane jsou vicerozmerne a maji tvary jako 1x3x56x56x6. Tj, ta divna osmnactka je asi ve zkutecnosti 3x6. Ta 3 mi unika, ale 6 je neco, co bych cekal, kdyz mam x, y, w, h plus dva typy kuzelu.
3. Ten agregovany "output" ma rozmer 1x1064x6. Tj. 6 zustane, ostatni dimenze se splacnou.
Zkusil jsem pustit ten ONNX model na CPU, ale zatim uplne nechapu skalu hodnot v tom "output". Jsou mimo 0..1, ale moc male na to, aby to byly pixely ve 416x416 obrazku.
Jirka se asi bude zlobit, že to nebylo ke zveřejnění, ale … snad mi to odpustí. Výsledek vypadal takto:
Spousta malých obdělníčků. Znova jsem koukal na yolo popisek a zmiňují tam jednak tu mřížku:
YOLO divides an input image into an S × S grid. If the center of an object falls into a grid cell, that grid cell is responsible for detecting that object. Each grid cell predicts B bounding boxes and confidence scores for those boxes. These confidence scores reflect how confident the model is that the box contains an object and how accurate it thinks the predicted box is.
a dále NMS:
One key technique used in the YOLO models is non-maximum suppression (NMS). NMS is a post-processing step that is used to improve the accuracy and efficiency of object detection. In object detection, it is common for multiple bounding boxes to be generated for a single object in an image. These bounding boxes may overlap or be located at different positions, but they all represent the same object. NMS is used to identify and remove redundant or incorrect bounding boxes and to output a single bounding box for each object in the image.
To Jirka zmiňoval a já moc nechápal o co jde … ale je to způsob, jak z těch mnoha detekci (confidence level 0.999!) získat jednu velkou. Teď už přeskočím na konec (za chvíli budu muset do práce) … s tvrzením „Vrah je slon” (jj, pondělky bývají náročnější) … a zkonvertuji alespoň data nahraná Patem.
Hmm, tak asi později — nemám teď u sebe OAK-D a mezi desítkami parametrů nevidím ukládání výstupu:
(depthai) md@md-ThinkPad-P50:~/git/depthai-experiments/gen2-yolo/device-decoding$ python main.py -h
usage: main.py [-h] [-conf CONFIG] [-recording RECORDING] [-rgbr RGBRESOLUTION]
               [-rgbf RGBFPS] [-monor MONORESOLUTION] [-monof MONOFPS] [-fps FPS]
               [-defaultRes {None,min,max}] [-isp ISPSCALE] [-sharpness SHARPNESS]
               [-lumaDenoise LUMADENOISE] [-chromaDenoise CHROMADENOISE]
               [-manualFocus MANUALFOCUS] [-afMode AFMODE] [-awbMode AWBMODE]
               [-sceneMode SCENEMODE] [-abMode ANTIBANDINGMODE]
               [-effectMode EFFECTMODE] [-dct DISPARITYCONFIDENCETHRESHOLD]
               [-lrct LRCTHRESHOLD] [-sig SIGMA] [-med {0,3,5,7}]
               [-lrc STEREOLRCHECK] [-ext EXTENDEDDISPARITY] [-sub SUBPIXEL]
               [-maxd MAXDEPTH] [-mind MINDEPTH] [-sbbsf SBBSCALEFACTOR]
               [-openvinoVersion {2020_3,2020_4,2021_1,2021_2,2021_3,2021_4,2022_1,UNIVERSAL}]
               [-xls XLINKCHUNKSIZE] [-tun CAMERATUNING] [-dev DEVICEID]
               [-usbs {usb2,usb3}] [-irDotBrightness IRDOTBRIGHTNESS]
               [–irFloodBrightness IRFLOODBRIGHTNESS]
…

16. března 2024 — Software syncing

Dnes jsem se zase něco naučil — od Jirky, jak jinak.
OAK-D kamera nějak běží, detekuje a reportuje kužely (a loguje v OSGARovi), ale když pak chci detekce visualizovat s původními obrázky, tak mám problém:
python -m osgar.logger oak-cone-detection-240315_203533.log -stream oak.detections  oak.color \
                                                            -format "{timestamp} {len(data)}"

0:00:03.442914 219488
0:00:03.487640 4
0:00:03.489948 214840   <====
0:00:03.517288 309346
0:00:03.540213 301433
0:00:03.566320 4
0:00:03.566519 290162
0:00:03.589637 4
0:00:03.599398 299662
0:00:03.615203 304556
0:00:03.638670 4
0:00:03.664591 4
0:00:03.664854 283100
0:00:03.681872 222737
0:00:03.713446 4
0:00:03.724757 4
0:00:03.743658 733428
0:00:03.747007 375482
0:00:03.776240 4
0:00:03.787632 4
0:00:03.790691 386878
0:00:03.812691 408704
… prostě mi přišly tři obrázky za sebou a k čemu se váže ta detekce z času 3.566320?! Jirka to komentoval: Dataframy z OAKu obsahují i timestamp a sequence id. Podle sequence id by to mělo jít párovat se vstupním obrázkem. … a je to přesně tak … viz Software syncing. Přidal jsem sekvenční číslo do OSGAR driveru pro OAK-D kameru (rovnou i pro depth) a výsledky detekce z neuronky je teď možné relativně snadno napárovat v použitým vstupním obrázkem. Ale … sekvenční čísla pro depth jedou v „jiném rytmu” a tak jsem raději rovnou doplnil i ten timestamp_us:
seq_num = packets[-1].getSequenceNum()  # for sync of various outputs
dt = packets[-1].getTimestamp()  # datetime.timedelta
timestamp_us = ((dt.days * 24 * 3600 + dt.seconds) * 1000000 + dt.microseconds)
OSGAR používá msgpack a ten nemá Pythonovský datetime.timedelta v základní sadě. A je škoda ukládat floaty, když vím, že zdroj je v mikrosekundách. Výsledek?
5        oak.depth_seq     1864 | 166 |   8.3Hz
6        oak.color_seq      341 |  31 |   1.5Hz
7   oak.detections_seq      341 |  31 |   1.5Hz

OSGAR time, OSGAR stream, [seq_num, timestamp_us]
0:00:03.472923 6 [0, 163893263641]
0:00:03.516000 7 [0, 163893263641]
0:00:03.518708 6 [2, 163893313635]
0:00:03.547843 6 [3, 163893338631]  <==
0:00:03.567436 5 [0, 163893348213]
0:00:03.569827 6 [4, 163893363629]
0:00:03.596117 7 [2, 163893313635]
0:00:03.596373 6 [5, 163893388627]
0:00:03.619423 7 [3, 163893338631]  <==
0:00:03.619587 6 [6, 163893413624]
0:00:03.646627 6 [7, 163893438618]
0:00:03.650795 5 [1, 163893448204]
0:00:03.666352 7 [4, 163893363629]

18. března 2024 — Debugging DepthAI pipeline

Přiznám se bez mučení — synchronizace obrázku se seznamem detekcí nebylo vše, co mne v sobotu trápilo. I když jsem nahrávání pouštěl několikrát dokola, tak typicky u 31. obrázku se mi to „kouslo” (ale hloubková data se nahrávala dál). Když jsem vypnul nahrávání hloubkových dat, stále stejný problém. Když jsem snížil FPS (počet snímků za sekundu) na 1, tak stejně po 30 sekundách konec.
Jako tonoucí jsem hledal „stéblo” na stránkách Luxonisu a našel Debugging DepthAI pipeline. Úvodní věta, currently, tools for debugging the DepthAI pipeline are limited, mne příliš nepovzbudila (fakticky lze zapnout debug výstup na konzoli a to je asi vše), ale byla tam i zmínka ... which would allow users to debug a “frozen” pipeline much easier, which is usually caused by a filled up blocking queue. Prostě že probém je typicky plná blokovaná fronta.
V mém případě to byl xoutRgb, který jsem vůbec v upravené verzi OSGAR driveru nečetl. Sice měla být jako „neblokovaná”, ale 32 už je možná moc? V každém případě po vyčítání i této fronty, případně úplné odstranění xoutRgb, to najednou jede jak má!
A zároveň jsem pochopil, proč v tom jejich demu jsou dvě výstupní okna. V popisu ColorCamera modulu je zmíněno, že preview - ImgFrame - RGB (or BGR planar/interleaved if configured), mostly suited for small size previews and to feed the image into NeuralNetwork. Prostě zmenšený obrázek se používá jak pro „normální náhled” tak jako vstup do neuronek! A toto preview zobrazovalo to druhé okno. Proč? Protože pokud chcete na vstupu mít 416x416 pixelový obrázek se zachováním poměrů stran, musíte řezat. A to pěkně ukazuje obrázek isp.jpg:
A když bboxy pronásobíte pouze výškou a posunete o polovičku rozdílu výšky a šířky dostanete konečně to co chcete:
p.s. už jenom drobné pozorování, že pokud byl původný záběr kamery úzký, tak po tom ořezu pro detekci bude ještě užší … ale jak to vylepšit si nechám do nějaké ver2.