基於Java的圖像象素處理(2)

討論和代碼
先討論這個ImgMod02.java
我們設計的初衷是: 展示如何在象素級別修改一個圖片 , 同時展示修改的結果, 並且和原始圖像對比
解壓圖像, 並且以象素方式來保存
 
這個程序將象素以三維的方式來保存
int[縱座標][ 橫座標][顏色]
第一, 二個數值代表了這個象素在圖像上的位置, 每個象素都不一樣, 底3個表示他的顏色, 用一個4byte表示了:
 
0 alpha
1 red
2 green
3 blue
 
數據類型
注意:這個數據是以整數顯示的, 這樣比無符號位更適合。
這個整數類型的選用可以排除很多因爲JAVA不支持有符號的算法而引起的麻煩。
 
支持的文件類型
 
這個程序支持jpg gif格式, 當然你也可以嘗試其他的格式, 如果這個程序不支持你所提供的格式, 他會拋出異常的
程序框架
這個程序你也可以改成一個怎麼獲取圖像象素的框架程序。換句話說, 這個程序做到了把圖像以象素的方式解開, 並且把它放進一個易於處理的格式裏面, 當然, 他也真實地操作了象素。
這些被改過的象素又返回程序, 和原始圖像一起展示給你, 如圖5所示
 
 
有用的信息
 
你可以這樣執行這個程序
java ImgMod02 ProcessingProgramName ImageFileName
 
用於測試, 源文件包含了一個處理象素方法的類: ProgramTest.
 
默認文件是junk.gif
第二個參數是可選的, 默認值是在程序當前目錄尋找一個叫junk.gif的文件
 
默認的圖像處理類是 ProgramTest
 
如果兩個參數都不寫, 就是用ProgramTest和junk.gif
【題外話】這個老外可真羅索,不知道這個文檔有人看沒有,感覺像唐僧。
 
圖像文件是必須由客戶提供的
如果你沒有這個junk.gif文件, 程序也會拋出異常
圖像顯示格式
當程序啓動之後, 原始圖像和處理之後的圖像都顯示在一個Frame裏面, 上面是原始圖像, 下面是處理之後的圖像。
Replot按鈕是用來重新加載的按鈕, 當您按下這個按鈕新的圖像將被加載。
processImg 方法
圖像象素程序必須實現ImgIntfc02接口, 這個接口只有一個方法:
int[][][] processImg(int[][][] threeDPix, int imgRows, int imgCols);
第一個參數是上文提到的3維象素數組,第二個和第三個表示這個圖像中需要處理的行數和列數。
 
這個圖像處理的類的構造器是不支持有參數的構造函數的。之所以這樣做, 是因爲在這個程序裏面, 圖像處理實例是通過ClassForName來獲得的,他的實例名來自命令行參數,這個決定了不適合用有參數的構造器。 這個圖像處理的類必須實現processImg方法
 
More on the processImg method
 
這個processImg 方法接受到一個3維數組,我們將這個數組做一個拷貝, 然後處理, 並且返回一個修改後的3維數組。
小心數值範圍
 processImg方法可以隨意地對象素的數組進行修改, 但是原始象素數據是由無符號位字節組成的, 如果您的處理方法是的這些數值成了一個負數或者>255的正數, 這個據要你處理一下了, 否則無論你做了什麼, 程序只是返回8位BIT的值, 而截斷你的其他位BIT, 顯示的效果肯定不是您所期望的。一個簡單的做法是:假設<0使之=0, >255使之=255.
 
操作細節
這個程序從文件讀取圖像數據,然後保存在一個rawImg內存對象裏面,然後被轉換成足夠大的int[] 數組裏面, 每個象素佔一個int[]值。這個一維數組叫做oneDPix. 程序實例化了一個 PixelGrabber對象, 用來獲得這個一維數組。
將一維的數組轉換成三維
 
兩個原因讓我們這樣做:
1)  便於做象素處理程序的調用
2)  將數據從無符號類型轉換成可以便於算法的有符號類型, 這點我以後在解釋
處理象素
【oldjavaman翻譯的時候的補充】
對於一個圖像文件來說, 假設我們是一個10pis*10pix的圖像, 當然這麼小的圖像基本沒有作用, 一般我們的程序的ICON的大小是32x32,爲了方便解釋1維》》3維的過程, 我們舉個例子來解釋, 下面的表格我們可以看成是放大的10x10的圖片, 計算機將他轉換成一個長度爲100的int[]數組, 他們分別對應了下面的格子。
0
1
2
3
4
5
6
7
8
9
10
 
 
 
 
 
 
 
 
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
 
 
 
 
 
 
 
