---
# System prepended metadata

title: 期末專案 2

---

# 期末專案 2
## Virtual Calculator
### 安裝套件
進入文件設置，點擊==Project: pyramidProject==→==Python Interpreter==
選擇添加==cvzone==、==mediapipe==

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

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

### 導入套件
從cvzone導入手部追蹤模塊中的手部檢測器
==HandDetector==用來檢測我們的手是否點擊了按鈕
```python=
import cv2
from cvzone.HandTrackingModule import HandDetector
```

### 設置鏡頭
指定所要使用的攝影機，並寫一個循環使相機不斷捕捉影像，最後輸出影像
```python=
# 指定使用相機
cap = cv2.VideoCapture(0)
# 不斷地使用相機，並補抓影像
while True:
    # success 中會指定有沒有成功地抓到資料, True 就是成功，False 就是失敗
    # img 如果成功，那 img 中就是目前攝影機的影像
    success, img = cap.read()
    # 將圖片做水平翻轉
    img = cv2.flip(img, 1)

    # 顯示圖像
    cv2.imshow("Image", img)
    # 延遲一毫秒的時間
    cv2.waitKey(1)
```
### 檢測手指
先做初始化設定，並檢測手部
```python=
import cv2
from cvzone.HandTrackingModule import HandDetector
# 指定使用相機
cap = cv2.VideoCapture(0)
# 產生一個手部骨架偵測器，將信心度設為0.8，並且只偵測一隻手
detector = HandDetector(detectionCon=0.8, maxHands=1)

#不斷地使用相機，並補抓影像
while True:
    # success 中會指定有沒有成功地抓到資料, True 就是成功，False 就是失敗
    # img 如果成功，那 img 中就是目前攝影機的影像
    success, img = cap.read()
    # 將圖片做水平翻轉
    img = cv2.flip(img, 1)
    # 將攝影機所擷取的圖片傳入，由圖片中找出手的骨架
    # 回傳值的 hands 就是骨架的資訊
    # img 則是 detector 會在圖片中畫出手的骨架，之後回傳
    hands, img = detector.findHands(img,flipType=False)

    # 顯示圖像
    cv2.imshow("Image", img)
    # 延遲一毫秒的時間
    cv2.waitKey(1)
```
### 初始化按鈕
```python=
#定義一個名為 Button() 的類，並提供位置、寬度和長度作為輸入
#以便我們可以按照明確定義的順序排列鍵盤按鍵
class Button:
    def __init__(self, pos, width, height, value):
        self.pos = pos
        self.width = width
        self.height = height
        self.value = value
    #初始化按鈕，並定義一個名為draw()的函數，它接受兩個引數，即影象和按鈕列表並返回影象
    def draw(self, img):
        cv2.rectangle(img, self.pos, (self.pos[0] + self.width, self.pos[1] + self.height),
                      (225, 225, 225), cv2.FILLED)
        cv2.rectangle(img, self.pos, (self.pos[0] + self.width, self.pos[1] + self.height),
                      (50, 50, 50), 3)
        cv2.putText(img, self.value, (self.pos[0] + 30, self.pos[1] + 70), cv2.FONT_HERSHEY_PLAIN,
                    2, (50, 50, 50), 2)

```
### 創建按鈕
```python=
#給出位置輸入附加在一個名為 button list 的列表中
#我們可以將這個列表傳遞給 draw 函數以在我們的實時框架之上進行繪製
buttonList = []
for x in range(4):
    for y in range(4):
        xpos = x * 100 + 800
        ypos = y * 100 + 150
        buttonList.append(Button((xpos, ypos), 100, 100, '5'))
```

