Java線程控制的圖像分割與合成(轉(zhuǎn))
Java線程控制的圖像分割與合成(轉(zhuǎn))[@more@]摘 要:使用Java對WEB靜態(tài)圖像進(jìn)行分割重組,然后根據(jù)用戶的交互操作合成顯示,并利用線程對程序的并發(fā)性加以控制,從而達(dá)到圖像顯示的動(dòng)態(tài)性和交互性效果。
關(guān)鍵詞:Java語言 類Class 線程Thread
Java是一種面向?qū)ο蟮木幊陶Z言。它具有與平臺(tái)無關(guān)、面向?qū)ο蟆?dòng)態(tài)、安全等特點(diǎn),允許直接使用多線程方式進(jìn)行編程,對程序進(jìn)行并發(fā)控制。 Java還支持分布式網(wǎng)絡(luò)操作,從而能夠方便地進(jìn)行網(wǎng)絡(luò)文件對象的存取。利用Java語言本身提供的繪圖功能,可以繪制一些簡單的圖形。而對于復(fù)雜圖形,一般先用繪圖軟件制成圖像,然后采用Java所提供的方法對圖像下載并進(jìn)行處理和控制,從而實(shí)現(xiàn)靜態(tài)圖像的動(dòng)態(tài)顯示。
1 Java圖像處理與線程的并發(fā)控制
1.1 Java圖像處理
Java語言提供了豐富的類(Class)、接口(Interface)以及相應(yīng)的調(diào)用方法(Method)。使用這些類或接口,可以定義自己的類或子類,充分利用Java面向?qū)ο蟮奶匦赃M(jìn)行編程。在java.awt包中,提供了專門的Image類,它是1種抽象類,可提供抽象的方法描繪圖片的一些共同特性。而在Applet類和Tookit類中都提供了2種getImage()方法下載圖像,分別根據(jù)絕對地址和相對地址查詢所要下載的圖像。通常采用相對地址的下載方法,它的語法定義及功能如下:
1.public Image getImage(URL url,String name)
功能:根據(jù)相對地址下載圖像。
參數(shù):url??URL(統(tǒng)一資源定位)基地址,
name??圖像文件名。
獲取圖像后就可以調(diào)用Graphics類提供的drawImage()方法顯示圖像。
2.public drawImage(Image img,int x,int y,observer)
功能:在指定位置顯示圖像。
參數(shù):img??待顯示圖像,x??橫坐標(biāo),y??縱坐標(biāo),observer??圖像監(jiān)視器,用來監(jiān)視圖像的下載情況,接受圖像裝載信息(當(dāng)圖像完全載入時(shí)返回True,否則返回False)。
在顯示圖像時(shí),通常希望獲得對圖像的控制,從而以自己喜歡的各種方式實(shí)現(xiàn)媒體播放。為此,Java專門提供了用于跟蹤包括圖像和聲音等多媒體對象的ImageObserver類和MediaTracker類,在本文程序中主要用到的是跟蹤多幅圖像狀態(tài)的MediaTracker類。
1.2 Java多線程并發(fā)功能
目前,線程(Thread)已經(jīng)為許多操作系統(tǒng)和應(yīng)用開發(fā)系統(tǒng)所采用。線程是程序的單個(gè)控制流,具有順序程序的特點(diǎn),但是線程不是1個(gè)程序,它僅僅是程序的1個(gè)執(zhí)行序列。線程具有很強(qiáng)的并發(fā)功能,在同一時(shí)刻可能有多個(gè)線程同時(shí)處于執(zhí)行狀態(tài)。線程是動(dòng)態(tài)的,具有一定的生命周期,分別經(jīng)歷從創(chuàng)建、執(zhí)行、阻塞直到消亡的過程。Java語言中提供了專門的Thread類,以支持直接的多線程編程。Thread類提供了對線程的控制方法,如Start (),Stop(),Run()、Suspend()、resume()、Sleep()以及Run()方法等等,它們可以對線程的狀態(tài)進(jìn)行控制。并可以運(yùn)用SetPriority()方法設(shè)置線程的運(yùn)行優(yōu)先順序。Thread類的定義方法如下:
Thread(ThreadGroup group,Runable target,String name)
SetPriority()用來設(shè)置線程的優(yōu)先級。線程優(yōu)先級是1個(gè)介于MINPRIORITY(在類中定義為1)和MAXPRIORITY(在類中定義為10)之間的整數(shù)。線程不同的優(yōu)先級決定了不同線程之間的切換。
2 Java圖像分割與合成的算法及實(shí)現(xiàn)
Java程序首先將一個(gè)完整的圖像下載,然后將其分割成20個(gè)單元拼圖,即分為5行4列。在本例中特地將第20幅圖像單元設(shè)為1個(gè)空白圖像,以便拼圖時(shí)用戶交互操作使用。這些參數(shù)分別定義在相應(yīng)的變量中。
final int XCELLS=5; //每行拼圖的數(shù)目
final int YCELLS=4;//每列拼圖的數(shù)目
final int ALLCELLS=20;//分割元素的數(shù)目
final int EMPTY=19;//將第20單元,即cells[19]置成
//空白圖像
然后將這些圖像分割單元存于1個(gè)Cell類數(shù)組cells[]中,在這里Cell類中含有圖像以及它的起始位置和當(dāng)前位置,其具體定義如下:
class Cell
{int sx,sy; //起始位置
int cx,cy; //當(dāng)前位置
Image img; //單元圖像
public Cell(Image img,int x,int y) //Cell類構(gòu)造函數(shù)
{this.img=img;
sx=x;sy=y;} //給起始位置賦值為x,y
}
為了對每個(gè)圖像分割單元進(jìn)行狀態(tài)跟蹤,還需要建立1個(gè)MediaTracker類的實(shí)體(instance),然后調(diào)用addImage()方法,為每個(gè)要跟蹤的圖像指定1個(gè)唯一的標(biāo)識符。標(biāo)識符決定了圖像獲取時(shí)的優(yōu)先順序并使得圖像能夠獨(dú)立完整地進(jìn)行處理。
MediaTracker tracker=new MediaTracker(this)
//為當(dāng)前使用類建立1個(gè)MediaTracker實(shí)體,用于跟蹤類
//上的圖像
cells[EMPTY]=new Cell(createEmpty(),toPoint(EMPTY).x,toPoint(EMPTY).y);
tracker.addImage(cells[EMPTY].img,0);
//調(diào)用createEmpty()方法產(chǎn)生空白圖像,并加入到所跟蹤
//的cells數(shù)組中20單元
void setPosition(int x,int y) //設(shè)置單元圖像當(dāng)前位置
{cx=x;cy=y;}
各個(gè)圖像單元的位置存放于位置數(shù)組position里:
int position[][]=new int[XCELLs][YCELLS]
這樣就可以使用Cell類數(shù)組cells[]對圖像的各個(gè)單元進(jìn)行操作,從而將各個(gè)單元圖像進(jìn)行合成顯示,并通過position[][]數(shù)組改變各個(gè)單元的位置。為了對各單元進(jìn)行并發(fā)操作,需要對線程加以控制,并通過鼠標(biāo)事件和按鍵事件控制進(jìn)程的開始、睡眠和進(jìn)行等狀態(tài)變化,其實(shí)現(xiàn)方法如下 (僅以run()方法為例):
Thread imageThread=null; //定義線程imageThread,初始
//值為空
public void run()
{imageThread.setPriority(Thread.MINPRIORITY);//設(shè)置線
//程執(zhí)行優(yōu)先級別
try
{imageThread.sleep(2000);//線程睡眠等待2000ms
}catch(InterruptedException e){}
first=changeArray();//調(diào)用changeArray()方法隨機(jī)改變圖
//像單元位置
while(!loaded)//判斷圖像若未被跟蹤載入,則調(diào)用相關(guān)
//方法跟蹤并加載圖像
{repaint();
try
{imageThread.sleep(100);
}catch(InterruptedException e){System.out.println(e);}
}
}
changeArray()方法用來隨機(jī)地改變圖像單元的位置,其實(shí)現(xiàn)方法如下:
boolean changeArray()
{
int source[]=new int[20];
int full[]=new int[20];
for(int i=0;i {
int r=(int)(Math.random()*20);
while(full[r]!=0)
r=(r+(int)(Math.random()*20))%20;
source[i]=r;
full[r]=1;
}
int pos=0;
for(int i=0;i {
Point p=toPoint(source[pos]);
cells[pos].setPosition(p.x,p.y);
position[p.x][p.y]=pos;
}
x=cells[EMPTY].cx;
y=cells[EMPTY].cy;
return(false);
}
當(dāng)applet執(zhí)行后點(diǎn)擊鼠標(biāo),線程就被啟動(dòng),開始裝載圖像并執(zhí)行changeArray()隨機(jī)選擇1個(gè)位置來移動(dòng)圖像單元,此時(shí)可以使用鍵盤移動(dòng)圖像上的任意單元到任何位置。在這里還有一個(gè)重要內(nèi)容就是怎樣將圖像分割成許多的單元,我們可以通過引用CropImageFilter方法來分割圖像,它是1個(gè)分割圖像過濾器。其實(shí)現(xiàn)方法如下:
Image crop(int pos)
{//pos參數(shù)為調(diào)用函數(shù)給出的圖像單元位置號
Point p=toPoint(pos);//將位置號轉(zhuǎn)化為坐標(biāo)形式
ImageFilter filter=new CropImageFilter(xside*p.x,yside*p.y,xside,yside);
//在給定坐標(biāo)和長寬的絕對矩形區(qū)域內(nèi)創(chuàng)建分割圖像過
//濾器實(shí)體filter
ImageProducer producer=new FilteredImageSource(baseImage.getSource(),filter;)
//由原圖像和分割圖像過濾器實(shí)體創(chuàng)建新的圖像
//產(chǎn)生器producer
return createImage(producer);//由圖像產(chǎn)生器producer產(chǎn)生
//圖像并返回
}
通過以上步驟,整個(gè)圖像的分割與合成顯示就完成了。本程序主要利用了crop()、changeArray()、mousedown()、Thread()等方法以及幾個(gè)表示程序運(yùn)行狀態(tài)的布爾變量實(shí)現(xiàn)了一個(gè)線程控制和動(dòng)感圖像相結(jié)合的圖像處理過程。
作者單位:山東東營石油大學(xué)計(jì)算機(jī)系(257062)