Denne artikkelen ble publisert som en del av Data Science Blogathon
Introduksjon
Hei alle sammen! Mens cyberpunk ennå ikke har kommet så mye inn i livene våre, og nevro-grensesnitt er langt fra ideelle, kan LiDAR bli det første stadiet på veien mot fremtidens manipulatorer. Derfor, for ikke å kjede meg i ferien, bestemte jeg meg for å fantasere litt om kontrollene til en datamaskin og, antagelig, hvilken som helst enhet, opp til en gravemaskin, romskip, drone eller komfyr.
Hovedideen er å flytte musen, ikke bevege hele hånden, men bare pekefingeren, som lar deg kjøre gjennom menyen uten å ta hendene fra tastaturet, trykke på knapper og, sammen med hurtigtaster, bli til en ekte tastatur ninja! Hva skjer hvis du legger til sveipe- eller rullebevegelser? Jeg tror det kommer en bombe! Men inntil dette øyeblikket må vi fortsatt vente et par år)
La oss begynne å sette sammen prototypen vår av fremtidens manipulator
Hva trenger du:
-
Kamera med LiDAR Intel Realsense L515.
-
Evne til å programmere i python
-
Bare husk litt skolematematikk
-
Feste for kameraet på skjermen aka stativ
Vi fester kameraet til et stativ med aliexpress, det viste seg å være veldig praktisk, lett og billig)
Vi finner ut hvordan og på hva vi skal lage en prototype
Det er mange måter å løse denne oppgaven på. Du kan trene opp detektoren eller håndsegmenteringen selv, klippe ut det resulterende bildet av høyre hånd og deretter bruke dette fantastiske depotet fra Facebook-forskning på bildet, få et utmerket resultat eller gjøre det enda enklere.
For å bruke mediapipelageret, etter å ha lest denne lenken, du kan forstå at dette er et av de beste alternativene for i dag.
For det første er alt der allerede ut av esken - installasjon og lansering vil ta 30 minutter, med tanke på alle forutsetninger.
For det andre, takket være et kraftig utviklingsteam, tar de ikke bare State Of Art in Hand Pose Estimation, men gir også et lettfattelig API.
For det tredje er nettverket klart til å kjøre på CPU, så inngangsterskelen er minimal.
Sannsynligvis vil du spørre hvorfor jeg ikke kom hit og ikke brukte lagrene til vinnerne av denne konkurransen. Faktisk studerte jeg løsningen deres i detalj, de er ganske prod-klare, ingen stabler med millioner av rutenett osv. Men det største problemet, ser det ut til, er at de jobber med dybdebilder. Siden dette er akademikere nølte de ikke med å konvertere alle dataene gjennom Matlab, i tillegg virket oppløsningen som dybdene ble filmet i liten for meg. Dette kan ha en dyp effekt på resultatet. Derfor ser det ut til at den enkleste måten er å få nøkkelpunktene i RGB-bildet og ta verdien langs Z-aksen i Depth Frame etter XY-koordinatene. Nå er ikke oppgaven å optimalisere noe mye, så vi skal gjøre det ettersom det går raskere fra et utviklingssynspunkt.
Husk skolematematikk
Som jeg allerede skrev, for å få koordinaten til punktet der musepekeren skal være, må vi bygge en linje som går gjennom to nøkkelpunkter i falanxen til fingeren, og finne skjæringspunktet mellom linjen og planet til monitoren.
Bildet viser skjematisk monitorens plan og linjen som skjærer den. Du kan se på matematikken her.
Ved å bruke to punkter får vi en parametrisk representasjon av en rett linje i rommet.
Jeg skal ikke fokusere for mye på læreplanen i skolens matematikk.
Installere et bibliotek for arbeid med et kamera
Dette er kanskje den vanskeligste delen av denne jobben. Som det viste seg, er programvaren for kameraet for Ubuntu veldig grov, liberal sans er rett og slett full av alle slags feil, feil og danser med en tamburin.
Til nå har jeg ikke vært i stand til å beseire den merkelige oppførselen til kameraet, noen ganger laster det ikke inn parametere ved oppstart.
Kameraet fungerer bare én gang etter omstart av datamaskinen!!! Men det er en løsning: før hver lansering, gjør en hard tilbakestilling av programvaren av kameraet, tilbakestiller USB-en, og kanskje vil alt være bra. Forresten, for Windows 10 er alt bra der. Det er rart at utviklerne ser for seg roboter basert på Windows =)
For å få ekte mening under Ubuntu 20, gjør dette:
$ sudo apt-get install libusb-1.0-0-dev Kjør deretter cmake på nytt og gjøre installer. Her is en komplett oppskrift som fungerte forum meg: $ sudo apt-get install libusb-1.0-0-dev $ git clone https://github.com/IntelRealSense/librealsense.git $ cd librealsense/ $ mkdir build && cd build
Etter å ha samlet fra sorter, vil den være mer eller mindre stabil. En måned med kommunikasjon med teknisk støtte viste at du må installere Ubuntu 16 eller lide. Jeg valgte det selv, vet du hva.
Vi fortsetter å forstå vanskelighetene i det nevrale nettverket
La oss nå se en annen video av finger-og-mus-operasjonen. Vær oppmerksom på at pekeren ikke kan stå på ett sted og flyter så å si rundt det tiltenkte punktet. Samtidig kan jeg enkelt dirigere det til ordet jeg trenger, men med en bokstav er det vanskeligere, jeg må forsiktig flytte markøren:
Dette, som du forstår, rister ikke på hendene mine, på helligdager drakk jeg bare ett krus New England DIPA =) Det handler om konstante svingninger av nøkkelpunkter og Z-koordinater basert på verdiene hentet fra lidaren.
La oss se nærmere på:
I vår SOTA fra media pipe er det absolutt færre svingninger, men de finnes også. Som det viste seg, sliter de med dette ved å bruke prokid vaniya fra tidligere frame heatmap i gjeldende ramme- og tognettverk – det gir mer stabilitet, men ikke 100 %.
For meg ser det også ut til at spesifisiteten til markeringen spiller en rolle. Det er neppe mulig å lage samme markering på et slikt antall rammer, for ikke å snakke om at oppløsningen på rammen er forskjellig overalt og ikke veldig stor. Vi ser heller ikke flimringen av lys, som mest sannsynlig ikke er konstant på grunn av de forskjellige driftsperiodene og eksponeringsmengden til kameraet. Og nettverket returnerer også en sandwich fra varmekartet lik antall nøkkelpunkter på skjermen, størrelsen på denne tensoren er BxNx96x96, der N er antall nøkkelpunkter, og selvfølgelig etter terskel og endre størrelse til originalen rammestørrelse, vi får det vi får (
Eksempel på gjengivelse av varmekart:
Kode anmeldelse
All koden er i dette depotet og er veldig kort. La oss ta en titt på hovedfilen og se resten selv.
importere cv2 importere mediapipe as mp importere følelsesløs as np importere pyautogui importere pyrealsense2.pyrealsense2 as rs fra google.protobuf.json_format importere MessageToDict fra mediapipe.python.solutions.drawing_utils importere _normalisert_til_piksel_koordinater fra pynput importere tastatur fra utils.common importere get_filtred_values, draw_cam_out, get_right_index fra utils.hard_reset importere hardware_reset fra utils.set_options importere set_short_range pyautogui.FAILSAFE = Falsk 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(nøkkel): if key == keyboard.Key.ctrl: pyautogui.leftClick() if key == keyboard.Key.alt: pyautogui.rightClick() def få_fargedybde(pipeline, align, colorizer): frames = pipeline.wait_for_frames(timeout_ms=15000) # venter på en ramme fra kameraet aligned_frames = align.process(frames) depth_frame = aligned_frames.get_depth_frame() color_frame =(get_aligned_frames) if ikke depth_frame or ikke color_frame: retur Ingen, Ingen, Ingen 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(2)im cd_data(2) cvtColor(cv2.flip(cv1.flip(depth_col_img, 0), 2), cv2.COLOR_BGR2RGB) color_img = cv2.cvtColor(cv2.flip(cv1.flip(color_img, 0), 2), cv2RGB_ deBth_RGB_ np.flipud(np.fliplr(depth_img)) depth_col_img = cv2.resize(depth_col_img, (1280 * 2, 720 * 2)) col_img = cv2.resize(col_img, (1280 * 2, 720) de cv2, 2 .resize(depth_img, (1280 * 2, 720 * 2)) retur color_image, depth_color_image, depth_image def get_right_hand_coords(fargebilde, dybdefargebilde): color_image.flags.writeable = Falske resultater = hands.process(fargebilde) color_image.flags.writeable = Ekte fargebilde = cv2.cvtColor(farge_bilde, cv2.COLOR_RGB2BGR) handedness_dict =__] koordinater xy0 = Ingen, Ingen if results.multi_hand_landmarks: forum idx, hand_handedness in enumerate(results.multi_handedness): handedness_dict.append(MessageToDict(hand_handedness)) right_hand_index = get_right_index(handedness_dict) if høyre_håndsindeks != -1: forum i, landemerkeliste in enumerate(results.multi_hand_landmarks): if i == høyre_indeks: bilderader, bildekolonner, _ = fargebilde.form forum idx, landemerke in enumerate(landmark_list.landmark): landmark_px = _normalized_to_pixel_coordinates(landmark.x, landmark.y, image_cols, image_rows) if landemerke_px: idx_to_coordinates[idx] = landemerke_px forum i, landemerke_px in enumerate(idx_to_coordinates.values()): if i == 5: xy0 = landemerke_px if i == 7: xy1 = landemerke_px bryte retur col_img, depth_col_img, xy0, xy1, idx_to_coordinates def Begynn(): 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) # belastningsparametere for arbeid på kort avstand colorizer = rs.colorizer () print ("Conf loaded") align_to = rs.stream.color align = rs.align (align_to) # kombiner dybdekart og fargebilde prøv: while True: col_img, depth_col_img, depth_img = get_col_depth (pipelin, align, colorize) hvis color_img er Ingen og color_img er Ingen og color_img er Ingen: fortsett color_img, depth_col_img, xy00, get_colg_coordinates x_11_right, xy_00_, xy_11, (depth_col_img) ) hvis xy00 ikke er Ingen eller xy11 ikke er Ingen: 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.), til (00 - z)) # 11 hardcode spesifikk for skjermen min hvis draw_cam_out (col_img, depth_col_img, xyXNUMX_f, xyXNUMX_f, c_xy, m_xy): break finally: hands.close () pipeline.stop () hardware_reset () # start kameraet på nytt og vent til det vises listener = keyboard.Listener (on_press = on_press) # sett en lytter for key tavleknappen trykker på listener.start () start () # start programmet
Jeg brukte ikke klasser eller strømmer, fordi for et så enkelt tilfelle er det nok å kjøre alt i hovedtråden i en endeløs while-løkke.
Helt i begynnelsen initialiseres mediarøret, kameraet, kamerainnstillingene for kortdistanse- og hjelpevariablene lastes inn. Deretter kommer magien som kalles "alight depth to color" - denne funksjonen matcher hvert punkt fra RGB-bildet, et punkt på Depth Frame, det vil si at den gir oss muligheten til å få XY-koordinatene, Z-verdien. Det er forstått at det er nødvendig å kalibrere på skjermen din ... Jeg har bevisst ikke trukket ut disse parameterne separat, slik at leseren som bestemte seg for å kjøre koden ville gjøre det selv, samtidig som den vil bli gjenbrukt i koden)
Deretter tar vi fra hele prediksjonen bare punkter nummerert 5 og 7 på høyre hånd.
Det eneste som gjenstår er å filtrere de oppnådde koordinatene ved å bruke et glidende gjennomsnitt. Det var selvfølgelig mulig å bruke mer seriøse filtreringsalgoritmer, men etter å ha sett på visualiseringen og trukket i forskjellige spaker, ble det klart at et glidende gjennomsnitt med en dybde på 5 bilder ville være nok for demoen, jeg vil merke at for XY var 2-3 rammer nok. men ting er verre med 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_filtred_values(dybdebilde, 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(y0_flo)(xy) 0])) y0_f = round(mean(y0_d)) x0_d.append(float(xy0[1])) x1_f = round(mean(x1_d)) y1_d.append(float(xy1[1])) y1_f = round( mean(y0_d)) z_val_f = get_area_mean_z_val(depth_image, x1_f, y1_f) z_val_f_d.append(float(z_val_f)) z_val_f = mean(z_val_f_d) z_val_s = get_area_mean_p_z_val(s_val_f_val) z_val_s = get_area_mean_f_val. = mean(z_val_s_d) points = [(y0_f, x0_f), (y1_f, x1_f)] x_coords, y_coords = zip(*points) A = np.vstack([x_coords, np.ones(len(x_coords))]). T m, c = lstsq(A, y_coords)[0] m_xy_d.append(float(m)) m_xy = mean(m_xy_d) c_xy_d.append(float(c)) c_xy = mean(c_xy_d) a0, a1, a1, a0 = equation_plane() x, y, z = line_plane_sintersection(y0_f, x1_f, z_v_s, y2_f, x3_f, z_v_f, a0, a0, a1, a1) x_d.append(float(x)) x = round(mean(x_d) ) y_d.append(float(y)) y = round(mean(y_d)) z_d.append(float(z)) z = round(mean(z_d)) retur z_v_f, z_v_s, m_xy, c_xy, (y00_f, x0_f), (y11_f, x1_f), x, y, z
Vi lager en deque med en lengde på 5 rammer og gjennomsnitt alt på rad =) I tillegg beregner vi y = mx + c, Ax + By + Cz + d = 0, ligningen for den rette linjen er strålen i RGB bildet og ligningen til monitorplanet, får vi det y = 0.
konklusjonen
Vel, det er alt, vi saget ned den enkleste manipulatoren, som, selv med sin dramatisk enkle utførelse, allerede kan brukes, om enn med vanskeligheter, i det virkelige liv!
Media vist i denne artikkelen eies ikke av Analytics Vidhya og brukes etter forfatterens skjønn.
I slekt
- "
- &
- 7
- 9
- Logg inn
- algoritmer
- Alle
- analytics
- api
- rundt
- Kunst
- Artikkel
- BEST
- Biggest
- Eske
- bugs
- bygge
- nærmere
- kode
- Felles
- Kommunikasjon
- konkurranse
- fortsette
- Par
- Gjeldende
- CZ
- dato
- detalj
- utviklere
- Utvikling
- gJORDE
- avstand
- drone
- England
- etc
- gjennomføring
- Figur
- Endelig
- slutt
- Først
- Fokus
- format
- funksjon
- framtid
- gå
- her.
- ferien
- Hvordan
- HTTPS
- Tanken
- iDX
- bilde
- indeks
- Intel
- IT
- Jobb
- nøkkel
- stor
- lansere
- Bibliotek
- håndtere
- lett
- linje
- laste
- kart
- matematikk
- Media
- flytte
- nettverk
- neural
- Opportunity
- alternativer
- rekkefølge
- bilde
- rør
- Synspunkt
- prediksjon
- trykk
- Profil
- program
- trekke
- Python
- Reader
- Lesning
- .
- forskning
- REST
- Resultater
- avkastning
- roboter
- Kjør
- Skole
- Vitenskap
- Skjerm
- forstand
- sett
- Kort
- Enkelt
- Størrelse
- liten
- So
- Software
- Solutions
- Rom
- Stabilitet
- Scene
- Begynn
- oppstart
- Tilstand
- sudo
- støtte
- Teknisk
- teknisk støtte
- Fremtiden
- tid
- Ubuntu
- us
- usb
- verdi
- video
- Se
- visualisering
- vente
- HVEM
- vinduer
- Arbeid
- virker
- X
- år