วันอาทิตย์ที่ 26 พฤษภาคม พ.ศ. 2562

ผลสรุปเวลาการทำงานของระบบรุ่นต้นแบบและรุ่นปรับปรุงโดยใช้ time.clock จาก Raspberry Pi

จากผลทดลองของบทความก่อนหน้าที่ได้ทำการสรุปเวลาการทำงานตั้งแต่เริ่มต้นทำ Image Processing ไปจนถึงการแปลงท่าทางที่ได้เป็นคำสั่งของโปรแกรมรุ่นต้นแบบและรุ่นปรับปรุงจากการใช้ multiprocessing และ pipeline แล้วนั้นได้ทำการทดลองบนเครื่อง Lenovo z580

ในการทดสอบครั้งนี้ได้ทำการทดสอบเก็บผลจากบอร์ด Raspberry Pi 3 Model B+ ซึ่งเป็นอุปกรณ์ที่ใช้ในตัว Smart Mirror เพื่อทดสอบว่าจะสามารถปรับปรุงประสิทธิภาพการทำงานของระบบจริงได้หรือไม่

 โดยจะแบ่งออกเป็น 2 กลุ่มหลักคือ กลุ่มแรกที่ใช้ threading module ซึ่งเป็นวิธีการของรุ่นต้นแบบ และกลุ่มที่ 2 คือกลุ่มที่ใช้ multiprocessing ซึ่งเป็นวิธีการของรุ่นปรับปรุง แต่ละกลุ่มจะแบ่งเป็น 2 วิธีย่อยคือ วิธีการทำงานแบบไม่ใช้ pipeline และวิธีการทำงานโดยใช้ pipeline และแต่ละข้อมูลจะประกอบไปด้วยช่วงเวลาการทำงานของระบบทั้งหมด 400 ชุด เพื่อนำมาใช้ในการหาค่าเฉลี่ยของช่วงเวลาการทำงานของระบบ

โดยผลของเวลาเฉลี่ยรวมถึงเปอร์เซนต์การทำงานของ CPU มีดังนี้


Mean clock time not use pipeline with thread in raspberry pi : 0.0884469275


Mean clock time not use pipeline with process in raspberry pi : 0.083370595


Mean clock time using pipeline with thread in raspberry pi : 0.135355755


Mean clock time using pipeline with process in raspberry pi : 0.0634883825

จากผลลัพธ์ข้างต้น จะพบว่าค่าเวลาเฉลี่ยของทั้ง 4 วิธีนั้นมีความใกล้เคียงกัน มีเพียงวิธีการใช้ pipeline ร่วมกับ thread ที่มีค่าเวลาเฉลี่ยมากกว่าอีก 3 วิธี อีกทั้งเปอร์เซนต์การใช้งานของ CPU ยังอยู่ในระดับเดียวกันด้วย จากผลลัพธ์ข้างต้น สามารถนำมาสรุปเบื้องต้นได้ว่าการดัดแปลงระบบ pipeline มาใช้ร่วมกับ multiprocess นั้นยังไม่สามารถปรับปรุงประสิทธิภาพของตัวระบบได้ดีพอ


วันศุกร์ที่ 24 พฤษภาคม พ.ศ. 2562

ผลสรุปเวลาการทำงานของระบบรุ่นต้นแบบและรุ่นปรับปรุงโดยใช้ time.clock เพิ่มเติม

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

กลุ่มแรกที่ใช้ threading module ซึ่งเป็นวิธีการของรุ่นต้นแบบ
และกลุ่มที่ 2 คือกลุ่มที่ใช้ multiprocessing ซึ่งเป็นวิธีการของรุ่นปรับปรุง

แต่ละกลุ่มจะแบ่งเป็น 2 วิธีย่อยคือ วิธีการทำงานแบบไม่ใช้ pipeline และวิธีการทำงานโดยใช้ pipeline และแต่ละข้อมูลจะประกอบไปด้วยช่วงเวลาการทำงานของระบบทั้งหมด 400 ชุด เพื่อนำมาใช้ในการหาค่าเฉลี่ยของช่วงเวลาการทำงานของระบบ

โดยผลที่ได้คือ

Mean clock time not use pipeline thread : 0.006046565

Mean clock time using pipeline thread : 0.012087405

Mean clock time not use pipeline process : 0.0086365625

Mean clock time using pipeline process : 0.008092675

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

วันอังคารที่ 21 พฤษภาคม พ.ศ. 2562

