---
# System prepended metadata

title: 人工智慧導論專題製作

---

# 人工智慧導論專題製作
## *MediaPipe Hand* 電腦猜拳遊戲
##### 報告者:D1173566 資訊一乙 蔡耀東

---

### MediaPipe Hand 簡略介紹

Mediapipe 偵測手掌後，會在手掌與手指上產生 21 個具有 x、y、z 座標的節點，透過包含立體深度的節點，就能在 3D 場景中做出多種不同的應用，下圖標示出每個節點的順序和位置。

![](https://i.imgur.com/XUr3ray.png)

搭配 Mediapipe 手掌偵測的方法，透過攝影鏡頭獲取影像後，即時標記出手掌骨架和動作。

---

### 以下為進度以及部分程式碼
#### 程式碼
```python 
import cv2
import mediapipe as mp
import time


cap = cv2.VideoCapture(0)
mpHands = mp.solutions.hands
hands = mpHands.Hands()
mpDraw = mp.solutions.drawing_utils
handSpoStyle = mpDraw.DrawingSpec(color=(0, 255, 20), thickness=5)
handConStyle = mpDraw.DrawingSpec(color=(255, 20, 255), thickness=3)
previousTime = 0
currentTime = 0


while True:
    ret, img = cap.read()
    if ret:
        imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        result = hands.process(imgRGB)
        # print(result.multi_hand_landmarks)
        imgHeight = img.shape[0]
        imgWidth = img.shape[1]

        if result.multi_hand_landmarks:
            for handLms in result.multi_hand_landmarks:  # print the landmarks on hand
                mpDraw.draw_landmarks(
                    img, handLms, mpHands.HAND_CONNECTIONS, handSpoStyle, handConStyle)
                # print the point's coordinates
                for i, lm in enumerate(handLms.landmark):
                    xPosition = int(lm.x * imgWidth)
                    yPosition = int(lm.y * imgHeight)
                    cv2.putText(img, str(i), (xPosition - 25, yPosition + 5),
                                cv2.FONT_HERSHEY_SCRIPT_SIMPLEX, 0.4, (0, 215, 255), 2)
                    

        currentTime = time.time()
        fps = 1 / (currentTime - previousTime)
        previousTime = currentTime
        cv2.putText(img, f"FPS : {int(fps)}", (30, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 255), 3)

        cv2.imshow('img', img)



    if cv2.waitKey(1) == ord('q'):
        break
```

---

#### 目前進度
https://youtu.be/d_oCL-c8xg4

## 未來增加項目
* 手勢偵測(剪刀，石頭，布)
* 電腦判斷輸贏
* 提供選項輸入
* 透過猜拳輸出選項、答案

---
## 最終成果
程式碼
```python=
import cv2
import mediapipe as mp
import math
import random


mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands


ans1 = input('輸入你的選項:')
print('你的選項是:'+ans1)
ans2 = input('輸入電腦的選項:')
print('電腦的選項是:'+ans2)
print("請比OK手勢開始猜拳")


def vector_2d_angle(v1, v2):
    v1_x = v1[0]
    v1_y = v1[1]
    v2_x = v2[0]
    v2_y = v2[1]
    try:
        angle_ = math.degrees(math.acos(
            (v1_x*v2_x+v1_y*v2_y)/(((v1_x**2+v1_y**2)**0.5)*((v2_x**2+v2_y**2)**0.5))))
    except:
        angle_ = 180
    return angle_


def hand_angle(hand_):
    angle_list = []
    # thumb angle
    angle_ = vector_2d_angle(
        ((int(hand_[0][0]) - int(hand_[2][0])),
         (int(hand_[0][1])-int(hand_[2][1]))),
        ((int(hand_[3][0]) - int(hand_[4][0])),
         (int(hand_[3][1]) - int(hand_[4][1])))
    )
    angle_list.append(angle_)
    # forefinger angle
    angle_ = vector_2d_angle(
        ((int(hand_[0][0])-int(hand_[6][0])),
         (int(hand_[0][1]) - int(hand_[6][1]))),
        ((int(hand_[7][0]) - int(hand_[8][0])),
         (int(hand_[7][1]) - int(hand_[8][1])))
    )
    angle_list.append(angle_)
    # middlefinger angle
    angle_ = vector_2d_angle(
        ((int(hand_[0][0]) - int(hand_[10][0])),
         (int(hand_[0][1]) - int(hand_[10][1]))),
        ((int(hand_[11][0]) - int(hand_[12][0])),
         (int(hand_[11][1]) - int(hand_[12][1])))
    )
    angle_list.append(angle_)
    # ringfinger angle
    angle_ = vector_2d_angle(
        ((int(hand_[0][0]) - int(hand_[14][0])),
         (int(hand_[0][1]) - int(hand_[14][1]))),
        ((int(hand_[15][0]) - int(hand_[16][0])),
         (int(hand_[15][1]) - int(hand_[16][1])))
    )
    angle_list.append(angle_)
    # pinky angle
    angle_ = vector_2d_angle(
        ((int(hand_[0][0]) - int(hand_[18][0])),
         (int(hand_[0][1]) - int(hand_[18][1]))),
        ((int(hand_[19][0]) - int(hand_[20][0])),
         (int(hand_[19][1]) - int(hand_[20][1])))
    )
    angle_list.append(angle_)
    return angle_list


def hand_pos(finger_angle):
    f1 = finger_angle[0]   # thumb
    f2 = finger_angle[1]   # forefinger
    f3 = finger_angle[2]   # middlefinger
    f4 = finger_angle[3]   # ringfinger
    f5 = finger_angle[4]   # picky
    # < 50 stretch，>= 50 curl

    if f1 >= 50 and f2 >= 50 and f3 >= 50 and f4 >= 50 and f5 >= 50:
        return 2
    elif f1 >= 50 and f2 < 50 and f3 < 50 and f4 >= 50 and f5 >= 50:
        return 1
    elif f1 < 50 and f2 < 50 and f3 < 50 and f4 < 50 and f5 < 50:
        return 0
    elif f1 >= 50 and f2 >= 50 and f3 < 50 and f4 < 50 and f5 < 50:  # ok
        return 3
    elif f1 < 50 and f2 >= 50 and f3 < 50 and f4 < 50 and f5 < 50:
        return 3
    else:
        return 4


def int2hand(interger):
    int2hand = ['Paper', 'Scissor', 'Stone', 'ok']
    return int2hand[interger]


def game(your):
    cp = random.randint(0, 2)
    print("電腦出:" + int2hand(cp))

    win = [1, 2, 0]
    lose = [2, 0, 1]

    if (your == win[cp]):
        print("You win!")
        print("最終選項是"+ans1)
    elif (your == lose[cp]):
        print("You lose!")
        print("最終選項是"+ans2)
    else:
        print("平手，請在猜一次")


cap = cv2.VideoCapture(0)            # read camera
fontFace = cv2.FONT_HERSHEY_SIMPLEX  # print text
lineType = cv2.LINE_AA               # print text

start = False

# mediapipe tracking hands
with mp_hands.Hands(
        model_complexity=0,
        min_detection_confidence=0.7,
        min_tracking_confidence=0.7) as hands:

    if not cap.isOpened():
        print("Cannot open camera")
        exit()
    w, h = 540, 310
    while True:
        ret, img = cap.read()
        img = cv2.resize(img, (w, h))
        if not ret:
            print("Cannot receive frame")
            break
        img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        results = hands.process(img2)
        if results.multi_hand_landmarks:
            for hand_landmarks in results.multi_hand_landmarks:
                finger_points = []
                for i in hand_landmarks.landmark:
                    xPosition = i.x*w
                    yPosition = i.y*h
                    finger_points.append((xPosition, yPosition))

                if finger_points:
                    finger_angle = hand_angle(finger_points)
                    # print(finger_angle)
                    your = hand_pos(finger_angle)            # return pose

                    if (your <= 3):
                        cv2.putText(img, int2hand(your), (30, 120), fontFace, 3,
                                    (255, 255, 255), 10, lineType)  # print text

                    if (your != 4):
                        if (start == False and your == 3):
                            start = True
                        elif (start == True and your != 3):
                            game(your)
                            start = False

        cv2.imshow('img', img)
        if cv2.waitKey(5) == ord('q'):
            break


cap.release()
cv2.destroyAllWindows()

```
### 程式執行
#### 輸入兩個選項
![](https://i.imgur.com/eW7o55y.png)
#### 鏡頭打開，開始猜拳，得出最終結果![](https://i.imgur.com/xG8V9yf.png)

---

### 最終成果展示
[展示影片](https://youtu.be/-OCqrDLLS-Q)



