系列文章
透過安裝篇的文章,我們已經將 Python、OpenCV、ADB 這些環境處理完畢了,接下來我們需要進行測試,測試 ADB 是否能夠抓取模擬器的螢幕截圖、測試 OpenCV 是否能夠抓取我們所想要的圖片,並且計算其位置、其準確率。
測試 ADB 截圖
首先第一步我們需要測試的是「測試 ADB 是否能夠抓取模擬器的螢幕截圖」,這邊我們會需要 import os
引入,並且透過 os.popen
去呼叫 adb 指令來進行模擬器截圖、模擬器輸出圖片的動作。
1 2 3 4 5 6 7 8 9
| import os
if __name__ == '__main__': while True: os.system('adb shell /system/bin/screencap -p /sdcard/screencap.png') os.system('adb pull /sdcard/screencap.png ./screencap.png')
|
不過我們會發現終端機不斷地輸出訊息如下:
1 2 3 4 5 6 7 8 9 10
| /sdcard/screencap.png: 1 file pulled, 0 skipped. 38.9 MB/s (401994 bytes in 0.010s) /sdcard/screencap.png: 1 file pulled, 0 skipped. 47.1 MB/s (468572 bytes in 0.009s) /sdcard/screencap.png: 1 file pulled, 0 skipped. 41.2 MB/s (469204 bytes in 0.011s) /sdcard/screencap.png: 1 file pulled, 0 skipped. 22.9 MB/s (467375 bytes in 0.019s) /sdcard/screencap.png: 1 file pulled, 0 skipped. 56.3 MB/s (468928 bytes in 0.008s) /sdcard/screencap.png: 1 file pulled, 0 skipped. 48.3 MB/s (468177 bytes in 0.009s) /sdcard/screencap.png: 1 file pulled, 0 skipped. 46.9 MB/s (468718 bytes in 0.010s) /sdcard/screencap.png: 1 file pulled, 0 skipped. 53.9 MB/s (468843 bytes in 0.008s) /sdcard/screencap.png: 1 file pulled, 0 skipped. 55.6 MB/s (468152 bytes in 0.008s) /sdcard/screencap.png: 1 file pulled, 0 skipped. 41.6 MB/s (468735 bytes in 0.011s)
|
如果我們希望系統不要輸出這些資訊,那我們就要換另一種寫法,使用 subprocess
的 check_output
來呼叫 adb 指令。
1 2 3 4 5 6 7 8 9
| import os
if __name__ == '__main__': while True: subprocess.check_output('adb shell /system/bin/screencap -p /sdcard/screencap.png', shell=True) subprocess.check_output('adb pull /sdcard/screencap.png ./screencap.png', shell=True)
|
這樣我們就可以在根目錄底下獲得 screencap.png
這個螢幕截圖了,而且根據程式持續運作,這張截圖會不斷更新模擬器最新的畫面,既然我們現在已經能將模擬器實時截圖並輸出到專案的根目錄當中了,那麼接下來我們需要測試 OpenCV 能不能偵測我們想要的目標物件,並且將目標物件透過畫框的方式繪製出範圍。
測試 OpenCV 偵測物件
首先我們需要有一個主要的螢幕截圖,這裡我們稱做 screencap.png
,以及我們的目標 prepared.png
,而我們希望達成的事情是透過 OpenCV 去找尋 screencap.png
當中有沒有符合 prepared.png
的地方,其座標、相符率有多少。
首先我們需要 import cv2
引入,然後透過 cv2.imread
來載入 screencap.png
螢幕截圖以及載入 prepared.png
目標物件,再來透過 cv2.matchTemplate
來計算 screencap.png
螢幕截圖當中,與 prepared.png
目標物件有多少相符率,以及其座標位置,再來透過 cv2.rectangle
來繪製目標物件的位置及大小,最後以 cv2.imwrite
的方式來輸出圖片並儲存為 output.png
,整個流程到處都會使用到 cv2
的功能。
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
| import cv2
if __name__ == '__main__': while True: screenshot = cv2.imread('./screencap.png') prepared = cv2.imread('./prepared.png') result = cv2.matchTemplate(screenshot, prepared, cv2.TM_CCORR_NORMED) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
mat_top, mat_left = max_loc prepared_height, prepared_width, prepared_channels = prepared.shape bottom_right = (mat_top + prepared_width, mat_left + prepared_height) cv2.rectangle(screenshot, (mat_top, mat_left), bottom_right, (101, 67, 196), 2)
cv2.imwrite('./output.png', screenshot)
|
透過這樣的程式碼,我們可以獲得一個非常成功的輸出結果。
但目前這樣有個缺點,在畫面有我們所想找的目標物件時,OpenCV 可以精確地找到目標物件的位置,但如果目前畫面沒有目標物件時,OpenCV 仍然會找出相似度最高的物件,這會導致我們的程式一直在判斷錯誤的地方執行觸發,直到有正確目標物件出現時才能觸發正確的事件,為了避免這樣的情況發生,我們必須去比對 max_val
這項數值,這項數值意旨目標物件的相似率,所以我們可以這樣設計,先讓 OpenCV 去計算目標物件,然後判斷 max_val
這項數值有沒有大於一定的百分比,如果有才進行動作,並且結合前面 adb 擷取螢幕截圖的部份的話,我們就可以寫出一個實時監控的程式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import cv2
if __name__ == '__main__': while True: subprocess.check_output('adb shell /system/bin/screencap -p /sdcard/screencap.png', shell=True) subprocess.check_output('adb pull /sdcard/screencap.png ./screencap.png', shell=True)
screenshot = cv2.imread('./screencap.png') prepared = cv2.imread('./prepared.png') result = cv2.matchTemplate(screenshot, prepared, cv2.TM_CCORR_NORMED) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
if max_val >= 0.99: mat_top, mat_left = max_loc prepared_height, prepared_width, prepared_channels = prepared.shape bottom_right = (mat_top + prepared_width, mat_left + prepared_height) cv2.rectangle(screenshot, (mat_top, mat_left), bottom_right, (101, 67, 196), 2) cv2.imwrite('./output.png', screenshot)
|
到這邊為止,測試篇的內容就差不多了,我們測試了 adb 對模擬器的控制,以及 OpenCV 去判斷截圖的偵測,下一篇將講述如何結合 OpenCV 並透過 adb 去控制模擬器,做出相對應的動作。
下一篇文章:操作篇