日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

點(diǎn)畫法和像素處理

系統(tǒng) 1944 0

本文說(shuō)明如何通過(guò)實(shí)現(xiàn) BufferedImageOp 接口來(lái)編寫自定義 Java 2D 圖像處理類。它使用一個(gè) 2D 細(xì)胞自動(dòng)機(jī) (CA),即 循環(huán)空間 ,來(lái)構(gòu)造圖像處理應(yīng)用程序。CA 會(huì) “操作” 圖像(例如,一個(gè) PEG 文件),使圖像不斷地按有趣的方式轉(zhuǎn)換。我希望本文能開闊您的視野,使您能編寫一個(gè)全新的圖像處理應(yīng)用程序類。

2D 細(xì)胞自動(dòng)機(jī)

2D 細(xì)胞自動(dòng)機(jī)由分布在 2D 網(wǎng)格(通常稱為 布局 )中的 細(xì)胞 組成。每個(gè)細(xì)胞都有一個(gè) 狀態(tài) ,可以是 0 到 n 之間的任意整數(shù)。清單 1 顯示了如何用 Java 代碼聲明一個(gè)細(xì)胞自動(dòng)機(jī)布局:


清單 1. 定義 TwoDCellularAutomaton.universe

            
protected int[][] universe;

所有細(xì)胞每個(gè)時(shí)刻都同時(shí)更新狀態(tài)。一個(gè)細(xì)胞的新狀態(tài)取決于該細(xì)胞的當(dāng)前狀態(tài)和它相鄰細(xì)胞的當(dāng)前狀態(tài),狀態(tài)的轉(zhuǎn)換根據(jù)特定的規(guī)則進(jìn)行。清單 2 更新了下一時(shí)刻的布局:


清單 2. TwoDCellularAutomaton 類(部分清單)

            				public void update() {
            
int[][] newUniverse = new int[rowCount][colCount];
for (int row = 0; row < rowCount; row++) {
for (int col = 0; col < colCount; col++) {
newUniverse[row][col] = updateCell(row, col);
}
}
for (int row = 0; row < rowCount; row++) {
for (int col = 0; col < colCount; col++) {
universe[row][col] = newUniverse[row][col];
}
}
}

protected abstract int updateCell(int row, int col);

不同類型的 CA 更新單個(gè)細(xì)胞所用的規(guī)則不相同。規(guī)則的定義由子類完成。

循環(huán)空間

循環(huán)空間是由麥迪遜市威斯康星大學(xué)數(shù)學(xué)系的 David Griffeath 發(fā)現(xiàn)的,并由 A. K. Dewdney 在 Scientific American 的一個(gè)專欄中推廣。

在循環(huán)空間中,每個(gè)細(xì)胞都有一個(gè)狀態(tài),它是 n 種狀態(tài)中的一種。每個(gè)細(xì)胞的初始狀態(tài)通常是隨機(jī)定義的,也就是說(shuō),是 0 和 n - 1 (包括 0 和 n - 1)之間的一個(gè)隨機(jī)數(shù)字。細(xì)胞的鄰居定義為 von Neumann 鄰居 :包括它的上下左右 4 個(gè)鄰近細(xì)胞。

清單 3 通過(guò)給出每個(gè)細(xì)胞鄰居和細(xì)胞本身的不同坐標(biāo)來(lái)定義該細(xì)胞的 von Neumann 鄰居:


清單 3. 定義 TwoDCellularAutomaton.VON_NEUMANN_NEIGHBORHOOD

            
protected static final int[][] VON_NEUMANN_NEIGHBORHOOD = { { -1, 0 },
{ 1, 0 }, { 0, -1 }, { 0, 1 } };

循環(huán)空間由以下規(guī)則定義:

如果一個(gè)細(xì)胞的狀態(tài)是 k ,它有一個(gè)鄰居的狀態(tài)是 k + 1 ,那么該狀態(tài)在下一時(shí)刻將會(huì)有一個(gè)新的狀態(tài) k + 1 。否則,該細(xì)胞的狀態(tài)將保持不變。

