วันจันทร์ที่ 13 พฤษภาคม พ.ศ. 2562

สาเหตุและการแก้ไขปัญหาการสั่งการจากท่าทาง

ในปัจจุบันการสั่งการของระบบ Smart Mirror ที่ใช้การรับข้อมูล Depth Image มาทำ Image Processing และ Blob Tracking เพื่อนำ object ที่ได้ไปใช้คำนวณทิศทางการเคลื่อนที่และนำผลที่ได้สรุปเป็น gesture และส่ง gesture ดังกล่าวไปแปลงเป็นคำสั่งสำหรับใช้สั่งการหน้า Web Application นั้นมีปัญหาที่การสั่งการเกิดความผิดปกติขึ้น ยกตัวอย่างว่าเราต้องการเปลี่ยนหน้าแสดงผลไปยังหน้าถัดไป ต้องทำการเลื่อนมือไปทางขวา 1 ครั้ง แต่กลับส่งผลให้มีการเลื่อนหน้ามากกว่า 1 ครั้งทำให้ข้ามหน้าที่เราต้องการไป

โดยสาเหตุของปัญหาดังกล่าวมาจากการที่ในช่วงเวลาของการตรวจจับท่าทาง จะมีบางช่วงของข้อมูลที่เกิดการตกหล่นไป

ซึ่งเงื่อนไขของการตรวจจับของระบบก่อนทำการแก้ไขนั้นทำเพียงแค่เช็คว่าท่าทางล่าสุดที่เข้ามาแตกต่างกับท่าทางก่อนหน้าหรือไม่ และจะทำการเก็บท่าทางใหม่ที่เข้ามาเพื่อเช็คกับท่าทางถัดไปไม่ว่าจะเข้าเงื่อนไขหรือไม่ โดยดูได้จากโค้ดดังนี้

if last_gesture != gesture:
     if gesture == "swipe up":
          mouse.scroll(0 , -5)
     if gesture == "swipe down":
          mouse.scroll(0 , 5)
     if gesture == "swipe left":
          keyboard.press(Key.right)
          keyboard.release(Key.right)
     if gesture == "swipe right":
          keyboard.press(Key.left)
          keyboard.release(Key.left)

     if gesture == "grab down":
          keyboard.press('x')
          keyboard.release('x')
          # print("Grab up")
     if gesture == "grab left" :
          keyboard.press('z')
          keyboard.release('z')
          # print("Grab left")
     if gesture == "grab right" :
          keyboard.press('c')
          keyboard.release('c')
          # print("Grab right")
last_gesture = gesture

ซึ่งจากโค้ดข้างต้นจะทำให้เกิดการสั่งการเกินได้ดังนี้

สมมติเราทำการเลื่อนมือไปทางขวา 1 ครั้งเพื่อสั่งการ swipe right ดังรูปในผล จะพบว่าระหว่างช่วงที่เกิด swipe right มีบางช่วงที่เกิด undefined action ขึ้นระหว่างการตรวจสอบ

ซึ่งจากโค้ดเปรียบเทียบว่า last_gesture ซึ่งเก็บค่า swipe right ไว้มาเทียบกับ gesture คือ undefined action นั้นตรงตามเงื่อนไขจริงแต่ไม่มี action เกิดขึ้น

จากนั้นจะทำการปรับค่า last_gesture เป็น undefined action เพื่อเตรียมไปเช็คกับข้อมูลถัดไป และเมื่อพบ gesture swipe right อีกครั้ง ซึ่งเข้าเงื่อนไขการสั่งการ ทำให้เกิดการเลื่อนหน้าครั้งที่ 2 ขึ้น แม้ว่าจริงๆแล้วทั้งหมดจะเกิดจากการเลื่อนมือเพียงครั้งเดียว



ภาพตัวอย่างผลการเลื่อนมือไปทางขวา 1 ครั้ง และมีช่วง undefined action เกิดขึ้น

ซึ่งปัญหานี้แก้ไขโดยการสร้างตัวแปรเพิ่มขึ้นมา 2 ตัว คือ

  • state_gesture สำหรับเก็บข้อมูลท่าทางล่าสุดก่อนจะเกิด undefined action
  • undefined_count สำหรับนับการเกิด undefined action เพื่อใช้ reset state_gesture ในกรณีที่ตรวจไม่พบท่าทางตามที่กำหนดไว้

