讓我們Py在一起:手勢控制PowerPoint放映切換

作者:Ted Lee

在先前的拙著《Python玩AI,你也可以》中,成功的解析了「剪刀石頭布RSP」實例(RSP.py)。緊接著,我們也測試了PowerPoint檔自動放映的範例(Slideshow.py)。本文嘗試將這兩隻個別測妥的程式合併成可以「用手勢自動切換PowerPoint」的小專案(PPT controller.py),並以此過程來展示專案開發的技巧:

將大問題拆解為數個小問題後,再將各部份的解答回組成原解。

圖1詳盡地說明本文發展的過程:第一線,和陳會安老師學了CVzone的 ch6-5.py 範例後,我們先很用功的寫出每一行程式的註解 cvzoneRSP_詳註.py 。接著,再發想出用手勢來控制PowerPoint的播放切換。隨後,著手搜尋並測試了 PPT slideshow.py 這個程式片段。完成之後,我們將這兩隻程式合拼成 PPT controller.py。

圖1:手勢控制PowerPoint切換的演進過程。

cvzoneRSP_詳註.py

詳細說明請讀者參閱《Python玩AI,你也可以》,以下僅列出完整程式碼:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from cvzone.HandTrackingModule import HandDetector #L5初始化用
import cv2
cap = cv2.VideoCapture(0) #攝影機的handler
detector = HandDetector(detectionCon=0.5, maxHands=1) #detectionCon:偵測的信心值(confidence)、maxHands:可測到幾隻手
while cap.isOpened(): #當攝影機被開啟時
    success, img = cap.read() #回傳攝影機讀到的影像
    hands, img = detector.findHands(img) #從影像中中偵測手
    if hands: #如果有偵測到手
        hand = hands[0]
        bbox = hand["bbox"] #bbox: bounding box
        fingers = detector.fingersUp(hand) #fingers = [手指1, 手指2, 手指3, 手指4, 手指5]
        totalFingers = fingers.count(1) #fingers裡有個1
        print(totalFingers)
        msg = "None" #顯示剪刀、石頭、布
       
        if totalFingers == 5:
            msg = "Paper"
           
        if totalFingers == 0:
            msg = "Rock"
           
        if totalFingers == 2:
            if fingers[1] == 1 and fingers[2] == 1: #食指 + 中指
                msg = "Scissors"
               
        cv2.putText(img, msg, (bbox[0]+200,bbox[1]-30), cv2.FONT_HERSHEY_PLAIN, 2, (0, 255, 0), 2) #顯示bbox框框 + 訊息
    cv2.imshow("Image", img) #顯示圖片img,視窗標題為Image
   
    if cv2.waitKey(1) & 0xFF == ord("q"): #按q離開迴圈
        break
   
cap.release() #釋放攝影機handler cap
cv2.destroyAllWindows() #關閉視窗

PPT slideshow.py
這篇Satck Overflow中的文章展示如下的程式碼,它是援用Python版的Win32擴充(extensions) pywin32 使用 COM(Component Object Model ,元件物件模型) 來控制PowerPoint


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import win32com.client #L4, 5用
import time #L8, 11, 14, 17用

app = win32com.client.Dispatch("PowerPoint.Application")
presentation = app.Presentations.Open(FileName=u'd:\\要播放的PowerPoint檔.pptx', ReadOnly=1)  #開啟PowerPoint檔

presentation.SlideShowSettings.Run()  #PowerPoint放映
time.sleep(1) #延遲一段時間

presentation.SlideShowWindow.View.Next()  #切換到下一頁
time.sleep(1)

presentation.SlideShowWindow.View.Next()  #切換到下一頁
time.sleep(1)

presentation.SlideShowWindow.View.Previous()  #切回到上一頁
time.sleep(1)

presentation.SlideShowWindow.View.Exit() #關閉PowerPoint檔
app.Quit() #關閉PowerPoint

讓我們Py在一起:PPT controller.py

cvzoneRSP_詳註.py 和 PPT slideshow.py 整併如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import win32com.client
import time

app = win32com.client.Dispatch("PowerPoint.Application")
presentation = app.Presentations.Open(FileName=u'd:\\Bit It.pptx', ReadOnly=1)

presentation.SlideShowSettings.Run()

delay_find = 0
flag = 0

import time

from cvzone.HandTrackingModule import HandDetector
import cv2

cap = cv2.VideoCapture(0) #使用第一台攝影機
detector = HandDetector(detectionCon=0.5, maxHands=1) #手部偵測

#攝影机已開啟
while cap.isOpened():
    success, img = cap.read() #讀入影像
    hands, img = detector.findHands(img) #找手
   
    if flag == 0:      
        #找到手
        if hands:
            hand = hands[0]
            bbox = hand["bbox"]
           
            #有幾根手指
            fingers = detector.fingersUp(hand)
            totalFingers = fingers.count(1)
           
            msg = "None"
            if totalFingers == 1:      
               presentation.SlideShowWindow.View.Next()
           
            cv2.putText(img, msg, (bbox[0]+200,bbox[1]-30), cv2.FONT_HERSHEY_PLAIN, 2, (0, 255, 0), 2)                                      
            flag = 1
            delay_find = 0
    cv2.imshow("Image", img)
   
    delay_find = delay_find + 1    
    if delay_find > 30:
       flag = 0
       
    #按q離開
    if cv2.waitKey(1) & 0xFF == ord("q"):
        presentation.SlideShowWindow.View.Exit() #關閉PowerPoint
        app.Quit() #關閉PowerPoint
       
        break
       
cap.release()
cv2.destroyAllWindows()

延伸應用發想

可以在控制PowerPoint放映時還能像新聞主播播報新聞那樣隨時圈畫重點嗎?也許將本文再結合這篇「AI虛擬畫家 」就能達成。讀者們可以自行試試看。或者,電腦視覺特區(Computer Vision Zone) 上也有許多使用AI的電腦視覺專案,像是「虛擬鍵盤(Virtual Keyboard)」,有興趣的讀者可以參考它們的程式碼再行整併出更有趣的實例。
期待!

後記:如何解題?

一般而言,解決問題的基本方法論(methodology)有兩種:由上而下(Top Down)或由下而上(Bottom Up),如圖2和圖3所示。
前者是把大問題先拆解為各個功能獨立的小問題,個別求出其解後再將之組成原問題的解答;後者是從已知解答的各個小問題再發想出相關的應用,而這個新問題的答案就能快速地從已知合併(merge)出最終的結果。

 

圖2:由上而下求解。

圖3:由下而上求解。

然而,如果讀者已熟悉圖2及圖3的方法了,多練習幾個範例以建立直覺(intuition)。之後,再把這些方法都數忘記。不過,到那時,相信您定可信手拈來,而雖離師輔,道亦不遠矣!

 

圖4:全方位求解。

教學影片:

(作者為本刊專欄作家,本文同步表於作者部落格,原文連結;責任編輯:謝涵如)

Ted Lee
Ted Lee

Author: Ted Lee

從工程師轉任中學教師,又為了捍衛教育理念,投身成為 STEAM 教育工作者,自稱「無可救藥的人文教育理想主義者」的李俊德(Ted Lee)。

Share This Post On

Submit a Comment

發佈留言必須填寫的電子郵件地址不會公開。