這個(gè)規(guī)則是循環(huán)的,因此,如果一個(gè)細(xì)胞處于狀態(tài) n - 1 ,而且有一個(gè)狀態(tài)為 0 的鄰居,那么該細(xì)胞在下一時(shí)刻的狀態(tài)將為 0

ConvolveOp 算是一個(gè)細(xì)胞自動(dòng)機(jī)

Java 2D API 的 ConvolveOp 類代表一個(gè) 空間螺旋 :每個(gè)目標(biāo)像素的顏色通過(guò)對(duì)應(yīng)的源像素及其鄰居像素的顏色來(lái)確定。

您是不是覺得這個(gè)定義很熟悉呢?這與 2D 細(xì)胞自動(dòng)機(jī)基本上是同一個(gè)東西,但不盡相同。例如,狀態(tài)(顏色)是連續(xù)的而不是分散的(也不完全如此:RGB 值的個(gè)數(shù)是無(wú)限的,但很接近連續(xù))。這使得該類更像是一個(gè) 連續(xù)自動(dòng)機(jī) 。而且您不能使用像 CA 那樣細(xì)的粒度控制基于細(xì)胞及其鄰居細(xì)胞當(dāng)前狀態(tài)的新狀態(tài)。

因此,您無(wú)法使用一個(gè) ConvolveOp 定義循環(huán)空間,但它仍然是很有趣的。它是查看 ConvolveOp 的另一種方式。

這個(gè)簡(jiǎn)單規(guī)則會(huì)導(dǎo)致意想不到的復(fù)雜行為。清單 4 實(shí)現(xiàn)了在循環(huán)空間中更新細(xì)胞的規(guī)則:


清單 4. 定義 CyclicSpace.updateCell(int, int)

            
protected int updateCell(int row, int col) {
int[] neighborStates = getNeighborStates(row, col, neighborhood);
int currentState = universe[row][col];
for (int i = 0; i < neighborStates.length; i++) {
int neighborState = neighborStates[i];
if (neighborState == (currentState + 1) % n) {
return neighborState;
}
}

return currentState;
}

我曾說(shuō)過(guò),循環(huán)空間布局的初始狀態(tài)是隨機(jī)的。細(xì)胞會(huì)被 “更大的” 細(xì)胞 “吃掉”,最后會(huì)再次循環(huán)回到狀態(tài) 0 。在這個(gè)過(guò)程中,區(qū)域自行組織并展開,成為波浪形。最后,會(huì)出現(xiàn)一個(gè)穩(wěn)定的波浪圖案。這些波浪呈對(duì)角線在布局中移動(dòng),看上去有點(diǎn)像紙風(fēng)車。


創(chuàng)建圖像操作器

java.awt.image.BufferedImageOp 接口允許您創(chuàng)建自己的圖像操作器(也稱為 過(guò)濾器 )。本文只討論 BufferedImageOp 的一個(gè)方法:

            BufferedImage filter(BufferedImage src, BufferedImage dest)
          

src dest 是 2D 像素網(wǎng)格。實(shí)現(xiàn)此方法時(shí),您可以按任意方式從 src 構(gòu)建 dest 。普遍做法是在 src 中迭代像素,并按照一定規(guī)則在 dest 中創(chuàng)建相應(yīng)的像素。這就是在圖像處理應(yīng)用程序中需要做的事情,我根據(jù)著名的法國(guó)畫家 Georges-Pierre Seurat 將它命名為 Seurat (參見 下載 獲取完整的示例代碼)。

Seurat 應(yīng)用程序

您可能知道圖像像素與 CA 中的細(xì)胞存在映射關(guān)系。它們都以 2D 網(wǎng)格形式存在,每個(gè)都有狀態(tài),對(duì)于像素就是它的紅綠藍(lán)(RGB)值。我將在 filter(BufferedImage src, BufferedImage dest) 實(shí)現(xiàn)中探討這種映射關(guān)系。對(duì)于 src 中的每個(gè)像素,我會(huì)根據(jù)一定規(guī)則將該像素的 RGB 值與 CA 中相應(yīng)細(xì)胞的狀態(tài)組合起來(lái),創(chuàng)建 dest 中相應(yīng)像素的新 RGB 值。這個(gè)規(guī)則將定義一個(gè)過(guò)濾器。