ผลสรุปเวลาการทำงานของระบบรุ่นต้นแบบและรุ่นปรับปรุงโดยใช้ time.clock

โดยผลทดสอบนี้จะทำการเก็บค่าเวลาของ time.clock() ตั้งแต่เริ่มต้นการทำงานตั้งแต่การทำ Image Processing จนเสร็จสิ้นการแปลงท่าทางที่ได้เป็นคำสั่ง โดยทำการแบ่งข้อมูลออกเป็น 2 ชุด คือ ข้อมูลที่ได้จากโปรแกรมรุ่นต้นแบบ และ ข้อมูลที่ได้จากโปรแกรมที่ทำการปรับปรุงโดยใช้ Multiprocessing และ Pipeline Program เข้ามาเสริมการทำงาน โดยข้อมูลทั้ง 2 ชุดนั้นจะเก็บเวลาการทำงานจาก time.clock() ไว้ทั้ง 400 จุด และนำมาทำการหาค่าเฉลี่ยเพื่อตรวจอสอบว่าการปรับปรุงส่งผลให้ประสิทธิภาพนั้นเร็วขึ้นหรือไม่

โดยผลทดสอบที่ได้คือ

Mean clock time not use pipeline : 0.0078674975
Mean clock time using pipeline : 0.00783607

จะพบว่าเวลาของทั้ง 2 วิธีนั้นใกล้เคียงกันมาก ซึ่งจากผลที่ได้สามารถสรุปในเชิงเบื้องต้นได้ว่าการปรับปรุงระบบโดยใช้ Multiprocessing และ Pipeline Program เข้ามาเสริมการทำงานนั้นยังส่งผลได้ไม่ดีเท่าที่ควร

โค้ดที่ใช้สำหรับทดสอบ

import csv

dataset = 400

with open('clocK time delay.csv') as csvfile:
     readCSV = csv.reader(csvfile, delimiter=',')

     clock_delay = []
     for row in readCSV: # print(row[4])
          clock_delay.append(float(row[4]))

     delay_sum = 0
     for i in range(dataset):
          delay_sum += clock_delay[i]
          print("Mean clock time not use pipeline : %s" % (delay_sum/dataset))

with open('clock time pipeline.csv') as csvfile:
     readCSV = csv.reader(csvfile, delimiter=',')

     clock_pipeline = []
     for row in readCSV:
          clock_pipeline.append(float(row[1]))

     pipeline_sum = 0
     for i in range(dataset):
          pipeline_sum += clock_pipeline[i]
          print("Mean clock time using pipeline : %s" % (pipeline_sum/dataset))

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

การกด Keyboard เพื่อเปลี่ยนสีรูป

การกด Keyboard เพื่อเปลี่ยนสีรูปสามารถแบ่งเป็นขั้นตอนได้ดังนี้
    1. ใส id ลงใน <img>
    2. สร้าง class ที่ใช้ในการเปลี่ยนสีใน css
    3. สร้างเงื่อนไขเมื่อกด keyboard


1. ใส่ id ให้กับ img tag เพื่อที่จะสามารถใช้คำสั่งเจาะจงไปที่ id นั้น

    <img id="leftarrow" src="left arrow.png">



left arrow.png

2. สร้าง Class ที่ใช้ในการเปลี่ยนสี

    <style>
        .add_red {
          -webkit-filter: opacity(.5) drop-shadow(0 0 0 red);
          filter: opacity(.6) drop-shadow(0 0 0 red);
       }
    </style>

    ฟังก์ชันที่ใช้ มีดังนี้

    1.opactity(%) ใช้ในการกำหนดความทึบแสงของภาพ ซึ่งระดับของความทึบแสงจะบอกถึงระดับโปร่งใสของภาพ โดย
    0% คือ ภาพมีความโปร่งใสมากที่สุด
    100% คือ ภาพต้นแบบที่ไม่มีการปรับระดับความทึบแสง

                                       opacity(100%)                                      opacity(50%)

    2.drop-shadow ใช้ในการเพิ่มเงาลงในภาพ โดยจะมีตัวแปรดังนี้

        - offset-x offset-y  โดยที่ offset-x จะกำหนดตำแหน่งของเงาในแนวราบ โดยถ้ามีค่าเป็นลบ เงาจะมีทิศไปทางขวา และ offset-y จะกำหนดตำแหน่งในแนวนอน โดยถ้าตั้งค่าเป็นลบ เงาจะมีทิศขึ้น
        - blur-radius ใช้ในการกำหนดรัศมีการเบลอภาพ ซึ่งการเบลอของภาพจะเพิ่มขึ้นตามค่าที่ได้รับเข้ามา
        - spread-radius ใช้กำหนดขนาดของเงา ยิ่งมีค่ามากก็เงาก็จะใหญ่ตามค่าที่ได้รับ ถ้าค่าติดลบ เงานที่ได้จะมีขนาดเล็กลง


        เราใช้ทั้งสองคุณสมบัตินี้ในการเพิ่มสีให้กับรูปสีขาว คือการสร้างเงาที่เป็นสีที่เราต้องการ จากนั้นทำให้ภาพโปร่งใส จนเห็นสีของเงา