99
 
 
 
 
 
 
 
 
 
 
 
 
那麼轉換成3維圖像是怎麼樣的?對應上圖中的紅色的pix將轉換成下面這個值
Pix[1][1][0]alpha
Pix[1][1][1]=red
Pix[1][1][2]=green
Pix[1][1][3]=blue
而綠色的pix 的值對應3維數組裏面的
Pix[8][3][0]alpha
Pix[8][3][1]=red
Pix[8][3][2]=green
Pix[8][3][3]=blue
之所以這樣操作, 目的是爲了未來做特殊效果, 如高亮這個象素做準備, 這樣更利於算法處理。我也開始成爲唐僧了。不知道您看到這裏懂了沒有。
主要代碼
獲取一維的象素點數據
 
try{
     PixelGrabber pgObj = new PixelGrabber( rawImg,0,0,imgCols,imgRows,
                              oneDPix,0,imgCols);
     if(pgObj.grabPixels()&&((pgObj.getStatus()& ImageObserver.ALLBITS)!= 0)){
threeDPix = convertToThreeDim( oneDPix,imgCols,imgRows);
     }
 
 
這個方法主要利用了PixelGrabber對象, 在PixelGrabber. grabPixels()方法執行後, 會把數據存儲在oneDPix數組中。
 
一維數據轉換成三維
int[][][] convertToThreeDim(
          int[] oneDPix,int imgCols,int imgRows){
       int[][][] data =
                    new int[imgRows][imgCols][4];
 
第一步先初始化一個3維數組, 如上所言, 第一個維數是行的象素值, 第二個是列的象素值, 第三個的長度=4
先獲得某一行的數組
for(int row = 0;row < imgRows;row++){
      int[] aRow = new int[imgCols];
      for(int col = 0; col < imgCols;col++){
        int element = row * imgCols + col;
        aRow[col] = oneDPix[element];
      }
在將這行的數據拆成4個整數, 用移位運算和與運算
for(int col = 0;col < imgCols;col++){
         data[row][col][0] = (aRow[col] >> 24) & 0xFF;
         data[row][col][1] = (aRow[col] >> 16) & 0xFF;
        data[row][col][2] = (aRow[col] >> 8) & 0xFF;
          data[row][col][3] = (aRow[col]) & 0xFF;
                                         
      }/
}
    return data;
 }
 
象素處理方法
在找個例子裏面, 我們找出所有的對角線位置的象素, 並將他置爲白色r=255, g=255 , b=255, 將apha值置爲255, 不透明。
int[][][] temp3D =
                    new int[imgRows][imgCols][4];
//第一步把獲得的3維數組做一個copy
    for(int row = 0;row < imgRows;row++){
      for(int col = 0;col < imgCols;col++){
        temp3D[row][col][0] =
                          threeDPix[row][col][0];
        temp3D[row][col][1] =
                          threeDPix[row][col][1];
        temp3D[row][col][2] =
                          threeDPix[row][col][2];
        temp3D[row][col][3] =
                          threeDPix[row][col][3];
      }
    }
for(int col = 0;col < imgCols;col++){
      int row = col;
      if(row > imgRows -1)break;
//設置成不透,明
      temp3D[row][col][0] = (byte)0xff;
      temp3D[row][col][1] = (byte)0xff;
      temp3D[row][col][2] = (byte)0xff;
      temp3D[row][col][3] = (byte)0xff;
    }
 
 
所有的程序下載: http://www.developer.com/java/other/article.php/3403921
總結
我展示了任何修改象素的方式來修改圖像,也提供了一個簡單的圖像象素修改程序
接下來的課程
接下來我們的課程將告訴你如何使用常規和非常規算法來實現一下功能:
  • 高亮一個圖像的某些區域.
  • 模糊一個圖像
  • 銳化一個圖像
  • 檢測一個圖像的邊緣
  • 過濾一個顏色
  • 讓圖像的顏色反轉
  • 讓兩個圖像融合
  • 旋轉一個圖像
  • 放大縮小一個圖像
  • 使用線性和非線性的方式來調整亮度
  • 其他的一些圖像處理效果
OldJavaMan的補充
    儘管這個程序運行的時候看起來平淡無償, 但是, 我們可以清晰的看到圖像象素的處理手段, 接下來我們只要對ImgIntfc02接口編寫實現類, 用算法來處理processImg方法, 就能獲得讓人心動的效果, 相信大家都用過PohtoShop, 我們一樣可以自己編寫程序來實現PS裏面的特效。
關於原始作者
Richard Baldwin 是德州的一名教授,他是一位私人顧問, 致力於C# , Java和XML技術的研究。 由於Java的平臺無關性, 他相信未來的web程序主要是用C#, Java 和XML來實現。 作者在很多美國德州的高科技企業擔任技術顧問,他是《Baldwin's Programming Tutorials》這本書的作者。他也經常在《JavaPro》雜誌撰寫文章。
 
Richard 有 Southern Methodist University學位,他有許多年的將計算機科技應用在現實世界的經驗。
 
關於譯者
OldJavaMan,長期致力於Java相關領域的技術工作, 主要參與J2EE相關程序的設計, 目前在南京的一家軟件企業就職,他希望和廣大的Java愛好者結交朋友。大家可以通過mail聯繫他 。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章