樂事開運相機

樂事開運相機

去年(2021)七八月的時候,我們收到了來自客戶的一個想法,希望做一個行銷活動,民眾用手機拍了洋芋片之後,可以用 AI 偵測,並把偵測的結果透過演算的形式轉化成一個像是廟裡求得的籤詩一樣,最後可以把這個有趣的籤詩存下來。當時只是問技術的可行性,也要等提案過了才會執行。

那時覺得這個想法實在是太酷了,我對 AI 一直沒有什麼研究,想說如果有這個機會的話,那麼就來執行,真的很瘋狂!

因為是行銷活動,我們向來希望可以讓提高使用者體驗的意願,所以一開始就打定主意是一個行動式的網頁(mobile web)而非一個需要下載的 APP,因此怎麼在取得照片後去背,並且留下只有洋芋片的透明圖檔變成是當下技術難度(對我而言)最高的問題了。

Hot dog, not hot dog

我之前有簡單的上過一個 Jetson Nano 的推廣課程,Jupyter Notebook 等東西大概有碰過,不過推廣課程都是把 tutorial 的 code 剪下貼上,而 AI 相關的技術我一直都沒有真正的在任何工作專案上使用過。現在要實際運用它,還是要再仔細找更多資源。有看過矽谷群瞎傳(Silicon Valley)的我,想說應該會有「Hot dog,not hot dog」的教學吧,結果還真的有 🤣

但找了好一陣子之後,就知道我們要做的不是 classification,而是 image segmentation。再找了更多資料後,確定我們要找的東西叫 image matting,也就是把一張照片或影片出現的物件,前後景分離。主要參考的作法,是 F, B, Alpha Matting,但這些作法其實都需要提供一張 trimap,如下方右上角的圖,黑色代表 100% 肯定是背景,白色代表 100% 肯定是前景,而灰色的則是不確定的部份,而這個 F, B, Alpha Matting 的方是主要就是給了原圖(左上角)跟 trimap(右上角),它可以產出 mask(左上角),而利用這個 mask,我們就可以把透過遮罩把前景取出(左上加左下),合成我們想要的樣子(右下角)。

https://pymatting.github.io/intro.html#alpha-matting

DeepLabV3+

說也真是有趣,我們這一次最主要的 AI 工作在於自動產出 trimap。我們參考了 tensorflow 的 image segmentation tutorial 以及 keras 的 DeepLabV3+ 的 sample code 來做我們的訓綀。所以重點在當我們取得一張拍有洋芋片的照片時,我們可以自動產出 trimap 後,再丟入 image matting 來去背。

其實如果不是要把背景弄得很漂亮的話,直接用 image segmentation 也是可以的,但因為它的邊邊真的會處理得不夠漂亮,弄不好會很像狗啃的,所以還是丟進 image matting 去背會更有質感一些。

訓練完之後,image segmentation 的結果(還沒做 matting)

資料集

但我好像跳過我們怎麼取得資料來做訓練的。沒錯,就是硬拍、硬畫。原本我們想要自己弄,先拍了幾十張洋芋片的照片,再用 labelme 把範圍標起來。

這個是我寫的說明文件上,亂標的(不精細)

我們用了這幾十張的資料集來訓練,發現成效太差了,於是乎我們找了外援,也就是臨時工軍團!最後一共收了七千多張洋芋片的照片以及標記,如下面的圖兒們。

在這當中,我覺得用滑鼠標示手真的會爛掉,幸好 labelme 在 macOS 上也可以裝,所以我們就可以在 macOS 與 iPad 上用 sidecar 的功能,讓 iPad 變成第二螢幕;不過重點是在使用 iPad 的 Apple Pencil,這樣就可以用比較直接的方式來標記了。

串起來

所以串起來大概就是下面這個樣子:‌‌‌‌

  • 拿到一張拍好的照片
  • image segmentation 取得前景跟背景
  • 在 contour 的部份畫出粗粗的線,作為 trimap 灰色的部份
  • 把 trimap & 原圖丟進去 image matting 拿到 mask
  • 把原圖跟 mask 合在一起去背
這沒有按照上面的順序

分數計算

去背做完之後,剩下的就比較好實作了。我們把象限位置對好,就可以計算分數了。本來有在想要把拍到的洋芋片置中,但後來考量到使用體驗,覺得它應該就是在原本拍照的位置才對。

當分數算好了,就可以產生籤詩的內容以及圖片了。

libcairo

最初在合成籤詩的時候,直覺的想法就是使用 opencv2 或 Pillow(PIL)把字貼上去。不過,使用它們的成果,字的鋸齒蠻明顯的。Pillow 並沒有支援反鋸齒,最後決定使用 libcairo 來做字的合成。libcairo 我認為不是很好駕馭,它在 Windows 上編譯有些問題,還好我們最後是放雲端,它在 Linux 上好裝許多。另外,我覺得它算是蠻底層的 library,所以置中、字的高度、長度等很多都要自己實作,尤其是我們的籤詩的詩本人是直式中文,還夾帶著英文。但為了美美的合圖,這些還是值得的。

也因為比較多手控合成字的部份,為了 debug 可以看所有籤詩組合,我們也特別做了一個合成器來確保直式中英文、標點符號會不會超出邊界、有沒有顯示上的問題。

Hosting

上文最開始提到,因為是網頁,上述有用到 tensorflow 的地方,最後要放在雲端的主機上。我們也是第一次在雲端上面跑有 GPU 的機器,價錢實在是貴森森呀!

我們向來雲端服務使用 Google Cloud Platform,值得一提的是,每一個區域(zone)可以使用的 GPU 不同。我們碰到的第一個雷,就是選了 NVIDIA Tesla K80,但每一次升級 NVIDIA driver,主機就找不到 GPU 了,找解法找了一輪發現 495 之後的 driver 不支援 K80,後來我們就改用 T4。

另一個雷也是跟升級 NVIDIA driver 有關,可參考上一篇寫的雲端上跑有用到 GPU 的 VM

結語

這整個專案可以順利,是一整個團隊的合作才得以完成。非常感謝專案經理唐瑋,她除了負責全部對內與對外的溝通(想像我們臨時 call 了好多打工標記的人員)、時程控管,還有介面、流程等設計;我們另一位技術總監顯清很明顯地比我還要更積極地推動 AI 的各個事項,在我還搞不清楚很多事情的時候,我都是先問他,並在我們碰到困難的時候提供改善的想法;最後是這個案子的前端工程師 Gin,剛來馥谷餘就緊急支援這個網站,我個人覺得最後的呈現相當好。

當然也謝謝我們的客戶,委託這麼有趣又相當有挑戰性的專案給我們,看到做的東西出現在電視廣告中是無比的興奮。

這次從 AI 幼幼班開始做起,中間一度不太確定是否可以有好的結果,但索幸是成功了。最後的關鍵在於原本訓練的照片量太少,把訓綀的來源拉大到七千多張後,效果就出來了。除了第一次做 AI、tensorflow 相關的東西外,我們也獲得了一個可以標註洋芋片的模型 🤣

最後把電視廣告以及實際上體驗的錄影呈現給大家欣賞一下。

0:00
/

References