วันพฤหัสบดีที่ 11 ตุลาคม พ.ศ. 2561

หลักการทำงานของโค้ด Smart Mirror & Hand Detection ( Part 2 ส่วนเค่าและตรวจสอบว่าเป็นมือหรือไม่ )

ต่อจาก Part ที่แล้วในส่วนถัดไปจะเป็นการทำงานของ BlobAnalysis โดยมีการทำงานดังนี้

  • ทำการวน Loop ตามความยาวของ array cs
  • ส่งค่า array cs ชุดที่ i ไปที่ class BlobAnalysis เพื่อเตรียมการคำนวณ


  • ในที่นี้ cs[i] ที่ส่งเข้ามาจะถูกเก็บในตัวแปรชื่อ contour ซึ่ง self.contour ก็คือการเก็บค่า contour ไว้ใช้ใน class 
  • self.contour_s คือตัวแปรที่เก็บค่า contour ซึ่งถูกปรับการเรียงเป็นแนวตั้ง และ squeeze() คือการลบ array นอกสุดออก 1 มิติ เช่น หากข้อมูลมีลักษณะเป็น [ [1,2] ] array ตัวนอกจะถูกลบออก
    1 มิติ กลายเป็น [ 1,2 ] แทน
  • self.contour_point จะไปเรียกฟังค์ชันซึ่งทำการนำ array self.contour_s มาแปลงค่าเป็น numpy array เป็น python list เพื่อให้สามารถทำการคำนวณใน python ได้ง่ายขึ้น
  • self.centroid จะไปเรียกฟังค์ชัน get_centroid() เพื่อนำค่า self.contour ไปคำนวณ Moment เพื่อนำมาหาจุดศูนย์กลางของข้อมูล ผลที่ได้จะเป็นลักษณะคู่อันดับ (x,y)
  • self.convex_hull จะเรียกฟังค์ชัน get_convex_hull โดยจะนำ self.contour มาทำการหา hull หรือส่วนโค้งเว้าใน contour นำมาคำนวณเพื่อเก็บใส่ตัวแปร epsilon และนำ hull กับ epsilon ไปเพื่อปรับค่า contour ในคำสั่ง cv2.approxPolyDP(convexHull,epsilon,True) และปรับการเรียงเป็นแนวตั้งพร้อมลบ array นอกสุดออก 1 มิติ และแปลงค่าจาก numpy array เป็น python list ก่อนทำการเก็บค่า
  • self.approx_hull_count จะทำการเก็บค่าความยาว self.convex_hull ไว้
  • self.id กำหนดให้มีค่าเป็น -1
  • self.area ทำการเก็บค่าพื้นที่ของ contour ด้วยคำสั่ง cv2.contourArea(self.contour)
  • self.deflect_count_90 จะเรียกฟังค์ชัน get_deflect_count(90) โดยค่าที่ส่งไปคือมุมที่เราต้องการทำไปคิด และนำ self.contour มาหา convex_hull จากนั้นนำ contour กับ hull มาทำการหา deflect ของภาพ จากนั้นจะนำ deflect มาทำการคำนวณหามุม และเข้าเงื่อนไขเพื่อเช็คว่าค่ามุมที่หามาได้น้อยกว่าหรือเท่ากับ 90 หรือไม่ ซึ่งก็คือการหามุมระหว่างร่องมือ หากไม่ถึง 90 จะเพิ่มค่า count 1 ค่า คนครบทุกตัว และเก็บค่า count ไป
  • self.isHand จะเรียกคำสั่ง self.check_isHand() ซึ่งจะนำค่า self.deflect_count_90 มาเข้าเงื่อนไขว่ามีค่า == 4 หรือไม่ ซึ่งเป็นการเปรียบเทียบว่า มือเรานั้นจะมีร่องมือเพียง 4 ร่องเท่านั้น หากมีค่าเท่ากับ 4 พอดีแสดงว่า blob ที่ได้มานั้นเป็นรูปมือจริงๆ จะทำการเก็บค่าเป็น True หากมีค่ามากกว่า 4 หรือน้อยกว่า 4 แสดงว่าไม่ใช่มือ เป็นอันเสร็จสิ้นการทำงานส่วนเก็บค่าตัวแปร
แหล่งอ้างอิง

squeeze :
https://www.tutorialspoint.com/numpy/numpy_squeeze.htm

np.vstack :
https://www.tutorialspoint.com/numpy/numpy_vstack.htm

np.array().tolist()
https://stackoverflow.com/questions/1966207/converting-numpy-array-into-python-list-structure

moment, epsilon, convexHull :
https://docs.opencv.org/3.1.0/dd/d49/tutorial_py_contour_features.html
https://www.learnopencv.com/find-center-of-blob-centroid-using-opencv-cpp-python/

โค้ดส่วนที่ทำงาน

class BlobAnalysis:
    def __init__(self,contour):
        self.contour = contour
        self.contour_s = np.vstack(contour).squeeze()
        self.contour_point = self.get_contour_point()
        self.centroid = self.get_centroid()
        self.convex_hull = self.get_convex_hull()
        self.approx_hull_count = self.get_approx_hull_count()
        self.id = -1
        self.area = cv2.contourArea(self.contour)
        self.deflect_count_90 = self.get_deflect_count(90)
        self.isHand = self.check_isHand()

    def set_id(self,i):
        self.id = i

    def get_contour_point(self):
        return np.array(self.contour_s).tolist()

    def get_centroid(self):
        m = cv2.moments(self.contour)
        cX = int(m['m10'] / m['m00'])
        cY = int(m['m01'] / m['m00'])
        return (cX, cY)

    def get_convex_hull(self):
        convexHull = cv2.convexHull(self.contour)
        epsilon = 0.015*cv2.arcLength(convexHull,True)
        approx = cv2.approxPolyDP(convexHull,epsilon,True)
        approx = np.vstack(approx).squeeze()
        return np.array(approx).tolist()

    def get_approx_hull_count(self):
        approx = self.convex_hull
        return len(approx)

    def get_deflect_count(self,max_angle):
        count = 0
        hull = cv2.convexHull(self.contour,returnPoints = False)
        defects = cv2.convexityDefects(self.contour, hull)
        for i in range(defects.shape[0]):
            s,e,f,d = defects[i,0]
            start = self.contour_s[s]
            end = self.contour_s[e]
            far = self.contour_s[f]
            a = math.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2)
            b = math.sqrt((far[0] - start[0])**2 + (far[1] - start[1])**2)
            c = math.sqrt((end[0] - far[0])**2 + (end[1] - far[1])**2)
            angle = math.acos((b**2 + c**2 - a**2)/(2*b*c)) * 57
            if angle <= max_angle:
                count += 1
        return count

    def check_isHand(self):
        if self.deflect_count_90 == 4 :
            return True
        else:
            return False

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

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