บทความนี้เผยแพร่โดยเป็นส่วนหนึ่งของไฟล์ Blogathon วิทยาศาสตร์ข้อมูล
บทนำ
สวัสดีทุกคน! ในขณะที่ไซเบอร์พังค์ยังไม่ได้เข้ามาในชีวิตของเรามากนัก และส่วนต่อประสานประสาทก็ยังห่างไกลจากอุดมคติ LiDAR สามารถกลายเป็นเวทีแรกบนเส้นทางสู่อนาคตของผู้บงการ ดังนั้น เพื่อไม่ให้รู้สึกเบื่อในช่วงวันหยุด ฉันจึงตัดสินใจจินตนาการเล็กน้อยเกี่ยวกับการควบคุมของคอมพิวเตอร์และอุปกรณ์ใดๆ ก็ได้ ซึ่งอาจรวมถึงรถขุด ยานอวกาศ โดรน หรือเตา
แนวคิดหลักคือการขยับเมาส์ ไม่ใช่ขยับทั้งมือ แต่เป็นนิ้วชี้เท่านั้น ซึ่งจะทำให้คุณสามารถวิ่งผ่านเมนูได้โดยไม่ต้องละมือจากแป้นพิมพ์ กดปุ่ม และพร้อมกับปุ่มลัด กลายเป็น นินจาคีย์บอร์ดตัวจริง! จะเกิดอะไรขึ้นหากคุณเพิ่มท่าทางการปัดหรือเลื่อน นึกว่าจะมีระเบิด! แต่จนถึงขณะนี้เรายังต้องรออีกสองสามปี)
มาเริ่มประกอบต้นแบบหุ่นยนต์แห่งอนาคตกันเถอะ
สิ่งที่คุณต้องการ:
-
กล้องที่มี LiDAR Intel Realsense L515
-
ความสามารถในการเขียนโปรแกรมใน python
-
จำคณิตศาสตร์โรงเรียนได้นิดหน่อย
-
เมาท์สำหรับกล้องบนจอภาพ aka ขาตั้งกล้อง
เราติดกล้องเข้ากับขาตั้งกล้องด้วย aliexpress มันกลับกลายเป็นว่าสะดวกมากน้ำหนักเบาและราคาถูก)
เราหาวิธีและสิ่งที่จะสร้างต้นแบบ
มีหลายวิธีในการทำงานนี้ให้สำเร็จ คุณสามารถฝึกตัวตรวจจับหรือการแบ่งส่วนมือได้ด้วยตัวเอง ตัดภาพที่ได้ของมือขวาออก จากนั้นใช้ที่เก็บที่ยอดเยี่ยมนี้จากการค้นคว้าบน Facebook กับรูปภาพ ได้ผลลัพธ์ที่ยอดเยี่ยมหรือทำให้ง่ายยิ่งขึ้นไปอีก
หากต้องการใช้ที่เก็บไปป์สื่อ หลังจากอ่านลิงก์นี้แล้ว, คุณสามารถเข้าใจได้ว่านี่เป็นหนึ่งในตัวเลือกที่ดีที่สุดสำหรับวันนี้
ประการแรก ทุกอย่างมีอยู่แล้วนอกกรอบ – การติดตั้งและการเปิดตัวจะใช้เวลา 30 นาที โดยคำนึงถึงข้อกำหนดเบื้องต้นทั้งหมดด้วย
ประการที่สอง ขอบคุณทีมพัฒนาที่ทรงพลัง พวกเขาไม่เพียงแต่นำเอา State Of Art in Hand Pose Estimation แต่ยังจัดเตรียม API ที่เข้าใจง่ายอีกด้วย
ประการที่สาม เครือข่ายพร้อมที่จะทำงานบน CPU ดังนั้นเกณฑ์การเข้าจึงน้อยที่สุด
คุณอาจจะถามว่าทำไมฉันไม่มาที่นี่และไม่ได้ใช้ที่เก็บของผู้ชนะการแข่งขันครั้งนี้ อันที่จริง ฉันศึกษาวิธีแก้ปัญหาของพวกเขาในรายละเอียดบางอย่าง พวกมันค่อนข้างพร้อมสำหรับใช้งานจริง ไม่มีกริดเป็นล้านๆ กอง ฯลฯ แต่ปัญหาที่ใหญ่ที่สุดสำหรับฉัน ดูเหมือนว่าพวกเขาทำงานกับภาพเชิงลึก เนื่องจากสิ่งเหล่านี้เป็นข้อมูลเชิงวิชาการ พวกเขาจึงไม่ลังเลเลยที่จะแปลงข้อมูลทั้งหมดผ่าน Matlab นอกจากนี้ ความละเอียดในการถ่ายภาพความลึกจึงดูเล็กน้อยสำหรับฉัน ซึ่งอาจส่งผลอย่างลึกซึ้งต่อผลลัพธ์ ดังนั้น ดูเหมือนว่าวิธีที่ง่ายที่สุดคือการหาจุดสำคัญในรูปภาพ RGB และนำค่าไปตามแนวแกน Z ใน Depth Frame ด้วยพิกัด XY ตอนนี้งานไม่ได้ปรับให้เหมาะสมอะไรมาก ดังนั้นเราจะทำให้มันเร็วขึ้นจากมุมมองของการพัฒนา
จำคณิตศาสตร์โรงเรียน
ตามที่ฉันเขียนไปแล้ว เพื่อให้ได้พิกัดของจุดที่ควรจะเคอร์เซอร์ของเมาส์ เราต้องสร้างเส้นที่ผ่านจุดสำคัญสองจุดของพรรคนิ้ว และหาจุดตัดของเส้นกับ เครื่องบินของจอภาพ
รูปภาพแสดงแผนผังระนาบของจอภาพและเส้นที่ตัดกัน คุณสามารถดูคณิตศาสตร์ได้ที่นี่
เมื่อใช้สองจุด เราจะได้การแสดงพาราเมตริกของเส้นตรงในอวกาศ
ฉันจะไม่เน้นหลักสูตรคณิตศาสตร์ของโรงเรียนมากเกินไป
การติดตั้งไลบรารี่สำหรับการทำงานกับกล้อง
นี่อาจเป็นส่วนที่ยากที่สุดของงานนี้ เมื่อมันปรากฏออกมา ซอฟต์แวร์สำหรับกล้องสำหรับอูบุนตูนั้นหยาบคายมาก ความรู้สึกแบบเสรีนั้นเกลื่อนไปด้วยแมลง ข้อบกพร่อง และการเต้นรำทุกประเภทด้วยแทมบูรีน
จนถึงตอนนี้ผมยังไม่สามารถเอาชนะพฤติกรรมแปลก ๆ ของกล้องได้ บางครั้งมันก็ไม่โหลดพารามิเตอร์เมื่อเริ่มทำงาน
กล้องจะทำงานเพียงครั้งเดียวหลังจากรีสตาร์ทคอมพิวเตอร์ !!! แต่มีวิธีแก้ปัญหา: ก่อนเปิดตัวแต่ละครั้ง ให้ทำการฮาร์ดรีเซ็ตซอฟต์แวร์ของกล้อง รีเซ็ต USB และบางทีทุกอย่างอาจจะเรียบร้อย อย่างไรก็ตาม สำหรับ Windows 10 ทุกอย่างเรียบร้อยดี เป็นเรื่องแปลกที่นักพัฒนาจินตนาการถึงหุ่นยนต์ตาม Windows =)
เพื่อให้ได้ความรู้สึกที่แท้จริงภายใต้ Ubuntu 20 ให้ทำดังนี้:
$ sudo apt-get install libusb-1.0-0-dev จากนั้นรัน cmake อีกครั้ง และ ทำการติดตั้ง ที่นี่ is ครบสูตรที่ได้ผล for ฉัน: $ sudo apt-get ติดตั้ง libusb-1.0-0-dev $ git clone https://github.com/IntelRealSense/librealsense.git $ cd librealsense/ $ mkdir build && cd build
เมื่อรวบรวมจากที่แปลก ๆ มันจะเสถียรไม่มากก็น้อย หนึ่งเดือนของการสื่อสารกับฝ่ายสนับสนุนด้านเทคนิคเปิดเผยว่าคุณต้องติดตั้ง Ubuntu 16 หรือไม่ก็ประสบ ฉันเลือกมันเอง คุณรู้อะไรไหม
เรายังคงเข้าใจความซับซ้อนของโครงข่ายประสาทต่อไป
มาดูวิดีโอการใช้งานนิ้วและเมาส์กัน โปรดทราบว่าตัวชี้ไม่สามารถยืนในที่เดียว และลอยอยู่รอบจุดที่ตั้งใจไว้ ในเวลาเดียวกัน ฉันสามารถกำหนดทิศทางของคำที่ต้องการได้อย่างง่ายดาย แต่ด้วยตัวอักษร มันยากกว่า ฉันต้องเลื่อนเคอร์เซอร์อย่างระมัดระวัง:
ตามที่คุณเข้าใจสิ่งนี้ไม่ได้จับมือฉันในวันหยุดฉันดื่ม New England DIPA เพียงแก้วเดียว =) มันเป็นเรื่องของความผันผวนอย่างต่อเนื่องของจุดสำคัญและพิกัด Z ตามค่าที่ได้รับจาก lidar
มาดูกันดีกว่า:
ใน SOTA ของเราจากท่อสื่อ มีความผันผวนน้อยกว่าอย่างแน่นอน แต่ก็มีอยู่ด้วย เมื่อมันปรากฏออกมา พวกเขากำลังดิ้นรนกับสิ่งนี้โดยใช้ prokid vaniya จากแผนที่ความร้อนของเฟรมที่ผ่านมาในเฟรมปัจจุบันและเครือข่ายรถไฟ - มันให้ความเสถียรมากกว่า แต่ไม่ใช่ 100%
สำหรับฉันแล้วดูเหมือนว่าความจำเพาะของมาร์กอัปก็มีบทบาทเช่นกัน แทบจะเป็นไปไม่ได้เลยที่จะสร้างมาร์กอัปแบบเดียวกันบนเฟรมจำนวนดังกล่าว ไม่ต้องพูดถึงความจริงที่ว่าความละเอียดของเฟรมนั้นแตกต่างกันทุกที่และไม่ใหญ่มาก นอกจากนี้ เรายังไม่เห็นการกะพริบของแสง ซึ่งส่วนใหญ่แล้วจะไม่คงที่เนื่องจากช่วงเวลาการทำงานที่แตกต่างกันและปริมาณการรับแสงของกล้อง และเครือข่ายยังส่งคืนแซนวิชจากแผนที่ความร้อนเท่ากับจำนวนจุดสำคัญบนหน้าจอ ขนาดของเทนเซอร์นี้คือ BxNx96x96 โดยที่ N คือจำนวนจุดสำคัญ และแน่นอน หลังจากธรณีประตูและปรับขนาดเป็นต้นฉบับ ขนาดเฟรมเราได้สิ่งที่เราได้รับ (
ตัวอย่างการแสดงแผนที่ความร้อน:
การตรวจสอบโค้ด
รหัสทั้งหมดอยู่ในที่เก็บนี้และสั้นมาก ลองดูที่ไฟล์หลักและดูส่วนที่เหลือด้วยตัวคุณเอง
นำเข้า cv2 นำเข้า มีเดียไพพ์ as mp นำเข้า มึน as np นำเข้า ปิออโตกุย นำเข้า pyralsense2.pyrealsense2 as rs ราคาเริ่มต้นที่ google.protobuf.json_format นำเข้า ข้อความถึงDict ราคาเริ่มต้นที่ mediapipe.python.solutions.draw_utils นำเข้า _normalized_to_pixel_coordinates ราคาเริ่มต้นที่ พินพุท นำเข้า แป้นพิมพ์ ราคาเริ่มต้นที่ 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 # Hand Pose Estimation hands = mp_hands.Hands (max_num_hands = 2, min_detection_confidence = 0.9) def on_press(กุญแจ): if คีย์ == keyboard.Key.ctrl: pyautogui.leftClick() if คีย์ == keyboard.Key.alt: pyautogui.rightClick() def รับ_สี_ความลึก(pipeline, align, colorizer): frames = pipeline.wait_for_frames(timeout_ms=15000) # กำลังรอเฟรมจากกล้อง aligned_frames = align.process(frames) depth_frame = aligned_frames.get_depth_frame() color_frame = aligned_frames.get_color_frame() if ไม่ deep_frame or ไม่ สี_กรอบ: กลับ ไม่มี ไม่มี ไม่มี depth_ima = np.asanyarray(depth_frame.get_data()) depth_col_img = np.asanyarray(colorizer.colorize(deep_frame).get_data()) color_image = np.asanyarray(color_frame.get_data()) depth_col_img = cv2 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) ความลึก_ np.flipud(np.fliplr(deep_img)) depth_col_img = cv2.resize(deep_col_img, (1280 * 2, 720 * 2)) col_img = cv2.resize(col_img, (1280 * 2, 720 * 2)) depth_img = cv2 .resize(deep_img, (1280 * 2, 720 * 2)) กลับ color_image, ความลึก_color_image, ความลึก_image def get_right_hand_coords(color_image, depth_color_image): color_image.flags.writeable = ผลลัพธ์ที่เป็นเท็จ = hands.process (color_image) color_image.flags.writeable = True color_image = cv2.cvtColor(color_image, cv2.COLOR_RGB2BGR) handedness_dict = [] idx_to_coordinates = {} xy0 = ไม่มี ไม่มี if ผลลัพธ์ multi_hand_landmarks: for idx, ความถนัดมือ in แจกแจง (results.multi_handedness): handedness_dict.append(MessageToDict(hand_handedness)) right_hand_index = get_right_index(handedness_dict) if right_hand_index != -1: for ผม, Landmark_list in แจกแจง (results.multi_hand_landmarks): if ผม == right_hand_index: image_rows, image_cols, _ = color_image.shape for idx สถานที่สำคัญ in แจกแจง (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 for ผม, Landmark_px in แจกแจง(idx_to_coordinates.values()): if ผม == 5: xy0 = สถานที่สำคัญ_px if ผม == 7: xy1 = สถานที่สำคัญ_px ทำลาย กลับ col_img, deep_col_img, xy0, xy1, idx_to_coordinates def เริ่มต้น(): ไปป์ไลน์ = 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) โปรไฟล์ = ไปป์ไลน์ สตาร์ท (config) depth_sensor = profile.get_device () first_deep_sensor () set_short_range (deep_sensor) # โหลดพารามิเตอร์สำหรับการทำงานที่ colorizer ระยะทางสั้น = rs.colorizer () พิมพ์ ("โหลด Conf") align_to = rs.stream.color align = rs.align (align_to) # รวมแผนที่ความลึกและ ลองภาพสี: ในขณะที่ 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, xy11, idx_to_coordinates = get_right_handimg depth_coords (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 (deep_img, xy00, xy11) pyautogui.moveTo (int (x), int (3500 - z)) # 3500 ฮาร์ดโค้ดเฉพาะสำหรับจอภาพของฉันหาก draw_cam_out (col_img, depth_col_img, xy00_f, xy11_f, c_xy, m_xy): แตกในที่สุด: hands.close () pipeline.stop () hardware_reset () # รีบูตกล้องและ รอให้มันปรากฏ listener = keyboard.Listener (on_press = on_press) # ตั้งค่า listener สำหรับคีย์ ปุ่มบอร์ดกด listener.start () เริ่ม () # เริ่มโปรแกรม
ฉันไม่ได้ใช้คลาสหรือสตรีม เพราะในกรณีง่ายๆ เช่นนี้ การดำเนินการทุกอย่างในเธรดหลักแบบวนซ้ำไม่รู้จบก็เพียงพอแล้ว
ในตอนเริ่มต้น ท่อสื่อ กล้องจะเริ่มต้น การตั้งค่ากล้องสำหรับช่วงสั้นและตัวแปรเสริมจะถูกโหลด ถัดมาคือความมหัศจรรย์ที่เรียกว่า “แสงลงสู่สี” – ฟังก์ชันนี้จับคู่แต่ละจุดจากภาพ RGB ซึ่งเป็นจุดบนเฟรมความลึก กล่าวคือ ทำให้เรามีโอกาสได้รับพิกัด 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(deep_image, 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 = ปัดเศษ (med) 0])) y0_f = round(mean(y0_d)) x0_d.append(float(xy0[0])) x1_f = round(mean(x1_d)) y1_d.append(float(xy1[1])) y1_f = round( ค่าเฉลี่ย (y1_d)) z_val_f = get_area_mean_z_val(deep_image, x0_f, y1_f) z_val_f_d.append(float(z_val_f)) z_val_f = ค่ากลาง (z_val_f_d) z_val_s = get_fz_val_sdloat1. = ค่าเฉลี่ย (z_val_s_d) คะแนน = [(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 = ค่าเฉลี่ย (m_xy_d) c_xy_d.append(float(c)) c_xy = ค่าเฉลี่ย (c_xy_d) a0, a1, a1, a0 = ระนาบสมการ () 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 = รอบ (ค่าเฉลี่ย (x_d) ) y_d.append(float(y)) y = round(mean(y_d)) z_d.append(float(z)) z = รอบ (ค่าเฉลี่ย (z_d)) กลับ z_v_f, z_v_s, m_xy, c_xy, (y00_f, x0_f), (y11_f, x1_f), x, y, z
เราสร้าง deque ที่มีความยาว 5 เฟรมและเฉลี่ยทุกอย่างในหนึ่งแถว =) นอกจากนี้ เราคำนวณ y = mx + c, Ax + By + Cz + d = 0 สมการสำหรับเส้นตรงคือรังสีใน RGB รูปภาพและสมการระนาบมอนิเตอร์ เราได้ y = 0
สรุป
นั่นคือทั้งหมดที่เราเลื่อยหุ่นยนต์ที่ง่ายที่สุดซึ่งถึงแม้จะมีการดำเนินการที่เรียบง่ายอย่างมาก แต่ก็สามารถใช้ได้ในชีวิตจริงแม้ว่าจะมีความยากลำบากก็ตาม!
สื่อที่แสดงในบทความนี้ไม่ใช่ของ Analytics Vidhya และใช้ดุลยพินิจของผู้เขียน
ที่เกี่ยวข้อง
- "
- &
- 7
- 9
- ลงชื่อเข้าใช้
- อัลกอริทึม
- ทั้งหมด
- การวิเคราะห์
- API
- รอบ
- ศิลปะ
- บทความ
- ที่ดีที่สุด
- ที่ใหญ่ที่สุด
- กล่อง
- เป็นโรคจิต
- สร้าง
- ใกล้ชิด
- รหัส
- ร่วมกัน
- การสื่อสาร
- การแข่งขัน
- ต่อ
- คู่
- ปัจจุบัน
- CZ
- ข้อมูล
- รายละเอียด
- นักพัฒนา
- พัฒนาการ
- DID
- ระยะทาง
- เสียงหึ่งๆ
- ประเทศอังกฤษ
- ฯลฯ
- การปฏิบัติ
- รูป
- ในที่สุด
- ปลาย
- ชื่อจริง
- โฟกัส
- รูป
- ฟังก์ชัน
- อนาคต
- ไป
- โปรดคลิกที่นี่เพื่ออ่านรายละเอียดเพิ่มเติม
- วันหยุด
- สรุป ความน่าเชื่อถือของ Olymp Trade?
- HTTPS
- ความคิด
- IDX
- ภาพ
- ดัชนี
- อินเทล
- IT
- การสัมภาษณ์
- คีย์
- ใหญ่
- เปิดตัว
- ห้องสมุด
- LIDAR
- เบา
- Line
- โหลด
- แผนที่
- คณิตศาสตร์
- ภาพบรรยากาศ
- ย้าย
- เครือข่าย
- ประสาท
- โอกาส
- Options
- ใบสั่ง
- ภาพ
- ท่อ
- จุดชมวิว
- คำทำนาย
- กด
- โปรไฟล์
- โครงการ
- การดึง
- หลาม
- ผู้อ่าน
- การอ่าน
- สูตร
- การวิจัย
- REST
- ผลสอบ
- รับคืน
- หุ่นยนต์
- วิ่ง
- โรงเรียน
- วิทยาศาสตร์
- จอภาพ
- ความรู้สึก
- ชุด
- สั้น
- ง่าย
- ขนาด
- เล็ก
- So
- ซอฟต์แวร์
- โซลูชัน
- ช่องว่าง
- Stability
- ระยะ
- เริ่มต้น
- การเริ่มต้น
- สถานะ
- sudo
- สนับสนุน
- วิชาการ
- การสนับสนุนทางเทคนิค
- ก้าวสู่อนาคต
- เวลา
- อูบุนตู
- us
- USB
- ความคุ้มค่า
- วีดีโอ
- รายละเอียด
- การสร้างภาพ
- รอ
- WHO
- หน้าต่าง
- งาน
- โรงงาน
- X
- ปี