清單 5 顯示如何迭代 src 中的所有像素并在 dest 中構(gòu)建像素。抽象方法 getNewRGB(Color) 由單獨(dú)的過(guò)濾器定義。它為輸入顏色計(jì)算并返回經(jīng)過(guò)過(guò)濾的 RGB 值。


清單 5. CellularAutomataFilter 類(部分清單)

            
public BufferedImage filter(BufferedImage src, BufferedImage dest) {
if (dest == null)
dest = createCompatibleDestImage(src, null);

int srcHeight = src.getHeight();
int srcWidth = src.getWidth();
for (int y = 0; y < srcHeight; y++) {
for (int x = 0; x < srcWidth; x++) {
// Get the pixel in the original image.
int origRGB = src.getRGB(x, y);
Color origColor = new Color(origRGB);

// Get the new RGB values from the filter.
int[] newRGB = getNewRGB(origColor);

// Convert the pixel coordinates to the CA coordinates by
// scaling.
int cAY = (int) ((double) twoDCellularAutomaton
.getRowCount()
/ (double) srcHeight * y);
int cAX = (int) ((double) twoDCellularAutomaton
.getColCount()
/ (double) srcWidth * x);
// Get the state of the corresponding CA cell.
int state = twoDCellularAutomaton.getState(cAY,
cAX);
// Determine the weight of the filtered RGB values depending on
// the state.
double filterProportion = (double) state
/ (double) twoDCellularAutomaton.getN();

// Determine the weighted average between the filtered RGB
// values and the image RGB values.
int weightedRed = (int) Math.round(newRGB[0] * filterProportion
+ origColor.getRed() * (1.0 - filterProportion));
int weightedBlue = (int) Math.round(newRGB[1]
* filterProportion + origColor.getBlue()
* (1.0 - filterProportion));
int weightedGreen = (int) Math.round(newRGB[2]
* filterProportion + origColor.getGreen()
* (1.0 - filterProportion));

// Set the pixel in dest with this weighted average.
dest.setRGB(x, y, new Color(weightedRed, weightedBlue,
weightedGreen).getRGB());
}
}

return dest;
}

abstract protected int[] getNewRGB(Color color);

您可能會(huì)發(fā)現(xiàn)我沒有利用圖像中的像素與 CA 中的細(xì)胞之間的一對(duì)一映射關(guān)系。更確切地講,CA 是粗粒度的(至少大多數(shù)情況如此)。我最初這樣做是出于性能考慮。但是,使用不同大小的 CA 布局可以獲得有趣的像素效果。

清單 6 顯示了 getNewRGB(Color) 的一種特殊實(shí)現(xiàn)。它計(jì)算 “RGB 互補(bǔ)(complement)”,但這不是實(shí)際的顏色互補(bǔ)(計(jì)算真正顏色互補(bǔ)的過(guò)濾器也很有趣,但將其編寫成代碼則沒有這么簡(jiǎn)單)。


清單 6. RGBComplementFilter 類(部分清單)

            
protected int[] getNewRGB(Color c) {
int red = c.getRed();
int newRed = getComplement(red);
int green = c.getGreen();
int newGreen = getComplement(green);
int blue = c.getBlue();
int newBlue = getComplement(blue);

return new int[] { newRed, newGreen, newBlue };
}

private int getComplement(int colorVal) {
// 'Reflect' colorVal across the mid-point 128.
int maxDiff = colorVal >= 128 ? -colorVal : 255 - colorVal;
// Divide by 2.0 to make the effect more subtle. Could also just use
// maxDiff for a more garish effect.
int diff = (int) Math.round(maxDiff / 2.0);
int newColorVal = colorVal + diff;

return newColorVal;
}

我已經(jīng)擴(kuò)展 getNewRGB(Color) ,使其不僅可以傳入要轉(zhuǎn)換的像素顏色,而且可以傳入 8 個(gè)鄰居像素的顏色。這允許我創(chuàng)建某些效果,比如模糊效果或檢測(cè)邊緣,其中過(guò)濾的像素顏色取決于它的鄰居的顏色。這將是一個(gè)很好的增強(qiáng)功能。

