OpenCV拼圖輔助程式(續)

2019-02-20

這是一次成功用 Open-CV 拼圖的經驗的續篇,主要是想補充並紀錄一下之前沒提到的一些研究結果

OpenCV + Python

就如之前提到,我用的是 OpenCV 和 Python 這個組合,因為 OpenCV 3.0 支援的語言不多,所以我選了最容易上手的 Python,最近發現 OpenCV 4.0 開始支援 Node.js 了,可惡!

黑蘋果 hackintosh

系統方面,我的首選是 Linux,不考慮 Windows。但因為這次要用到大量 GPU,Linux 的支援比較弱,就決定用早就想試試的 hackintosh,還可以 build iOS 呢﹗

Hackintosh

不過要安裝黑蘋果,首先要有蘋果電腦,詳情自己 Google 一下,不難找的

建立 Python 虛構環境

裝好 Python 後先建立 python 的虛構環境,原理就像 NodeJS 的 node_modules,避免這項目的模組影響到其他項目。我的選擇是使用 virtualenv,沒甚麼原因只是第一個搜尋到就是這個,另一個替代方案是用 Conda

# 安裝 virtualenv
$ pip install virtualenv

# 在項目內建立虛構環境
$ cd ~/my-project
$ virtualenv jigsaw-env

# 啟用虛構環境
$ source jigsaw-env/bin/activate

# 最檢查pip路徑是否正確
$ pip -V

如果沒出錯會看到 pip 指向剛設定好的路徑

pip 19.0.3 from ../jigsaw-env/lib/python3.7/site-packages/pip (python 3.7)

使用這個指令離開虛擬環境

$ deactivate

安裝 OpenCV

3.0 跟 4.0 的安裝方法沒太大差別,兩者都需要連同 OpenCV extra modules 安裝,比較麻煩的是當中要用到的 SIFT 不是免費技術,所以在 compile 的時候需要同意一些條款,簡單來說就是不能用 pre-built 版本,只能自己 build 了…

以下是 OpenCV 4 的安裝流程,當中 Python 的設定請自行更改路徑,參考這篇 OpenCV: Installation in Linux

# 先 clone 這兩個項目
$ git clone https://github.com/opencv/opencv.git
$ git clone https://github.com/opencv/opencv_contrib.git

# 建立 Build 資料夾
$ cd opencv
$ mkdir build
$ cd build

# build 需要自行更改 python 路徑
$ cmake -DOPENCV_ENABLE_NONFREE:BOOL=ON \
  -DOPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \
  -DPYTHON3_EXECUTABLE=/usr/bin/python3 \
  -DPYTHON_INCLUDE_DIR=/usr/include/python3.7m \
  -DPYTHON_LIBRARY=/usr/lib64/libpython3.7m.so \
  -DPYTHON3_NUMPY_INCLUDE_DIRS=/usr/lib/python3.7/site-packages/numpy/core/include/ \
  ..

如果 Python 的設定正確,應該會看到類似這樣的字串,如果你沒看見Python 3,一定是有東西忘記輸入或輸入錯了

--   Python 3:
--     Interpreter:                 /usr/bin/python3 (ver 3.7.2)
--     Libraries:                   /lib64/libpython3.7m.so (ver 3.7.2)
--     numpy:                       /usr/lib/python3.7/site-packages/numpy/core/include/ (ver )
--     install path:                lib/python3.7/site-packages/cv2/python-3.7
--
--   Python (for build):            /usr/bin/python2

最後用 make compile 和安裝

$ make -j7

$ sudo make install

如果出現了這句

ModuleNotFoundError: No module named 'cv2'

就需要在~/.bashrc~/.zshrc的最後一行加上這句,讓 Python 能讀取site-packages這個資料夾

export PYTHONPATH=/usr/local/lib/python3.7/site-packages:$PYTHONPATH

整個過程我的 Xeon 處理器大概用了 10 分鐘,如果是 i5 或以下的有機會超過半小時,喝杯咖啡再回來吧

技術應用

這個項目我總共寫了

  • 一個 Python 伺服器
  • 一個用 React Native 寫的 iOS App

React Native

