匯出龍族拼圖(Puzzle & Dragons)寵物清單的方法
2021-12-16
最近又回鍋 PAD 了,從這遊戲開服以來,斷斷續續玩到現在已經有接近二千隻寵物了,每次回歸都要重新面對那個讓人頭痛的搜尋系統,這次終於下定決心想寫個程序來匯出我的寵物清單,好讓我更容易上手!
我寫的一個手機版網頁 ヽ(=^・ω・^=)丿
現有的 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/
會有很多長這樣的圖片
圖片的像素不能太低喔!๑乛◡乛๑
抽取寵物圖示
因為這邊比較多數值需要修改,所以我們先抽樣測試一下,以下程序將會處理 ./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)
...
2. 加入條件縮小範圍
for c in contours:
...
if size > 5000 and size < 15000:
coord = (x,y)
3. 然後我們取最大面積的長方型
for c in contours:
...
if size > largestSize:
largestSize = w * h
...
4. 計算出第一隻和其他寵物的位置
詳見完整代碼
完整代碼連結
Github連結: extract_pet_verify.py
栽剪寵物圖示
取得坐標之後就很簡單了,我們會把圖示儲存到 ./out/cropped/
...
crop_img = img[y1:y2, x1:x2]
cv.imwrite('./out/cropped/' + str(idx) + '.jpg', crop_img)
...
配對圖片
用自己的方法取得寵物圖示,我是從其他網頁偷來的所以就不多說了,自己去看 ./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%,對我來說已經非常足夠了~
生成寵物編號
最後我們可以在 ./out/ids.txt
取得影片中寵物編號的 CSV
388,559,636,644,650,778...