[R] 方吉與R:去背也是數學問題!


方吉與R兩者毫無關聯!

呃,最近在蘑菇人方吉家看到了新的LINE貼圖組,這個:



看到的第一個反應,就是想把它們割下來作成噗浪自訂表情圖案。身為方吉的粉絲這真是再自然不過的反應了!最好還能去個背這樣。

所以咧?
PHOTOSHOP?
當然,PHOTOSHOP可以處理這個任務。
不過對於我這種不太熟這套軟體的人,操作起來過程還是會十分繁複。倒是有個有趣的問題,那就是,對於十分熟悉這套軟體——就拿「去背處理」來說好了——的人,是否有想過PHOTOSHOP又是怎麼做的

事實上它是一個數學問題
上面的圖格式是常見的PNG,一種無損壓縮的點陣圖檔案格式。點陣圖就是由點來表示的圖,我們可以很直覺地將一張圖以數學矩陣來表示:矩陣裡頭的每一個位置紀錄了該點的色彩資訊。如果有RGB三色資訊,那麼一張彩色的圖可以想像成是一組三維陣列——或者是三組二維矩陣,分別記錄了R、G、B三色的資訊。

在R裡面我們要如何看到這樣的資訊?
以PNG圖檔為例,我們可以利用png這個套件。



該套件的readPNG這個方法可以將PNG圖檔以矩陣的形式讀入R的環境。預設的引數native=FALSE讀進來的是三維陣列,如果改成TRUE則會以一個nativeRaster物件的二維矩陣成形。(點陣圖Bitmap又有別名Raster Graph。)

記住R是物件導向的語言,大部分的方法(也就是函數)具有「多型」性質;換言之,同一方法會針對物件的類別做出特化的行為。最明顯的例子就是summary或者是plot這些內建的方法,當所引入的物件類別不同,他們的行為也會有所差異。要確認一物件的類別,可以使用class這個方法:



在nativeRaster這個物件裡,數值是經過編碼的,至少我是看不懂那些數字是啥意思,所以如果想要更直覺一點的編碼,可以嘗試以as.raster這個方法將readPNG讀進來的三維陣列轉換成raster這個物件,它實質上是二維矩陣,並且用大部分人熟悉的色碼來記錄圖形中每一個點的色彩資訊。



好,那麼如何在R的環境裡重新將這樣的資訊形成原始圖片?
利用下面的程式碼,我要讀兩個版本的fungi.png,一個是原本的,另一個則是去背版本。如何去背?在我們這個簡單的例子裡,去背就是把背景顏色的那片灰給拿掉!事實上除了灰色還有一點白色的外框,所以我們會需要拿掉兩種色碼。以raster物件來說,我只要稍加檢視一下其矩陣內容,就可以知道哪兩個色碼是我要消除的對象。即使我完全不記得白色是#FFFFFF也無妨,因為肉眼上我馬上就可以知道白色會落於邊界,而背景的淡灰色#FAFAFA則會是整個矩陣裡最具有連續性(可能數量也最多)的數值。

但是,由於之後對去背圖的處理我仍然需要使用nativeRaster這個類別的物件,所以我不操作上述的色碼矩陣,而是操作nativeRaster這個物件底下的編碼,原則並未因此改變,我發現我要移除的編碼是-328966(那層淡灰色)與-1(邊緣白色)。然後這兩張圖我都還要做一個加工,我要把它們均勻切割——其實只是劃出切割線。



注意rasterImage這個作圖方法,必須先劃出一個空座標。此外就是,這邊我為了後續物件操作方便而動了點手腳,那就是針對去背版本,我先以native=TRUE讀進來,去背後再用writePNG的方式重新寫出一個PNG檔,然後再用readPNG把那個檔案以native=FALSE的方式讀進來。看起來有點蠢,但這邊很難解釋(我懶得解釋)我何必這麼作。一切都是為了後續方便,與前述的多型性質有關。

畫出來的圖是這樣:



很明顯,均勻散佈的切割線不能完美切割每個子圖,有些地方被劃到了。因為我懶得處理所以就先當作沒看見好惹。(喂)

我畫出這些線的目的,是為了確認這幾個坐標是可用來切割子圖的。R的作圖能力高深莫測,很多東西我摸都沒摸過,或許有哪個套件可以針對你在圖形上畫出來的線來直接進行圖片切割也不一定,但我在這邊沒有要這麼做,因為我不會。我要用土法煉鋼,以一個雙迴圈來處理圖形切割。我需要的就只是切割依據的座標而已。想要更手工的人,可以嘗試使用locator這個方法,它會回傳你滑鼠在圖形上點擊位置的座標。

我用下面這個簡單的雙迴圈結束這一回合不是是結束這個圖形切割的工作。我切了兩種版本,分別是原始與去背。可以看得出來在R裡面我們對圖形做處理實際上是對矩陣做處理;換言之,這是數學問題,以操作數學物件的方式完成任務。我讓檔名具有對應原始相對位置的意義,例如crop62就是第六列第二行的子圖。



切出來的第一個圖:



才、才不是為你準備的巧克力。

接下來,是做尺寸的縮放。
由於噗浪自訂表情的圖形大小限定在48*48以內,必須把割下來的子圖再縮小不過因為我要準備出門了所以晚點再說吧(WTF



[UPDATE]
我回來惹。
然後,我發現我老馬惹。
噗浪不吃我去背後的圖片的去背效果!
來自?writePNG的一個NOTE有如下文字:

Currently writePNG only produces 8-bit, deflate-compressed, non-quantized, non-interlaced images. Note in particular that readPNG can read 16-bit channels but storing them back using writePNG will strip the 8 LSB (irrelevant for display purposes but possibly relevant for use of PNG in signal-processing if the input is truly 16-bit wide).

經高人指點,是因為PNG8這個格式不被噗浪支援透明背景,好像是個不適合影像處理的格式。好吧,讓我再踹踹其他方法這篇就先降吧我撤

1 comment(s):

Shih-Hao Lee | 28 March, 2014 15:57

很棒的教學文章~感謝

Post a Comment

回應文章前請注意下列三勿原則:

1)勿拍照;(→會有靈異的照片從你的相機裡跑出來...
2)勿餵食;(→會有飢渴的猛獸從我的網誌裡跑出來...
3)勿告白。(→會有奇怪的東西從站長體內裡跑出來...

謝謝大家的配合。
( > ー <)b