3. สร้างเงื่อนไขเมื่อกด keyboard

    <script>
    document.onkeydown = function(e) {
        var keyCode = e.keyCode;

        if (keyCode == 37) { //left arrow on keyboard
            $("#leftarrow").addClass("add_red");
            setTimeout(
                function() {
                    $("#leftarrow").removeClass("add_red")
                }, 300
            );
        }
    };
    </script>

    วิธีที่เราจะนำ Class ที่ใช้ในการเปลียนสีมาใช้ คือ ใช้ฟังก์ชัน addClass เพื่อที่จะเพิ่ม Class ลงใน selector ที่ชื่อ leftarrow จากโค้ดด้านบน เมื่อกดปุ่ม left arrow บน keyboard ( มีค่าเท่ากับ 37 ในตาราง ascii) เมื่อกด ตัวลูกศรจะเปลี่ยนสี หลังจากนั้น .3 วินาที จึงจะกลับมาเป็นสีขาวเหมือนเดิม


วันศุกร์ที่ 17 พฤษภาคม พ.ศ. 2562

การปรับปรุงเงื่อนไขของ keymapping

จากเงื่อนไขของการทำ Keymapping ของบทความก่อนหน้านั้น ได้ทดลองปรับปรุงเงื่อนไขใหม่คือ
โดยแบ่งวิธีคิดเป็น 2 วิธีคือ
  1. เก็บค่าในการสั่งงานในแต่ละครั้ง เพื่อใช้ในการเว้นเวลาในการสั่งแต่ละรอบ  
  2. เปลี่ยนการนับจำนวนของการเกิด undefined action ตามเงื่อนไข เป็นการเช็คผลต่างของเวลา
    โดยวิธีแรกนั้นจะตั้งตัวแปรที่จะเปลี่ยนสถานะเมื่อถึงเวลาที่กำหนด (เวลาที่ใช้ในการสั่งงานในแต่ละครั้ง) ใช้สำหรับเช็คเงื่อนไขของการที่จะทำการ mapping ในแต่ละครั้ง โดยในที่นี้จะใช้ตัวแปร start แทน หากเป็น 0 จะทำการไปตรวจเช็คผลต่างของเวลาว่า ครบรอบเวลาการทำงานใน 1 ครั้งหรือไม่ ถ้าหากถึงเวลานั้นแล้วจะเปลี่ยนให้ start เป็น 1
    ต่อมา ถ้าหากเป็น 1 และท่าทางที่เข้ามานั้นไม่ใช่ undefined action จะทำการตรวจสอบท่าทางและทำการ mapping หลังจากนั้นจะทำการ reset timer เพื่อใช้เช็คผลต่างของเวลาในครั้งถัดไป

โดยดูได้จาก state diagram ด้านล่าง



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

โดยโค้ดของการทำงานมีดังนี้

def get_gesture():

     fps = 0
     last_gesture = "undefined action"
     t0 = time.time()

     start_time = timer()
     start = 1 # use as a state check

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

          # if state is ready and new gesture is not undefined
          if start == 1 and gesture != "undefined action":
               # set state check to not ready
               start = 0
               if last_gesture != gesture:
                    key_mapping(gesture)
               last_gesture = gesture

               end_time = timer()
               diff_time = end_time - start_time
               print("Action time : %s \n" %diff_time)
               start_time = end_time

          else:

               end_time = timer()
               diff_time = end_time - start_time
               print("Different time : %s \n" %diff_time)
               if diff_time >= 1:
                    start = 1
                    start_time = end_time

               last_gesture = "undefined action"

          t0 = t1

