מאמר זה פורסם כחלק מה- בלוגאת מדע הנתונים
מבוא
שלום לכולם! בעוד שהסייברפאנק עדיין לא נכנס לחיינו כל כך, וממשקי נוירו רחוקים מלהיות אידיאליים, LiDAR יכול להפוך לשלב הראשון בדרך לעתיד המניפולטורים. לכן, כדי לא להשתעמם בחגים, החלטתי לפנטז קצת על הפקדים של מחשב וככל הנראה על כל מכשיר, עד מחפר, חללית, מזל"ט או תנור.
הרעיון המרכזי הוא להזיז את העכבר, לא להזיז את כל היד, אלא רק את האצבע המורה, מה שיאפשר לך לרוץ בתפריט מבלי להוריד את הידיים מהמקלדת, ללחוץ על כפתורים, ויחד עם מקשים חמים להפוך ל- נינג'ה מקלדת אמיתית! מה קורה אם תוסיף תנועות החלקה או גלילה? אני חושב שתהיה פצצה! אבל עד לרגע זה אנחנו עדיין צריכים לחכות כמה שנים)
בואו נתחיל להרכיב את אב הטיפוס שלנו של המניפולטור של העתיד
מה אתה צריך:
-
מצלמה עם LiDAR Intel Realsense L515.
-
יכולת תכנות ב-python
-
רק קצת לזכור את המתמטיקה של בית הספר
-
הרכבה למצלמה על הצג הידועה גם בחצובה
אנחנו מחברים את המצלמה לחצובה עם aliexpress, זה התברר להיות מאוד נוח, קל משקל וזול)
אנחנו מבינים איך ועל מה לעשות אב טיפוס
ישנן גישות רבות לביצוע משימה זו. אתה יכול לאמן את הגלאי או פילוח היד בעצמך, לגזור את התמונה המתקבלת של יד ימין ואז ליישם את המאגר הנפלא הזה ממחקר פייסבוק על התמונה, לקבל תוצאה מצוינת או להקל עוד יותר.
כדי להשתמש במאגר צינורות המדיה, לאחר קריאת קישור זה, אתה יכול להבין שזו אחת האפשרויות הטובות ביותר להיום.
ראשית, הכל כבר שם מהקופסה - התקנה והשקה יימשכו 30 דקות, תוך התחשבות בכל התנאים המוקדמים.
שנית, הודות לצוות פיתוח רב עוצמה, הם לא רק לוקחים את מצב האמנות ביד, אלא גם מספקים API קל להבנה.
שלישית, הרשת מוכנה לפעול על המעבד, כך שסף הכניסה הוא מינימלי.
סביר להניח שתשאלו מדוע לא באתי לכאן ולא השתמשתי במאגרים של הזוכים בתחרות זו. למעשה, למדתי את הפתרון שלהם בפירוט מסוים, הם די מוכנים לפרוד, אין ערימות של מיליוני רשתות וכו'. אבל הבעיה הכי גדולה, נראה לי, היא שהם עובדים עם תמונות עומק. מכיוון שמדובר באקדמאים, הם לא היססו להמיר את כל הנתונים דרך מטלב, בנוסף, הרזולוציה בה צולמו העומקים נראתה לי קטנה. זה יכול להשפיע עמוקות על התוצאה. לכן, נראה שהדרך הקלה ביותר היא לקבל את נקודות המפתח בתמונת RGB ולקחת את הערך לאורך ציר ה-Z במסגרת העומק לפי קואורדינטות XY. עכשיו המשימה היא לא לייעל משהו הרבה, אז אנחנו נעשה את זה מכיוון שהוא מהיר יותר מנקודת מבט של פיתוח.
זוכרים את המתמטיקה בבית הספר
כפי שכבר כתבתי, כדי לקבל את הקואורדינטה של הנקודה שבה צריך להיות סמן העכבר, עלינו לבנות קו העובר דרך שתי נקודות מפתח של פלנקס האצבע, ולמצוא את נקודת החיתוך של הקו וה- מישור המוניטור.
התמונה מציגה באופן סכמטי את מישור המוניטור ואת הקו החותך אותו. אתה יכול להסתכל על המתמטיקה כאן.
באמצעות שתי נקודות, נקבל ייצוג פרמטרי של קו ישר במרחב.
לא אתמקד יותר מדי בתוכנית הלימודים במתמטיקה של בית הספר.
התקנת ספרייה לעבודה עם מצלמה
זה אולי החלק הקשה ביותר בעבודה הזו. כפי שהתברר, התוכנה למצלמה עבור אובונטו היא מאוד גסה, החוש הליברלי פשוט עמוס בכל מיני באגים, תקלות וריקודים עם טמבורין.
עד עכשיו לא הצלחתי לנצח את ההתנהגות המוזרה של המצלמה, לפעמים היא לא טוענת פרמטרים בהפעלה.
המצלמה פועלת פעם אחת בלבד לאחר הפעלה מחדש של המחשב!!! אבל יש פתרון: לפני כל השקה, בצע איפוס קשיח של המצלמה לתוכנה, מאפס את ה-USB, ואולי הכל יהיה בסדר. אגב, עבור Windows 10 הכל בסדר שם. מוזר שהמפתחים מדמיינים רובוטים המבוססים על Windows =)
כדי לקבל הגיון אמיתי תחת אובונטו 20, עשה זאת:
$ sudo apt-get install libusb-1.0-0-dev ואז הפעל מחדש את cmake ו לעשות התקנה. כאן is מתכון שלם שעבד ל אני: $ sudo apt-get install libusb-1.0-0-dev $ git clone https://github.com/IntelRealSense/librealsense.git $ cd librealsense/ $ mkdir build && cd build
לאחר איסוף ממינים, זה יהיה פחות או יותר יציב. חודש של תקשורת עם תמיכה טכנית גילה שאתה צריך להתקין אובונטו 16 או לסבול. אני בחרתי את זה בעצמך, אתה יודע מה.
אנו ממשיכים להבין את המורכבויות של הרשת העצבית
עכשיו בואו נראה סרטון נוסף של פעולת האצבע והעכבר. שימו לב שהמצביע לא יכול לעמוד במקום אחד וכביכול מרחף סביב הנקודה המיועדת. יחד עם זאת, אני יכול לכוון אותו בקלות למילה שאני צריך, אבל עם אות, זה יותר קשה, אני צריך להזיז בזהירות את הסמן:
זה, כפי שאתה מבין, לא מרעיד לי את היד, בחגים שתיתי רק ספל אחד של ניו אינגלנד DIPA =) הכל עניין של תנודות קבועות של נקודות מפתח וקואורדינטות Z על בסיס הערכים שהתקבלו מהלידר.
בואו נסתכל מקרוב:
ב-SOTA שלנו מ-media pipe, בהחלט יש פחות תנודות, אבל הן גם קיימות. כפי שהתברר, הם נאבקים עם זה על ידי שימוש ב-prokid vaniya ממפת החום של המסגרת בעבר ברשת המסגרת והרכבות הנוכחית - זה נותן יותר יציבות, אבל לא 100%.
כמו כן, נראה לי, הספציפיות של הסימון משחקת תפקיד. בקושי אפשר לעשות את אותו סימון על מספר כזה של פריימים, שלא לדבר על העובדה שהרזולוציה של המסגרת שונה בכל מקום ולא מאוד גדולה. כמו כן, איננו רואים את הבהוב האור, אשר ככל הנראה אינו קבוע בשל תקופות הפעולה השונות וכמות החשיפה של המצלמה. והרשת גם מחזירה כריך ממפת החום השווה למספר נקודות המפתח על המסך, הגודל של הטנזור הזה הוא BxNx96x96, כאשר N הוא מספר נקודות המפתח, וכמובן, לאחר סף ושינוי גודל למקור. גודל מסגרת, אנחנו מקבלים מה שאנחנו מקבלים (
דוגמה לעיבוד מפת חום:
ביקורת קוד
כל הקוד נמצא במאגר הזה והוא קצר מאוד. בואו נסתכל על הקובץ הראשי ונראה את השאר בעצמכם.
לייבא cv2 לייבא mediapipe as mp לייבא קהות as np לייבא pyautogui לייבא pyrealsense2.pyrealsense2 as rs החל מ- google.protobuf.json_format לייבא MessageToDict החל מ- mediapipe.python.solutions.drawing_utils לייבא _נורמליזציה_ל_פיקסל_קואורדינטות החל מ- pynput לייבא מקלדת החל מ- utils.common לייבא get_filtered_values, draw_cam_out, get_right_index החל מ- utils.hard_reset לייבא חומרה_איפוס החל מ- utils.set_options לייבא set_short_range pyautogui.FAILSAFE = False mp_drawing = mp.solutions.drawing_utils mp_hands = mp.solutions.hands # תנוחת ידיים הערכת ידיים = mp_hands.Hands(max_num_hands=2, min_detection_confidence=0.9) def on_press(מַפְתֵחַ): if key == keyboard.Key.ctrl: pyautogui.leftClick() if key == keyboard.Key.alt: pyautogui.rightClick() def get_color_depth(pipeline, align, colorizer): frames = pipeline.wait_for_frames(timeout_ms=15000) # waiting for a frame from the camera aligned_frames = align.process(frames) depth_frame = aligned_frames.get_depth_frame() color_frame =(get_color_frames.() if לֹא depth_frame or לֹא color_frame: לַחֲזוֹר 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(2_v)im c 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_COLOR) np.flipud(np.fliplr(depth_img)) depth_col_img = cv2.resize(depth_col_img, (2 * 1280, 2 * 720)) col_img = cv2.resize(col_img, (2 * 1280, 2) cv720, 2) .resize(depth_img, (2 * 1280, 2 * 720)) לַחֲזוֹר color_image, depth_color_image, depth_image def get_right_hand_coords(תמונה_צבע, תמונת_צבע_עומק): color_image.flags.writeable = תוצאות כוזבות = hands.process(color_image) color_image.flags.writeable = True color_image = cv2.cvtColor(color_image, cv2.COLOR_RGB2BGR) handedness_dict = {}_0 xyx, xy1 = אין, אין if results.multi_hand_landmarks: ל idx, hand_handedness in enumerate(results.multi_handedness): handedness_dict.append(MessageToDict(hand_handedness)) right_hand_index = get_right_index(handedness_dict) if right_hand_index != -1: ל i, landmark_list in enumerate(results.multi_hand_landmarks): if i == right_hand_index: image_rows, image_cols, _ = color_image.shape ל idx, ציון דרך 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 ל i, landmark_px in enumerate(idx_to_coordinates.values()): if i == 5: xy0 = landmark_px if i == 7: xy1 = landmark_px לשבור לַחֲזוֹר col_img, depth_col_img, xy0, xy1, idx_to_coordinates def התחלה(): pipeline = rs.pipeline() # initialize librealsense config = rs.config() print("התחל לטעון 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) # פרמטרים לטעינה לעבודה במרחק קצר colorizer = rs.colorizer () הדפס ("Conf loaded") align_to = rs.stream.color align = rs.align (align_to) # שילוב של מפת עומק ו color_img try: while True: col_img, depth_col_img, depth_img = get_col_depth (pipelin, align, colorize) אם color_img הוא None ו-color_img הוא None ו-color_img הוא None: להמשיך color_img, depth_col_img, xy00, xy_11_right, de_coordinates =x_00_11, ( th_col_img ) אם xy00 אינו None או xy11 אינו 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 (00 - z)) # 11 קוד קשיח ספציפי לצג שלי אם draw_cam_out (col_img, depth_col_img, xyXNUMX_f, xyXNUMX_f, c_xy, m_xy): break finally: hands.close () pipeline.stop () hardware_reset () # הפעל מחדש את המצלמה ו המתן עד שהוא יופיע מאזין = מקלדת.Listener (on_press = on_press) # הגדר מאזין למקלדת כפתור לחץ listener.start () התחל () # התחל את התוכנית
לא השתמשתי בשיעורים או בזרמים, כי למקרה פשוט כזה, מספיק לבצע את כל מה שבשרשור הראשי בלולאת תוך אינסופית.
ממש בהתחלה מאתחלים את צינור המדיה, המצלמה, נטענות הגדרות המצלמה למשתני טווח קצר ומשתני עזר. לאחר מכן מגיע הקסם שנקרא "הורדת עומק לצבע" - פונקציה זו מתאימה לכל נקודה מתמונת ה-RGB, נקודה על ה-Depth Frame, כלומר, היא נותנת לנו את ההזדמנות לקבל את קואורדינטות ה-XY, ערך ה-Z. מובן שיש צורך לכייל על המסך שלך... בכוונה לא שלפתי את הפרמטרים הללו בנפרד, כדי שהקורא שהחליט להריץ את הקוד יעשה זאת בעצמו, במקביל יעשה בו שימוש חוזר בקוד)
לאחר מכן, ניקח מכל החיזוי רק נקודות ממספרות 5 ו-7 של יד ימין.
הדבר היחיד שנותר לעשות הוא לסנן את הקואורדינטות שהתקבלו באמצעות ממוצע נע. אפשר היה כמובן ליישם אלגוריתמי סינון רציניים יותר, אבל לאחר בחינת ההדמיה שלהם ומשיכת מנופים שונים, התברר שממוצע נע בעומק של 5 פריימים יספיק להדגמה, אני רוצה לציין ש עבור XY, 2-3 פריימים הספיקו. אבל המצב גרוע יותר עם 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(תמונה_עומק, xy0, xy1): גלוֹבָּלִי 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_at(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_p_z_f. d(float(z_val_s)) z_val_s = 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_intersection(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)) לַחֲזוֹר z_v_f, z_v_s, m_xy, c_xy, (y00_f, x0_f), (y11_f, x1_f), x, y, z
אנו יוצרים דסק באורך של 5 פריימים ומממוצעים הכל בשורה =) בנוסף, אנו מחשבים y = mx + c, Ax + By + Cz + d = 0, המשוואה עבור הקו הישר היא הקרן ב-RGB תמונה ואת המשוואה של מישור המוניטור, נקבל את זה y = 0.
סיכום
ובכן, זה הכל, ניסרנו את המניפולטור הפשוט ביותר, שאפילו עם הביצוע הפשוט והדרמטי שלו, כבר ניתן להשתמש בו, אם כי בקושי, בחיים האמיתיים!
אמצעי התקשורת המוצגים במאמר זה אינם בבעלות Analytics Vidhya ומשמשים את שיקול הדעת של המחבר.
מוצרים מקושרים
- "
- &
- 7
- 9
- חֶשְׁבּוֹן
- אלגוריתמים
- תעשיות
- ניתוח
- API
- סביב
- אמנות
- מאמר
- הטוב ביותר
- הגדול ביותר
- אריזה מקורית
- באגים
- לִבנוֹת
- קרוב יותר
- קוד
- Common
- תקשורת
- תחרות
- להמשיך
- זוג
- נוֹכְחִי
- CZ
- נתונים
- פרט
- מפתחים
- צעצועי התפתחות
- DID
- מרחק
- זמזום
- אַנְגלִיָה
- וכו '
- הוצאת להורג
- פייסבוק
- תרשים
- בסופו של דבר
- סוף
- ראשון
- להתמקד
- פוּרמָט
- פונקציה
- עתיד
- Git
- כאן
- חגים
- איך
- HTTPS
- רעיון
- IDX
- תמונה
- מדד
- אינטל
- IT
- עבודה
- מפתח
- גָדוֹל
- לשגר
- סִפְרִיָה
- עסקה
- אוֹר
- קו
- לִטעוֹן
- מַפָּה
- מתימטיקה
- מדיה
- המהלך
- רשת
- עצביים
- הזדמנות
- אפשרויות
- להזמין
- תמונה
- מקטרת
- נקודת מבט
- נבואה
- ללחוץ
- פּרוֹפִיל
- תָכְנִית
- מושך
- פיתון
- קורא
- קריאה
- מתכון
- מחקר
- REST
- תוצאות
- החזרות
- רובוטים
- הפעלה
- בית ספר
- מדע
- מסך
- תחושה
- סט
- קצר
- פָּשׁוּט
- מידה
- קטן
- So
- תוכנה
- פתרונות
- מֶרחָב
- יציבות
- התמחות
- התחלה
- סטארט - אפ
- מדינה
- סודו
- תמיכה
- טכני
- תמיכה טכנית
- העתיד
- זמן
- אובונטו
- us
- USB
- ערך
- וִידֵאוֹ
- לצפיה
- ראיה
- לחכות
- מי
- חלונות
- תיק עבודות
- עובד
- X
- שנים