และการออกแบบฟังค์ชันและเงื่อนไขจะปรับเป็น state ดังนี้
  1. หากตรวจพบว่าท่าทางที่เกิดขึ้นเป็น undefined action จะตรวจสอบก่อนว่า เกิด undefined action ไปแล้วระยะหนึ่ง หากครบตามที่กำหนด จะทำการ reset ค่า state_gesture และ undefined_count กลับสู่ค่าเริ่มต้นเพื่อรอรับคำสั่งใหม่ หากยังไม่ครบจะทำการเพิ่มค่า undefined_count ขึ้นทีละ 1
  2. หากพบว่าท่าทางที่เกิดขึ้นกับท่าทางก่อนหน้าไม่เหมือนกัน จะทำการเช็คก่อนว่า last_gesture ที่เป็นท่าทางก่อนหน้าท่าทางล่าสุดเป็น undefined action หรือไม่ หากไม่ใช่ จะทำการ map ท่าทางกับคำสั่งและปรับค่า undefined_count ให้เป็น 0 และตั้งให้ state_gesture และ last_gesture ที่ใช้สำหรับเก็บค่าท่าทางให้เป็นท่าทางล่าสุดที่เข้ามา
  3. จากข้อ 2 หากพบว่า last_gesture เป็น undefined action จะทำการเช็ค state_gesture ที่เป็นท่าทางก่อนจะเกิด last_gesture ว่าเป็นท่าทางเดียวกันกับท่าทางที่เข้ามาล่าสุดหรือไม่ หากเป็นท่าทางเดียวกัน แสดงว่าเป็นช่วงของข้อมูลที่ขาดไป จะไม่ทำการใดๆ แต่หากเป็นคนละท่าทางกันแล้ว จะทำการ map ท่าทางกับคำสั่งและปรับค่า undefined_count ให้เป็น 0 และตั้งให้ state_gesture และ last_gesture ที่ใช้สำหรับเก็บค่าท่าทางให้เป็นท่าทางล่าสุดที่เข้ามา
โดยโค้ดสำหรับปรับการทำงานเบื้องต้นคือ

import os
import webbrowser
from pynput.keyboard import Key, Controller as keyboard_con
from pynput.mouse import Button, Controller as mouse_con
import datetime,time

import kinect_hand as input
from threading import Thread

def show_page():

     # os.system("sleep 5")
     # os.system("chromium-browser -no-sandbox --app=file:///home/pi/Desktop/kinect_hand_detection_and_tracking_2/src/index.html")
     webbrowser.open('file://' + os.path.realpath("/home/scarletdragon/Desktop/kinect_hand_detection_and_tracking_2/src/index.html"))

def key_mapping(gesture):

     keyboard = keyboard_con()
     mouse = mouse_con()

     if gesture == "swipe up":
          mouse.scroll(0 , -5)
     if gesture == "swipe down":
          mouse.scroll(0 , 5)
     if gesture == "swipe left":
          keyboard.press(Key.right)
          keyboard.release(Key.right)
     if gesture == "swipe right":
          keyboard.press(Key.left)
          keyboard.release(Key.left)

     if gesture == "grab down":
          keyboard.press('x')
          keyboard.release('x')
          # print("Grab up")
     if gesture == "grab left" :
          keyboard.press('z')
          keyboard.release('z')
          # print("Grab left")
     if gesture == "grab right" :
          keyboard.press('c')
          keyboard.release('c')
          # print("Grab right")

def get_gesture():

     fps = 0
     last_gesture = "undefined action"
     t0 = time.time()
     tt0 = t0
     tt1 = t0
     used_time = 0
     c = 0
     undefined_count = 0 # use to count undefined action
     state_gesture = "" # use to save state of gesture to check

     while True:
          tc0 = time.clock()
          input.get_input() # get depth input and do image processing and blob tracking
          gesture = input.check_gesture(fps) # get gesture from input data
          t1 = time.time()
          fps = 1/(t1-t0)
          print("Gesture : %s \n" %gesture)

          if gesture == "undefined action":
               if undefined_count == 7: # if found 7 undefined actions
                    undefined_count = 0 # reset count
                    state_gesture = "undefined action" # set state to undefined
               else:
                    undefined_count += 1 # update count
               last_gesture = "undefined action" # set last gesture to undefined

          elif last_gesture != gesture: # if latest gesture is not same as last gesture

               if last_gesture == "undefined action": # if last gesture is undefined

                    if state_gesture != gesture: # check previous state before undefined if same as latest not do anything
                         key_mapping(gesture) # if not map gesture

                    last_gesture = gesture # set last gesture with latest gesture
                    state_gesture = gesture # set state with latest gesture
                    undefined_count = 0 # reset count

               else:
                    key_mapping(gesture) # if last gesture is other gesture then map gesture

               last_gesture = gesture # set last gesture with latest gesture
               state_gesture = gesture # set state with latest gesture
               undefined_count = 0 # reset count

          tt1 = time.time()
          tc1 = time.clock()
          used_time = used_time + (tc1 - tc0)
          tc0 = tc1
          t0 = t1
          c = c + 1

          # if(tt1>tt0+1): # use to get log data
          # print("write row")
          # percent = used_time*100/(tt1 - tt0)
          # fps_a = c / used_time
          # file = open("keymap_prototype.csv","a")
          # file.write(str(datetime.datetime.now()) + "," + str(fps_a) + "," + str(percent) + "," + str(used_time) + "," + str(tt1 - tt0) + "\n")
          # file.close()
          # used_time = 0
          # c = 0
          # tt0 = t0

th0 = Thread(target=show_page, args=())
th0.start()
th1 = Thread(target=get_gesture, args=())
th1.start()

ซึ่งหลังจากลองปรับเปลี่ยนข้อมูลตามวิธีข้างต้นพบว่าสามารถแก้ปัญหาเรื่องการสั่งการที่เกินไปได้

ไม่มีความคิดเห็น:

แสดงความคิดเห็น