最后,我將配合 CA 時(shí)鐘更新圖像來(lái)動(dòng)畫圖像。為此,我使用了一個(gè) javax.swing.Timer (這是制作變化圖像動(dòng)畫的簡(jiǎn)單方式,但不是最好的方式。Jonathan Knudsen 的著作 Java 2D Graphics 提供了一種更好更復(fù)雜的方式來(lái)創(chuàng)建動(dòng)畫。

運(yùn)行 Seurat

圖 1 是 Georges Seurat 于 1884 年創(chuàng)作的點(diǎn)畫法名作 “A Sunday Afternoon on the Island of La Grand Jatte” 的照片:


圖 1. Georges Seurat 的 “A Sunday Afternoon on the Island of La Grand Jatte”
包含圖像的示例圖片

現(xiàn)在我將使用 RGB 互補(bǔ)過(guò)濾器在 Seurat 圖畫上運(yùn)行 Seurat 應(yīng)用程序。圖 2 顯示了過(guò)濾后的圖畫,此時(shí)循環(huán)空間處于它的初始隨機(jī)狀態(tài):


圖 2. 使用循環(huán)空間過(guò)濾圖畫的無(wú)組織隨機(jī)狀態(tài)
包含圖像的示例圖片

圖 3 顯示了過(guò)濾后的圖畫,此時(shí)循環(huán)空間開始進(jìn)入有序模式,但仍然帶有很大的隨機(jī)性:


圖 3. 使用循環(huán)空間過(guò)濾圖畫的中間狀態(tài)
包含圖像的示例圖片

圖 4 顯示了過(guò)濾圖畫的最終穩(wěn)定狀態(tài):

過(guò)程藝術(shù)與算法藝術(shù)

為編寫 Seurat(我最初稱它為 “Blue Poles”),我閱讀了大量有關(guān) Jackson Pollock 的資料。我總是會(huì)碰到術(shù)語(yǔ) 過(guò)程藝術(shù) 。我天真地認(rèn)為它表示基于算法或規(guī)則的藝術(shù),藝術(shù)家據(jù)此設(shè)計(jì)一組規(guī)則并根據(jù)某些初始條件運(yùn)行它們,從而創(chuàng)作出藝術(shù)作品,如畫作。但我發(fā)現(xiàn)過(guò)程藝術(shù)與藝術(shù)世界中最普通的含義大不相同。根據(jù) Guggenheim Collection 術(shù)語(yǔ),它的含義如下:

“ 過(guò)程藝術(shù)強(qiáng)調(diào)藝術(shù)創(chuàng)作的 ‘過(guò)程’(而不是預(yù)訂的作品或計(jì)劃)以及變化和稍縱即逝的效果,如一些藝術(shù)家在他們作品中闡述的那樣,包括 Lynda Benglis、Eva Hesse、Robert Morris、Bruce Nauman、Alan Saret、Richard Serra、Robert Smithson 和 Keith Sonnier。”

因此,如果算法(或程序)的中間狀態(tài)具有藝術(shù)趣味,那么基于算法和規(guī)則的藝術(shù)可以被認(rèn)為是一種過(guò)程藝術(shù)形式, 算法則是運(yùn)行過(guò)程 。

作為程序員,我們只適合創(chuàng)建過(guò)程藝術(shù)或幫助藝術(shù)家創(chuàng)建它。


圖 4. 使用循環(huán)空間在穩(wěn)定狀態(tài)下過(guò)濾的圖畫
包含圖像的示例圖片

不過(guò),靜態(tài)圖片不能真正實(shí)現(xiàn)過(guò)濾器/CA(畢竟,這個(gè)應(yīng)用程序是為 動(dòng)畫 靜態(tài)圖像而編寫的)。我建議您運(yùn)行實(shí)際的 Java applet 來(lái)查看運(yùn)行中的過(guò)濾器/CA(請(qǐng)參閱 參考資料 ,獲得即時(shí) demo 的鏈接)。

審美注意事項(xiàng)


一 些人可能會(huì)認(rèn)為在 “A Sunday Afternoon on the Island of La Grand Jatte” 之類的偉大作品上運(yùn)行圖像過(guò)濾器應(yīng)用程序是一種褻瀆。我當(dāng)然很贊同此觀點(diǎn)。但我只是以這幅畫為例子。我的主要目標(biāo)是展示如何使用一種簡(jiǎn)單的細(xì)胞自動(dòng)機(jī)器, 以有趣而復(fù)雜的方式來(lái)制作圖像動(dòng)畫,以一副熟悉的名畫作為例子會(huì)比較好。

我曾在許多類型的畫上運(yùn)行過(guò) Seurat,在抽象藝術(shù)和具象藝術(shù)方面都得到了有趣的結(jié)果。但是,似乎在現(xiàn)代藝術(shù) — 特別是流行藝術(shù)方面效果更好。例如,當(dāng)您在 Jasper Johns 的 “Flag” 畫上運(yùn)行 Seurat 時(shí),會(huì)出現(xiàn)有趣的圖案。循環(huán)空間的對(duì)角線能根據(jù) “Flag” 畫中的直線很好地工作。在 Jackson Pollock 的水滴畫中,運(yùn)行 Seurat 時(shí)也會(huì)產(chǎn)生有趣的結(jié)果。例如,隨著循環(huán)空間 CA 越過(guò) Pollock 的 “Blue Poles”,它會(huì)隱藏、顯示、再隱藏這幅復(fù)雜畫作的細(xì)節(jié),讓您在不同時(shí)間集中注意不同的部位。這對(duì)照片同樣適用。我喜歡在 Ralph Eugene Meatyard 超現(xiàn)實(shí)主義的照片上運(yùn)行 Seurat。

在運(yùn)行 Seurat 這樣的應(yīng)用程序時(shí),您有 3 種選擇:2D 細(xì)胞自動(dòng)機(jī)類型、過(guò)濾器和原始圖像。在這篇文章中,我只使用了循環(huán)空間,但是也可以使用其他類型的 2D 細(xì)胞自動(dòng)機(jī)(如 Hodgepodge)。只要發(fā)揮您的想象力,就能編寫出各種過(guò)濾器程序。我主要實(shí)踐了操作顏色的過(guò)濾器,但更改圖像空間關(guān)系的過(guò)濾器也很有趣。例如,您 可以編寫一個(gè)歪曲圖像表面的過(guò)濾器程序,創(chuàng)建類似于披頭士的 Rubber Soul 專輯的封面那種效果。最后,您可以使用任意圖像,比如照片。對(duì)于給定的圖像,各種過(guò)濾器和 CA 類型的組合可以生成更好或更差的結(jié)果。我希望本文能鼓起您體驗(yàn)的欲望。

致謝

我對(duì) Julia Braswell 在視覺藝術(shù)方面的幫助表示衷心的感謝!

關(guān)于作者

Paul Reiners

Paul Reiners 是一位 Sun 認(rèn)證的 Java 程序員和開發(fā)人員。他參與開發(fā)了幾個(gè)開放源碼程序,包括 Automatous Monk、Twisted Life 和 Leipzig。Reiners 于 1991 年 5 月獲得伊利諾斯大學(xué) Urbana-Champaign 分校的應(yīng)用數(shù)學(xué)(計(jì)算理論)碩士學(xué)位。他目前住在明尼蘇達(dá)州,在業(yè)余時(shí)間喜歡演奏低音電吉他,并且是一個(gè)爵士樂隊(duì)的成員。

點(diǎn)畫法和像素處理


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 濮阳县| 彭州市| 三原县| 大名县| 宜城市| 津市市| 阜平县| 扶余县| 阜阳市| 社会| 合作市| 合山市| 奉新县| 东方市| 大方县| 太康县| 开鲁县| 渭源县| 盐边县| 海淀区| 章丘市| 贵德县| 南和县| 南宁市| 曲麻莱县| 长岭县| 兰西县| 即墨市| 平度市| 新巴尔虎右旗| 法库县| 定边县| 乐亭县| 页游| 兴安县| 长子县| 西盟| 璧山县| 绥芬河市| 竹北市| 陆河县|