匯出龍族拼圖(Puzzle & Dragons)寵物清單的方法

2021-12-16

最近又回鍋 PAD 了,從這遊戲開服以來,斷斷續續玩到現在已經有接近二千隻寵物了,每次回歸都要重新面對那個讓人頭痛的搜尋系統,這次終於下定決心想寫個程序來匯出我的寵物清單,好讓我更容易上手!

PAD website demo 我寫的一個手機版網頁 ヽ(=^・ω・^=)丿

現有的 PAD 搜尋問題

PAD 現在多了很多武裝和進化路線,每隻寵物隨便都有兩三張或以上的頭像,對我來說不太可能全部記得,有時候看 Youtube 抄隊伍我只是想知道有沒有那隻寵物都要來回搜尋好幾個網頁,皆因內建的搜尋工具不能用一個寵物編號搜尋牠們的進 / 退化寵物,雖然官方的 WEB 檢索某程度上能解決這問題,但還是讓我覺得很疲累

Github 連結

Tl;dr 我把原碼放在 Github 了,請慢用~

https://github.com/auphone/pad-box-export-tool

OpenCV + Python 懶人組合

一次成功用 Open-CV 拼圖的經驗,這次還是會用 OpenCV + Python 這個組合,我有試圖使用 Tensorflow 自行 train 一個 dataset,奈何不太在行而且每次 training 都要花好幾個小時… 最後還是決定用比較熟悉的方法

以下是當前的版本

  • Opencv 4.5.4
  • Python 3.10.1
  • FFmpeg 4.4.1
  • ImageMagick 7.1.0

建立虛擬環境及安裝模組

python -m ensurepip --upgrade
python -m venv ~/venv/pad
source ~/venv/pad/bin/activate
pip install numpy matplotlib opencv-python

開始!

首先我們要像這樣用 screen recording 拍一條短片,重點是滾動的時候要用平均的速度方便之後處理

沒錯!就是這個速度!(ゝ∀・)b

使用 FFmpeg 每秒截圖 10 次

上面影片的速度大約是 1 秒 10 頁,按需要把 fps 改成其他數值,只要抽取出來的圖片能確實拍到所有寵物就 OK 了,把影片放到 videos/box.mp4 後運行

ffmpeg -i videos/box.mp4 -vf fps=10 ./out/screenshots/%d.jpg

使用 ImageMagick 裁剪圖片

取得圖片之後我們立即把上下方多餘的部份移除,可以省掉之後一些運算的資源,同樣地這裡根據手機像素和比例自行更改數值

mogrify -crop 750x720+0+400 ./out/screenshots/\*.jpg

./out/screenshots/ 會有很多長這樣的圖片 PAD box cropped 圖片的像素不能太低喔!๑乛◡乛๑

抽取寵物圖示

因為這邊比較多數值需要修改,所以我們先抽樣測試一下,以下程序將會處理 ./out/screenshots/1.jpg,這是我的 iphone SE2 的設定,完整代碼在下面

ICON_WIDTH = 120 // 圖示闊度
ICON_HEIGHT = 120 // 圖示高度
ICON_MARGIN_BOTTOM = 10 // 圖示底邊距,大約是顯示 Lv 的部份
ICON_SPACING = 17 // 圖示間距
PAGE_LEFT_PADDIG = 14 // 頁面左邊距,用於獲取第一張圖片 x 坐標
COL = 5 // 曼大橫行數量
ROW = 5 // 最大直行數量(會變動)

這邊用了 openCv 的 cv.findContours()cv.boundingRect() 取得大大小小的長方型,因為我們的頁面變化不多,所以這邊可以用一些固定數值找到在合理範圍內最大的長方型,從而計算出第一張和其他圖片的坐標

for c in contours:
    rect = cv.boundingRect(c)
    if cv.contourArea(c) > 10000: continue
    x,y,w,h = rect
    size = w * h
    if size > largestSize and size > 5000 and size < 15000:
        largestSize = w * h
        coord = (x,y)

1. 畫出全部 boundingRect

for c in contours:
    rect = cv.boundingRect(c)
    ...

PAD rect noise

2. 加入條件縮小範圍

for c in contours:
    ...
    if size > 5000 and size < 15000:
        coord = (x,y)

PAD rect filtered

3. 然後我們取最大面積的長方型

for c in contours:
    ...
    if size > largestSize:
        largestSize = w * h
        ...

PAD rect largest

4. 計算出第一隻和其他寵物的位置

詳見完整代碼

PAD first rect

PAD opencv rect

完整代碼連結

Github連結: extract_pet_verify.py

栽剪寵物圖示

取得坐標之後就很簡單了,我們會把圖示儲存到 ./out/cropped/

...
crop_img = img[y1:y2, x1:x2]
cv.imwrite('./out/cropped/' + str(idx) + '.jpg', crop_img)
...

PAD cropped icons

配對圖片

用自己的方法取得寵物圖示,我是從其他網頁偷來的所以就不多說了,自己去看 ./lib/image_downloader.js

Feature matching - SIFT + FLANN

我們用 nest loop 把全部圖片 1:1 比對,使用了 OpenCV 的 feature matching 功能,這邊就不多說了,90% 代碼都是直接複製這裡

...
sift = cv.SIFT_create()
matcher = cv.DescriptorMatcher_create(cv.DescriptorMatcher_FLANNBASED)

kp, des = sift.detectAndCompute(src,None)
kp2, des2 = sift.detectAndCompute(cropped,None)

matches = matcher.knnMatch(des1,des2,k=2)

score = 0
for m,n in matches:
    if m.distance < 0.75*n.distance:
        score += 1

if score > 15 and score > maxscore:
    maxscore = score
    maxid = id
...

確認一下比對結果

如果在 match.py 打開 DEBUG 模式,就可以生成這些圖片讓我們可以肉眼比對再進行微調以提升準確率,暫時就我略略的觀察準確率已高達 90%,對我來說已經非常足夠了~

PAD opencv match result

生成寵物編號

最後我們可以在 ./out/ids.txt 取得影片中寵物編號的 CSV

388,559,636,644,650,778...

項目連結

https://github.com/auphone/pad-box-export-tool