伺服器主要是 App 跟 OpenCV 的溝通,渠道是 socket.io,iOS App 的作用是拍照然後透過 socket.io 把圖片傳送到伺服器,沒甚麼特別我就不多講了,而且已經是 iOS 10 時候的事了,所以現在有 87% 機率是不能運行的了

OpenCV 圖像比對技術

除此之外就是圖像比對的技術,也就是這個項目的核心,俗語有講「貨比三家不吃虧」所以我幾乎把 OpenCV 內建的比對功能都試了一遍

Feature Matching 比較圖片特徵

Feature Matching (以下簡稱 FM) 是 OpenCV 的功能,Feature 即特徵,FM 即是找出兩件物件的相似特徵

OpenCv Feature Matching

如果是原圖與原圖的比較,我們可以用 Template Matching (TM),但要從拍照取得的 3D 拼圖塊跟 2D 的原圖比較,TM 就沒辦法處理了,因為拍下來的圖片一定是變形的

OpenCV 有幾種 Feature Matching 算法可以使用,以下就是我測試過的

SIFT Brute-Force Matching

Scale-invariant feature transform 是一個很常用的算法,初步測試讓我很驚訝,因為真的慢到一個點,單使用這個算法是不可能的了,混合其它算法出來的結果還可以

SIFT Algorithm 運算時間︰9 秒

p.s. 這速度光是運算 1000 張圖片就要花 2.5 小時了…

ORB Brute-Force Matching

Oriented FAST and Rotated BRIEF 是一個 SIFT 的替代方案,這個運算方法的優點是快和省電腦資源,重點是免費,可惜效果不是很理想,最後沒採用

ORB Algorithm 運算時間︰1 秒

p.s. 真的很快

FLANN based Matcher

為了解決速度問題,我們會使用 FLANN (Fast Library for Approximate Nearest Neighbors)配搭 SIFT 使用,看到名字有個 Fast 字就知道是根速度問題有關了

FLANN Matcher 運算時間︰5 秒

Homography

calib3d 的 Homography 是這次的主角,它可以修正圖片因拍攝而變形的問題,讓它比較接近原圖,當然拍攝的圖片也不能變形得太誇張

Homography 運算時間︰5 秒

運算速度太慢

這個項目遇到不少問題,雖然大部份都可以無視,反正我的目的就只是完成這副拼圖,但是速度的問題是一定要解決的,我把解決方法歸納於這兩點

選擇 macOS

第一個關鍵因素是系統,嘗試過三個主流系統後,發現 Linux 的圖像處理明顯比其他兩個慢,我不想花時間在效能提升方面上,所就直接轉用 hackintosh 了

p.s. 我的顯示卡是 GTX 960,因為慢得很誇張所以比較各系統時有很明顯的感覺

壓縮圖片大小到合理範圍

另一個因素是圖片大小,這裡指的圖片指的是拼圖原圖和手機拍的圖片,把原圖切割成多個部份可以運用多線程提升速度,我在這個項目就把它切成 9 等份

OpenCV Program in 9 screen

手機拍攝的圖片像素就縮減至 1000px,但不能太小因為會不準確,這個過程我在 Python 處理,不知道用 iOS 壓縮後再傳送會不會比較快,對於我的 6S 來說大概是不會吧,而且用 subnet 傳送一張圖片應該是以微秒作單位的

花了很多時間 build iOS

沒有太多 App 開發經驗,所以跟 OpenCV 比起來反而花了更多時間在 build iOS 那邊,除了要解決一堆權限問題之外,本來以為使用 Reactive Native 就不需要用 Xcode,最後發現是自己一廂情願…

準確率不太好

準確率嗯… 大概 50%吧,重新拍一次也只能提高至大約 70%,所以說有 30%還是要靠自己了,問題是我覺得這拼圖每一塊的獨特性已經很高了,這樣才只有 70%,很難想像能應用在其他比拼圖上…

p.s. 而且這程式其實也沒幫到多少,因為就算程式認到了我還要在拼圖板上猜那塊拼圖的位置 Orz,下次還是先列印 1:1 的原圖作為拼圖的底板好了