Paul Reiners 展示瞭如何通過 Java 2D API 和細胞自動機(cellular automata)以獨特的藝術方式製作圖像動畫。在這個過程中,他演示了用 Java 代碼實現圖像操作器並介紹了循環空間(cyclic space ),循環空間是一種 2D 細胞自動機。您可以根據本文的思路創建自己的圖像操作器,並使用 Java 技術創建藝術應用程序。
本文說明如何通過實現 BufferedImageOp
接口來編寫自定義 Java 2D 圖像處理類。它使用一個 2D
細胞自動機(CA),即循環空間,來構造圖像處理應用程序。CA 會 “操作” 圖像(例如,一個 PEG
文件),使圖像不斷地按有趣的方式轉換。我希望本文能開闊您的視野,使您能編寫一個全新的圖像處理應用程序類。
2D 細胞自動機由分佈在 2D 網格(通常稱爲佈局)中的細胞 組成。每個細胞都有一個狀態,可以是 0 到 n 之間的任意整數。清單 1 顯示瞭如何用 Java 代碼聲明一個細胞自動機佈局:
清單 1. 定義
TwoDCellularAutomaton.universe
|
所有細胞每個時刻都同時更新狀態。一個細胞的新狀態取決於該細胞的當前狀態和它相鄰細胞的當前狀態,狀態的轉換根據特定的規則進行。清單 2 更新了下一時刻的佈局:
清單 2.
TwoDCellularAutomaton
類(部分清單)public void update() { |
不同類型的 CA 更新單個細胞所用的規則不相同。規則的定義由子類完成。
|
在循環空間中,每個細胞都有一個狀態,它是 n 種狀態中的一種。每個細胞的初始狀態通常是隨機定義的,也就是說,是 0 和 n - 1(包括 0 和 n - 1)之間的一個隨機數字。細胞的鄰居定義爲 von Neumann 鄰居:包括它的上下左右 4 個鄰近細胞。
清單 3 通過給出每個細胞鄰居和細胞本身的不同座標來定義該細胞的 von Neumann 鄰居:
清單 3. 定義
TwoDCellularAutomaton.VON_NEUMANN_NEIGHBORHOOD
|
循環空間由以下規則定義:
如果一個細胞的狀態是 k,它有一個鄰居的狀態是 k + 1,那麼該狀態在下一時刻將會有一個新的狀態 k + 1。否則,該細胞的狀態將保持不變。
這個規則是循環的,因此,如果一個細胞處於狀態 n - 1,而且有一個狀態爲 0 的鄰居,那麼該細胞在下一時刻的狀態將爲 0。
|
這個簡單規則會導致意想不到的複雜行爲。清單 4 實現了在循環空間中更新細胞的規則:
清單 4. 定義
CyclicSpace.updateCell(int, int)
|
我曾說過,循環空間佈局的初始狀態是隨機的。細胞會被 “更大的” 細胞 “喫掉”,最後會再次循環回到狀態 0。在這個過程中,區域自行組織並展開,成爲波浪形。最後,會出現一個穩定的波浪圖案。這些波浪呈對角線在佈局中移動,看上去有點像紙風車。
|
java.awt.image.BufferedImageOp
接口允許您創建自己的圖像操作器(也稱爲過濾器)。本文只討論 BufferedImageOp
的一個方法:
BufferedImage filter(BufferedImage src, BufferedImage dest) |
src
和 dest
是 2D 像素網格。實現此方法時,您可以按任意方式從
src
構建 dest
。普遍做法是在 src
中迭代像素,並按照一定規則在
dest
中創建相應的像素。這就是在圖像處理應用程序中需要做的事情,我根據著名的法國畫家 Georges-Pierre Seurat
將它命名爲 Seurat(參見 下載 獲取完整的示例代碼)。
您可能知道圖像像素與 CA 中的細胞存在映射關係。它們都以 2D 網格形式存在,每個都有狀態,對於像素就是它的紅綠藍(RGB)值。我將在
filter(BufferedImage src, BufferedImage dest)
實現中探討這種映射關係。對於
src
中的每個像素,我會根據一定規則將該像素的 RGB 值與 CA 中相應細胞的狀態組合起來,創建
dest
中相應像素的新 RGB 值。這個規則將定義一個過濾器。
清單 5 顯示如何迭代 src
中的所有像素並在 dest
中構建像素。抽象方法
getNewRGB(Color)
由單獨的過濾器定義。它爲輸入顏色計算並返回經過過濾的 RGB 值。
清單 5.
CellularAutomataFilter
類(部分清單)本文轉自IBM Developerworks中國