Acest articol a fost publicat ca parte a Blogathon Data Science
Introducere
Bună ziua tuturor! În timp ce cyberpunk-ul nu a intrat încă atât de mult în viața noastră, iar interfețele neuro sunt departe de a fi ideale, LiDAR poate deveni prima etapă pe calea către viitorul manipulatorilor. Prin urmare, ca să nu mă plictisesc în vacanță, am decis să fantezez puțin despre comenzile unui computer și, probabil, orice dispozitiv, până la un excavator, navă spațială, dronă, sau aragaz.
Ideea principală este să mutați mouse-ul, mișcând nu întreaga mână, ci doar degetul arătător, ceea ce vă va permite să rulați prin meniu fără să luați mâinile de pe tastatură, să apăsați butoane și, împreună cu tastele rapide, să vă transformați într-un ninja cu tastatura reală! Ce se întâmplă dacă adăugați gesturi de glisare sau defilare? Cred că va fi o bombă! Dar până în acest moment mai trebuie să așteptăm câțiva ani)
Să începem asamblarea prototipului nostru de manipulator al viitorului
De ce ai nevoie:
-
Cameră cu LiDAR Intel Realsense L515.
-
Abilitatea de a programa în python
-
Amintește-ți puțin de matematica școlii
-
Suport pentru cameră pe monitor, alias trepied
Atașăm camera la un trepied cu aliexpress, s-a dovedit a fi foarte convenabil, ușor și ieftin)
Ne dăm seama cum și pe ce să facem un prototip
Există multe abordări pentru îndeplinirea acestei sarcini. Puteți antrena singur detectorul sau segmentarea mâinii, decupați imaginea rezultată a mâinii drepte și apoi aplicați acest minunat depozit din cercetarea Facebook pe imagine, obțineți un rezultat excelent sau faceți și mai ușor.
Pentru a utiliza depozitul media pipe, după ce ați citit acest link, puteți înțelege că aceasta este una dintre cele mai bune opțiuni pentru astăzi.
În primul rând, totul este deja din cutie - instalarea și lansarea vor dura 30 de minute, ținând cont de toate cerințele prealabile.
În al doilea rând, datorită unei echipe de dezvoltare puternice, aceștia nu numai că preiau Starea Artei în Estimarea Poziției Mânilor, ci oferă și un API ușor de înțeles.
În al treilea rând, rețeaua este gata să ruleze pe CPU, astfel încât pragul de intrare este minim.
Probabil, veți întreba de ce nu am venit aici și nu am folosit depozitele câștigătorilor acestei competiții. De fapt, le-am studiat soluția în detaliu, sunt destul de pregătite pentru produse, fără stive de milioane de grile etc. Dar cea mai mare problemă, mi se pare, este că funcționează cu imagini de profunzime. Întrucât aceștia sunt academicieni, nu au ezitat să convertească toate datele prin Matlab, în plus, rezoluția în care au fost filmate adâncimile mi s-a părut mică. Acest lucru ar putea avea un efect profund asupra rezultatului. Prin urmare, se pare că cea mai ușoară cale este să obțineți punctele cheie din imaginea RGB și să luați valoarea de-a lungul axei Z în cadrul de adâncime după coordonatele XY. Acum sarcina este să nu optimizăm ceva prea mult, așa că o vom face deoarece este mai rapid din punct de vedere al dezvoltării.
Amintirea matematicii școlare
După cum am scris deja, pentru a obține coordonatele punctului în care ar trebui să fie cursorul mouse-ului, trebuie să construim o linie care trece prin două puncte cheie ale falangei degetului și să găsim punctul de intersecție al liniei și al planul monitorului.
Imaginea prezintă schematic planul monitorului și linia care îl intersectează. Te poți uita la matematică aici.
Folosind două puncte, obținem o reprezentare parametrică a unei linii drepte în spațiu.
Nu mă voi concentra prea mult pe programa școlară de matematică.
Instalarea unei biblioteci pentru lucrul cu o cameră
Aceasta este poate cea mai grea parte a acestui job. După cum s-a dovedit, software-ul pentru camera pentru Ubuntu este foarte grosier, simțul liberal este pur și simplu plin de tot felul de bug-uri, erori și dansuri cu o tamburină.
Până acum, nu am reușit să înving comportamentul ciudat al camerei, uneori nu încarcă parametrii la pornire.
Camera funcționează o singură dată după repornirea computerului !!! Dar există o soluție: înainte de fiecare lansare, faceți o resetare hardware software a camerei, resetați USB-ul și poate totul va fi bine. Apropo, pentru Windows 10 totul este bine acolo. Este ciudat că dezvoltatorii își imaginează roboți bazați pe Windows =)
Pentru a obține un adevărat sens sub Ubuntu 20, procedați astfel:
$ sudo apt-get install libusb-1.0-0-dev Apoi rulați din nou cmake și face instalarea. Aici is o rețetă completă care a funcționat pentru eu: $ sudo apt-get install libusb-1.0-0-dev $ git clone https://github.com/IntelRealSense/librealsense.git $ cd librealsense/ $ mkdir build && cd build
După ce a fost colectat din soiuri, va fi mai mult sau mai puțin stabil. O lună de comunicare cu suportul tehnic a arătat că trebuie să instalați Ubuntu 16 sau să suferiți. L-am ales singur, știi ce.
Continuăm să înțelegem complexitățile rețelei neuronale
Acum să vedem un alt videoclip al operațiunii cu degetul și mouse-ul. Vă rugăm să rețineți că indicatorul nu poate sta într-un singur loc și, așa cum ar fi, plutește în jurul punctului dorit. În același timp, îl pot direcționa cu ușurință către cuvântul de care am nevoie, dar cu o literă, este mai dificil, trebuie să muți cu atenție cursorul:
Asta, după cum înțelegeți, nu îmi strânge mâna, de sărbători am băut doar o cană de New England DIPA =) Totul este vorba de fluctuații constante ale punctelor cheie și ale coordonatelor Z pe baza valorilor obținute de la lidar.
Să aruncăm o privire mai atentă:
În SOTA noastră din conducta media, cu siguranță există mai puține fluctuații, dar există și ele. După cum s-a dovedit, ei se luptă cu acest lucru folosind prokid vaniya din harta de căldură a cadrului anterioare în cadrul actual și rețeaua de tren - oferă mai multă stabilitate, dar nu 100%.
De asemenea, mi se pare, specificul markupului joacă un rol. Cu greu se poate face același marcaj pe un astfel de număr de cadre, ca să nu mai vorbim de faptul că rezoluția cadrului este diferită peste tot și nu foarte mare. De asemenea, nu vedem pâlpâirea luminii, care, cel mai probabil, nu este constantă din cauza diferitelor perioade de funcționare și a cantității de expunere a camerei. Și rețeaua returnează, de asemenea, un sandwich de pe harta termică egal cu numărul de puncte cheie de pe ecran, dimensiunea acestui tensor este BxNx96x96, unde N este numărul de puncte cheie și, desigur, după prag și redimensionare la originalul dimensiunea cadrului, obținem ceea ce obținem (
Exemplu de randare a hărții termice:
Revizuirea codului
Tot codul se află în acest depozit și este foarte scurt. Să aruncăm o privire la fișierul principal și să vedem restul pentru tine.
import cv2 import mediapipe as mp import NumPy as np import pyautogui import pyrealsense2.pyrealsense2 as rs din google.protobuf.json_format import MessageToDict din mediapipe.python.solutions.drawing_utils import _normalizate_la_coordonate_pixeli din pynput import tastatură din utils.common import get_filtered_values, draw_cam_out, get_right_index din utils.hard_reset import resetare_hardware din utils.set_options import set_short_range pyautogui.FAILSAFE = False mp_drawing = mp.solutions.drawing_utils mp_hands = mp.solutions.hands # Hand Pose Estimation hands = mp_hands.Hands(max_num_hands=2, min_detection_confidence=0.9) Def on_press(cheie): if key == keyboard.Key.ctrl: pyautogui.leftClick() if key == keyboard.Key.alt: pyautogui.rightClick() Def get_color_depth(pipeline, align, colorzer): frames = pipeline.wait_for_frames(timeout_ms=15000) # așteptarea unui cadru de la cameră aligned_frames = align.process(frames) depth_frame = aligned_frames.get_depth_frame() color_frame =(get)color_frames.(get)color_frames. if nu adâncime_cadru or nu culoare_frame: reveni None, None, None depth_ima = np.asanyarray(depth_frame.get_data()) depth_col_img = np.asanyarray(colorizer.colorize(depth_frame).get_data()) color_image = np.asanyarray(color_frame.get_data())img =_v2.img cvtColor(cv2.flip(cv2.flip(depth_col_img, 1), 0), cv2.COLOR_BGR2RGB) color_img = cv2.cvtColor(cv2.flip(cv2.flip(color_img, 1), 0), cv2.COLOR_BGR2RGB)_BGRpth2. np.flipud(np.fliplr(depth_img)) depth_col_img = cv1280.resize(depth_col_img, (2 * 720, 2 * 2)) col_img = cv1280.resize(col_img, (2 * 720, 2 cv 2, 1280 cv _2)) .resize(depth_img, (720 * 2, XNUMX * XNUMX)) reveni imagine_color, imagine_de_culoare, imagine_depth Def get_right_hand_coords(imagine_color, adâncime_imagine_culoare): color_image.flags.writeable = Rezultate false = hands.process(color_image) color_image.flags.writeable = True color_image = cv2.cvtColor(color_image, cv2.COLOR_RGB2BGR) handedness_dict = [] coordonate = {}_ xy 0 xy1 = Nici unul, Nici unul if results.multi_hand_landmarks: pentru idx, hand_handedness in enumerate(results.multi_handedness): handedness_dict.append(MessageToDict(hand_handedness)) right_hand_index = get_right_index(handedness_dict) if index_mâna_dreapta != -1: pentru i, landmark_list in enumerate(results.multi_hand_landmarks): if i == right_hand_index: image_rows, image_cols, _ = color_image.shape pentru idx, reper in enumerate(landmark_list.landmark): landmark_px = _normalized_to_pixel_coordinates(landmark.x, landmark.y, image_cols, image_rows) if landmark_px: idx_to_coordinates[idx] = landmark_px pentru i, landmark_px in enumerate(idx_to_coordinates.values()): if i == 5: xy0 = landmark_px if i == 7: xy1 = landmark_px rupe reveni col_img, depth_col_img, xy0, xy1, idx_to_coordinates Def Începe(): pipeline = rs.pipeline() # initialize librealsense config = rs.config() print("Start load conf") config.enable_stream(rs.stream.depth, 1024, 768, rs.format.z16, 30) config.enable_stream(rs.stream.color, 1280, 720, rs.format.bgr8, 30) profile = pipeline.start(config) depth_sensor = profile.get_device (). first_depth_sensor () set_short_range (depth_sensor) # parametri de încărcare pentru lucrul la o distanță scurtă colorizer = rs.colorizer () print ("Conf încărcat") align_to = rs.stream.color align = rs.align (align_to) # combinați harta de adâncime și imagine color încercați: în timp ce Adevărat: col_img, depth_col_img, depth_img = get_col_depth (pipelin, align, colorize) dacă color_img este None și color_img este None și color_img este None: continua color_img, depth_col_img, xy00, xy11, xyto00_coordinate_coordinate, xyto11_coordinate ) dacă xy00 nu este None sau xy11 nu este None: z_val_f, z_val_s, m_xy, c_xy, xy00_f, xy11_f, x, y, z = get_filtered_values (depth_img, xy3500, xy3500) pyautogui (move), int To (intgui.move) (00 - z)) # 11 hardcode specific monitorului meu dacă draw_cam_out (col_img, depth_col_img, xyXNUMX_f, xyXNUMX_f, c_xy, m_xy): break finally: hands.close () pipeline.stop () hardware_reset () # reporniți camera și așteptați să apară ascultător = tastatură.Listener (on_press = on_press) # setați un ascultător pentru tastă butonul de bord apasă ascultător.start () start () # începe programul
Nu am folosit clase sau fluxuri, pentru că, pentru un caz atât de simplu, este suficient să executați totul în firul principal într-o buclă while fără sfârșit.
La început, conducta media, camera sunt inițializate, sunt încărcate setările camerei pentru variabilele de rază scurtă și auxiliare. Urmează magia numită „alight depth to color” – această funcție se potrivește cu fiecare punct din imaginea RGB, un punct din Depth Frame, adică ne oferă posibilitatea de a obține coordonatele XY, valoarea Z. Se înțelege că este necesar să calibrați pe monitorul dvs.... Nu am scos acești parametri separat, în mod deliberat, astfel încât cititorul care a decis să ruleze codul să o facă singur, în același timp va fi reutilizat în cod)
În continuare, luăm din întreaga predicție doar punctele numerotate 5 și 7 ale mâinii drepte.
Singurul lucru rămas de făcut este să filtrați coordonatele obținute folosind o medie mobilă. A fost posibil, desigur, să se aplice algoritmi de filtrare mai serioși, dar după ce ne-am uitat la vizualizarea lor și am tras diverse pârghii, a devenit clar că o medie mobilă cu o adâncime de 5 cadre ar fi suficientă pentru demo, vreau să remarc că pentru XY au fost suficiente 2-3 cadre. dar lucrurile stau mai rău cu Z.
deque_l = 5 x0_d = collections.deque(deque_l * [0.], deque_l) y0_d = collections.deque(deque_l * [0.], deque_l) x1_d = collections.deque(deque_l * [0.], deque_l) y1_d = collections.deque(deque_l * [0.], deque_l) z_val_f_d = collections.deque(deque_l * [0.], deque_l) z_val_s_d = collections.deque(deque_l * [0.], deque_l) m_xy_d = collections.deque(deque_l * [0.], deque_l) c_xy_d = collections.deque(deque_l * [0.], deque_l) x_d = collections.deque(deque_l * [0.], deque_l) y_d = collections.deque(deque_l * [0.] , deque_l) z_d = collections.deque(deque_l * [0.], deque_l) Def get_filtered_values(imagine_adâncime, xy0, xy1): global x0_d, y0_d, x1_d, y1_d, m_xy_d, c_xy_d, z_val_f_d, z_val_s_d, x_d, y_d, z_d x0_d.append(float(xy0[1])) x0_f = round(mean(mean(x0_d.)app)[y0_float(x0_d.) 0])) y0_f = rotund(medie(y0_d)) x1_d.append(float(xy1[1])) x1_f = rotund(medie(x1_d)) y1_d.append(float(xy1[0])) y1_f = rotund( mean(y1_d)) z_val_f = get_area_mean_z_val(depth_image, x0_f, y0_f) z_val_f_d.append(float(z_val_f)) z_val_f = mean(z_val_f_d) z_val_s = get_area_mean)(z_val_f_d_val,s_val_f_d_val,s_val_f_val,s_val_f_val, z_val_f_d = mean(z_val_s_d) points = [(y1_f, x1_f), (y0_f, x0_f)] x_coords, y_coords = zip(*puncte) A = np.vstack([x_coords, np.ones(len(x_coords))]). T m, c = lstsq(A, y_coords)[1] m_xy_d.append(float(m)) m_xy = mean(m_xy_d) c_xy_d.append(float(c)) c_xy = mean(c_xy_d) a1, a0, a0, a1 = plan_ecuație() x, y, z = intersecție_plan_linie(y2_f, x3_f, z_v_s, y0_f, x0_f, z_v_f, a1, a1, a0, a1) x_d.append(float(x)) x = rotund(mean(x_d) ) y_d.append(float(y)) y = rotund(mean(y_d)) z_d.append(float(z)) z = rotund(mean(z_d)) reveni z_v_f, z_v_s, m_xy, c_xy, (y00_f, x0_f), (y11_f, x1_f), x, y, z
Creăm un deque cu o lungime de 5 cadre și facem o medie a tuturor pe rând =) În plus, calculăm y = mx + c, Ax + By + Cz + d = 0, ecuația pentru linia dreaptă este raza din RGB imaginea și ecuația planului monitorului, obținem y = 0.
Concluzie
Ei bine, atâta tot, am tăiat cel mai simplu manipulator, care, chiar și cu execuția sa dramatic de simplă, poate fi deja folosit, deși cu greu, în viața reală!
Mediile prezentate în acest articol nu sunt deținute de Analytics Vidhya și sunt utilizate la discreția autorului.
Legate de
- "
- &
- 7
- 9
- Cont
- algoritmi
- TOATE
- Google Analytics
- api
- în jurul
- Artă
- articol
- CEL MAI BUN
- Cea mai mare
- Cutie
- gandaci
- construi
- mai aproape
- cod
- Comun
- Comunicare
- concurs
- continua
- Cuplu
- Curent
- CZ
- de date
- detaliu
- Dezvoltatorii
- Dezvoltare
- FĂCUT
- distanţă
- zbârnâi
- Anglia
- etc
- execuție
- Figura
- În cele din urmă
- capăt
- First
- Concentra
- format
- funcţie
- viitor
- merge
- aici
- concediu
- Cum
- HTTPS
- idee
- idx
- imagine
- index
- Intel
- IT
- Loc de munca
- Cheie
- mare
- lansa
- Bibliotecă
- trata
- ușoară
- Linie
- încărca
- Hartă
- matematică
- Mass-media
- muta
- reţea
- neural
- Oportunitate
- Opţiuni
- comandă
- imagine
- ţeavă
- Punct de vedere
- prezicere
- presa
- Profil
- Program
- trăgând
- Piton
- Cititor
- Citind
- reţetă
- cercetare
- REST
- REZULTATE
- Returnează
- roboţi
- Alerga
- Şcoală
- Ştiinţă
- Ecran
- sens
- set
- Pantaloni scurți
- simplu
- Mărimea
- mic
- So
- Software
- soluţii
- Spaţiu
- Stabilitate
- Etapă
- Începe
- lansare
- Stat
- sudo
- a sustine
- Tehnic
- suport tehnic
- Viitorul
- timp
- Ubuntu
- us
- USB
- valoare
- Video
- Vizualizare
- vizualizare
- aștepta
- OMS
- ferestre
- Apartamente
- fabrică
- X
- ani