畫出所有按鈕，並放在 while 迴圈中
```python=
while True:
    # success 中會指定有沒有成功地抓到資料, True 就是成功，False 就是失敗
    # img 如果成功，那 img 中就是目前攝影機的影像
    success, img = cap.read()
    # 將圖片做水平翻轉
    img = cv2.flip(img, 1)
    # 將攝影機所擷取的圖片傳入，由圖片中找出手的骨架
    # 回傳值的 hands 就是骨架的資訊
    # img 則是 detector 會在圖片中畫出手的骨架，之後回傳
    hands, img = detector.findHands(img,flipType=False)

    #畫出所有按鈕
    for button in buttonList:
        button.draw(img)

    # 顯示圖像
    cv2.imshow("Image", img)
    # 延遲一毫秒的時間
    cv2.waitKey(1)
```
如下圖所示
![](https://i.imgur.com/ieQXhyh.jpg)

### 按鈕列表值
```python=
#更改列表內的植
buttonListValues = [['7', '8', '9', '*'],
                    ['4', '5', '6', '-'],
                    ['1', '2', '3', '+'],
                    ['0', '/', '.', '=']]
buttonList = []
for x in range(4):
    for y in range(4):
        xpos = x * 100 + 800
        ypos = y * 100 + 150
        #更改動態值設定
        buttonList.append(Button((xpos, ypos), 100, 100, buttonListValues[y][x]))
```
![](https://i.imgur.com/UZKRdM7.png)

### 新增上方計算列
```python=
#新增上方計算列，調整大小及位置
cv2.rectangle(img, (800, 50), (800 + 400, 70 + 100),
                  (225, 225, 225), cv2.FILLED)

cv2.rectangle(img, (800, 50), (800 + 400, 70 + 100),
                  (50, 50, 50), 3)
for button in buttonList:
    button.draw(img)
```
![](https://i.imgur.com/UIBHzhi.png)

### 加入變量
```python=
myEquation = ''
delayCounter = 0
```
#### 找到手指間的距離，判斷是否點擊按鈕
```python=
if hands:
    lmList = hands[0]['lmList']
    #依照食指尖及中指尖的距離來計算是否單擊或沒有
    length, _, img = detector.findDistance(lmList[8], lmList[12], img)
    print(length)
    #將食指定為指標
    x, y = lmList[8]
    
# 單擊檢查哪個按鈕並執行操作
if length < 50 and delayCounter == 0:
    for i, button in enumerate(buttonList):
        if button.checkClick(x, y):
            myValue = buttonListValues[int(i % 4)][int(i / 4)] 
            # 得到正確的數字
            if myValue == '=':
                 myEquation = str(eval(myEquation))
            else:
                myEquation += myValue
                delayCounter = 1
```
#### 檢查是否已點擊
```python=
    #檢查Ｘ、Ｙ初始值與寬度、高度和顏色
    def checkClick(self, x, y):
        if self.pos[0] < x < self.pos[0] + self.width and \
                self.pos[1] < y < self.pos[1] + self.height:
            cv2.rectangle(img, (self.pos[0] + 3, self.pos[1] + 3),
                          (self.pos[0] + self.width - 3, self.pos[1] + self. 
                           height - 3),(255, 255, 255), cv2.FILLED)
            cv2.putText(img, self.value, (self.pos[0] + 25, 
                        self.pos[1] + 80), cv2.FONT_HERSHEY_PLAIN,5, (0, 0, 0), 5)
            return True
        else:
            return False
```
#### 顯示結果
```python=
cv2.putText(img, myEquation, (810, 120), cv2.FONT_HERSHEY_PLAIN,
                3, (0, 0, 0), 3)
```
![](https://i.imgur.com/L77mOOs.png)

### 延遲設定
```python=
# to avoid multiple clicks
＃設定延遲計數器和計數器
    if delayCounter != 0:
        delayCounter += 1
        if delayCounter > 10:
            delayCounter = 0
```
```python=
    # 顯示圖像
    key = cv2.waitKey(1)
    cv2.imshow("Image", img)
    if key == ord('c'):
        myEquation = ''
 ```

[Code](https://www.computervision.zone/lessons/code-and-files-9)

[Video](https://www.youtube.com/watch?v=DZMJ77akgec&t=3536s)