วิธีที่ 2 จะแบ่งเป็น 2 เงื่อนไข ดังนี้

  1. หาก gesture ล่าสุดต่างกับ previous gesture จะทำการตรวจสอบก่อนว่า previous gesture นั้นเป็น undefined action หรือไม่ หากใช่ แสดงว่าอาจเกิดช่วงของข้อมูลที่ตกหล่นไป จะทำการเช็คอีกเงื่อนไขคือ gesture ก่อนเกิด undefined action นั้นต่างกับ gesture ล่าสุดหรือไม่ หากไม่ต่างกันแสดงว่าเกิดการตกหล่นของข้อมูลจริง จะไม่สั่งการเพิ่ม หากผลออกมาต่างกัน จะทำการ mapping คำสั่งตาม gesture ใหม่ที่เข้ามา 
  2. หาก gesture ที่เข้ามาเป็น undefined action จะทำการเช็คเวลาว่าเป็น ช่วงของ undefined action หรือไม่ หากใช่จะทำการปรับค่า gesture ที่บันทึกไว้สำหรับเช็คช่วงของข้อมูลที่ตกหล่นให้เป็น undefined action เพื่อป้องกันกรณีที่ต้องการสั่งคำสั่งเดิมอีกครั้งแต่ระบบมองว่าเป็นคำสั่งเดิมที่เกิดจากข้อมูลตกหล่นอันเป็นผลมาจากเงื่อนไขที่ 1
เมื่อทำเสร็จเงื่อนไขใดเงื่อนไขหนึ่ง จะทำการ reset timer เพื่อนำไปใช้ในการคำนวณเงื่อนไขเวลาในครั้งถัดไป โดยสามารถดูเพิ่มเติมได้จาก state diagram ดังรูปด้านล่าง



โดยค่าเวลานี้ได้มาจากการจับเวลาช่วงที่เกิด undefined action ใน 1 ครั้ง ว่าในตอนที่ตรวจจับไม่พบหรือไม่มีท่าทางเข้ามานั้นจะใช้เวลาในการตรวจจับเท่าใด โดยทำการเก็บเวลาที่ใช้ในการเกิด undefined action มาทั้งหมด160 ครั้ง และนำมาหาค่าเฉลี่ยซึ่งได้เวลาเฉลี่ยต่อการการเกิด undefined action อยู่ที่ 0.04 วินาที และต้องการเว้นช่วงที่ใช้ในการตรวจสอบประมาณ 7 ช่วง จึงได้เวลาที่ใช้สำหรับเงื่อนไขเป็น 0.04*7 เท่ากับ 0.28 วินาทีโดยประมาณ

โดยโค้ดของการทำงานวิธีที่2มีดังนี้

def get_gesture():

     fps = 0
     last_gesture = "undefined action"
     t0 = time.time()

     start_time = timer()
     # use to count undefined action
     undefined_count = 0
     # use to save state of gesture to check
     state_gesture = ""

     while True:

          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":

               end_time = timer()
               diff_time = end_time - start_time
               print("Different time : %s" %diff_time)

               if diff_time >= 0.28:
                    state_gesture = "undefined action"
                    start_time = end_time
                    last_gesture = "undefined action"

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

               # if last gesture is undefined
               if last_gesture == "undefined action":
                    # check previous state before undefined if same as latest not
                    if state_gesture != gesture:
                         # if not map gesture
                         key_mapping(gesture)

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

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

               end_time = timer()
               diff_time = end_time - start_time
               print("Action time : %s" %diff_time)
               start_time = end_time

          t0 = t1

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

วันอังคารที่ 14 พฤษภาคม พ.ศ. 2562

การทำ User Manual

    ในการทำ User manual เราจะใช้ ภาพลูกศรภาพเดียว ในการบอกถึงทิศทาง โดยเราจะใช้ฟังก์ชัน flip(), rotate()


    รูปข้างต้นจะเป็นลูกศรชี้ไปทางขวา ถ้าเราอยากได้ลูกศรที่ชี้ไปทางซ้าย เราจะใช้ฟังก์ชัน flip() ดังนี้

    <style>    
      img.flip {
        transform: scaleX(-1);
      }
    </style>
    <img class="flip" src="left arrow.png">



    ในส่วนของการปรับให้รูปต้นแบบลูกศร เป็นขึ้นหรือลง จะใช้เป็นฟังก์ชัน rotate() ดังนี้

    <style>
      img.rotate90 {
        transform: rotate(90deg);
      }
      img.rotate270 {
         transform: rotate(270deg);
      }
    </style>

    <img class="rotate90" src="left arrow.png" >
    <img class="rotate270" src="left arrow.png">

    ซึ่งในหน้า User Manual จะออกแบบได้เบื้องต้นดังภาพ

วันจันทร์ที่ 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()

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