熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

J2ME插值算法實現圖片的放大縮小方法

2013-11-23 19:13:44  來源: Java核心技術 

  前段時間接觸了一些數字圖像處理的問題位師兄的指導下在JME平台完成了一些基本的D圖像處理算法就當是對這段知識做一下總結決定把這些算法寫出來和各位朋友共同探討這篇文章先介紹圖像放大縮小的實現程序是以Nokia S的機器為平台實現的

  實現圖形縮放的基本思想

  圖像的變形變換簡單的說就是把源圖像每個點坐標通過變形運算轉為目標圖像相應點的新坐標但是這樣會導致一個問題就是目標點的坐標通常不會是整數所以我們在做放大變換時需要計算生成沒有被映射到的點;而在縮小變換時需要刪除一些點這裡我們采用最簡單的一種插值算法最近鄰域法顧名思義就是把非整數坐標作一個四捨五入取最近的整數點

  看下面的一個圖片放大的例子左圖為原始圖像右圖為放大倍的圖像裡面的數字表示所在像素的信息

  

  

  對於圖片像素的操作

  獲取Image圖片像素信息

  標准的midp沒有提供獲取圖片像素信息的函數對於NOKIA的機器我們可以采用Nokia SDK提供的API獲取像素信息具體程序如下

  
  g = imagegetGraphics()
  DirectGraphics dg = DirectUtilsgetDirectGraphics(g);
  dggetPixels(short[] pixels int offset int scanlength int xint y int width int height int format)

  參數介紹

  short[] pixels 用於接收像素信息的數組

  int offset這篇文章中的用到的地方就可以了

  int scanlength添圖片的寬度就行了

  int x

  int y

  int width圖片寬度

  int height圖片高度

  int format表示圖形格式好像Nokia S的機器都是采用格式表示RGB顏色的就是紅藍各用位表示至於可以表示透明色ARGB的格式應該是機器硬件實現的

  想具體了解Nokia SDK的信息可以查看Nokia SDK的幫助文檔

  使用像素信息數組生成Image圖片

  
  image = ImagecreateImage(w h);
  g = imagegetGraphics()
  DirectGraphics dg = DirectUtilsgetDirectGraphics(g);
  dgdrawPixels(short[] pixelsboolean transparency int offset int scanlength int x int y int widthint height int manipulation int format)
  short[] pixels像素信息數組
  boolean transparency是否包含alpha位信息
  int offset添 
  int scanlength添圖片的寬度就行了
  int x添 
  int y添 
  int width圖片寬度
  int height圖片高度
  int manipulation添 
  int format

  下面開始介紹具體的算法首先給出圖像縮放的完整函數然後對代碼分段進行解釋

  /*********************************

  * @todo 圖片放大縮小

  * @param srcImg 原始圖片

  * @param desW 變化後圖片的寬

  * @param desH 變化後圖片的高

  * @return 處理後的圖片

  *********************************/

  
 private Image ZoomImage(Image srcImg int desW int desH) {
  int srcW = srcImggetWidth(); //原始圖像寬
  int srcH = srcImggetHeight(); //原始圖像高
  short[] srcBuf = new short[srcW * srcH]; //原始圖片像素信息緩存
  //srcBuf獲取圖片像素信息
  Image desImg = ImagecreateImage(srcW srcH);
  if (srcImgisMutable()) { /*如果是可變圖像*/
  DirectUtilsgetDirectGraphics(srcImggetGraphics())
  getPixels(srcBuf  srcW   srcW srcH );
  } else { /*如果是非可變圖像*/
  desImggetGraphics()drawImage(srcImg   );
  DirectUtilsgetDirectGraphics(desImggetGraphics())
  getPixels(srcBuf  srcW   srcW srcH );
  }
  //計算插值表
  short[] tabY = new short[desH];
  short[] tabX = new short[desW];
  int sb = ;
  int db = ;
  int tems = ;
  int temd = ;
  int distance = srcH > desH ? srcH : desH;
  for (int i = ; i <= distance; i++) { /*垂直方向*/
  tabY[db] = (short) sb;
  tems += srcH;
  temd += desH;
  if (tems > distance) {
  tems = distance;
  sb++;
  }
  if (temd > distance) {
  temd = distance;
  db++;
  }
  }
  sb = ;
  db = ;
  tems = ;
  temd = ;
  distance = srcW > desW ? srcW : desW;
  for (int i = ; i <= distance; i++) { /*水平方向*/
  tabX[db] = (short) sb;
  tems += srcW;
  temd += desW;
  if (tems > distance) {
  tems = distance;
  sb++;
  }
  if (temd > distance) {
  temd = distance;
  db++;
  }
  }

//生成放大縮小後圖形像素buf
  short[] desBuf = new short[desW * desH];
  int dx = ;
  int dy = ;
  int sx = ;
  int sy = ;
  int oldy = ;
  for (int i = ; i < desH; i++) {
  if (oldy == tabY[i]) {
  Systemarraycopy(desBuf dy  desW desBuf dy desW);
  } else {
  dx = ;
  for (int j = ; j < desW; j++) {
  desBuf[dy + dx] = srcBuf[sy + tabX[j]];
  dx++;
  }
  sy += (tabY[i]  oldy) * srcW;
  }
  oldy = tabY[i];
  dy += desW;
  }
  //生成圖片
  desImg = ImagecreateImage(desW desH);
  DirectUtilsgetDirectGraphics(desImggetGraphics())
  drawPixels(desBuf true  desW   desW desH  );
  return desImg;
  }

  首先看函數的頭兩句很容易就是獲取原始圖片的寬度和高度

  
  int srcW = srcImggetWidth(); //原始圖像寬
  int srcH = srcImggetHeight(); //原始圖像高

  接下來一句我們要定義一個short型數組作為獲取原始圖片像素信息的緩存

  
 short[] srcBuf = new short[srcW * srcH];

  再下來一段有的朋友可能會有些不明白這裡要解釋一下由於getPixels()這個函數只能獲取可變圖像的像素信息非可變圖像無法獲取像素信息所以我們要用srcImgisMutable() 來判斷原始圖像是不是可變圖像然後分兩種情況來處理如果srcImg是可變圖像我們就直接用getPixels()來獲取它的像素信息並保存在srcBuf裡如果srcImg不是可變圖像我們就需要把srcImage畫到事先生成的可變圖像desImg上然後再獲取desImg的像素信息

  

  
 Image desImg = ImagecreateImage(srcW srcH);
  if (srcImgisMutable()) { /*如果是可變圖像*/
  DirectUtilsgetDirectGraphics(srcImggetGraphics())
  getPixels(srcBuf  srcW   srcW srcH );
  } else { /*如果是非可變圖像*/
  desImggetGraphics()drawImage(srcImg   );
  DirectUtilsgetDirectGraphics(desImggetGraphics())
  getPixels(srcBuf  srcW   srcW srcH );
  }

  再往下就是縮放算法的重點插值表的生成插值表分水平差值表和垂直插值表我們要分別生成原始圖像矩陣的種插值表然後利用插值表生成放大縮小後的圖像矩陣由於這個內容比較抽象很難用文字表述清楚所以我們用實例進行介紹

  大家看下面這個水平的*的表格

  

  | | | | |

  

  如果要將這個表格放大成*的表格放大的表格比原始表格多出了個格子我們只能對這多出來的個格子進行插值才能完成放大的操作現在結合生成水平插值表的代碼來完成這個過程

  
 distance = srcW > desW ? srcW : desW;
  for (int i = ; i <= distance; i++) { /*水平方向*/
  tabX[db] = (short) sb;
  tems += srcW;
  temd += desW;
  if (tems > distance) {
  tems = distance;
  sb++;
  }
  if (temd > distance) {
  temd = distance;
  db++;
  }
  }

  很明顯原始表格寬度srcW = ;放大後的表格寬度desW = ;所以distance = desW =

  接下來進入for循環我們一步步的演算其循環的過程

  

  | i| tabX賦值操作| tems | temd| sb | db |

  

  || tabX[] = | | | | |

  

  || tabX[] = | | | | |

  

  || tabX[] = | | | | |

  

  || tabX[] = | | | | |

  

  || tabX[] = | | | | |

  

  || tabX[] = | | | | |

  

  || tabX[] = | | | | |

  

  有此得到放大後*的表格為下圖所示其中每一個單元格中的數字n表示這個單元格的內容和原始表格中第n個單元格的內容一樣

  

  | | | | | | |

  

  例如左圖為原始表格右圖為放大的表格

  

  | 紅 | 綠 | 蘭 | 紫 | | 紅 | 綠 | 綠 | 蘭 | 紫 | 紫 |

  

  同樣垂直方向的插值表我們也可以用相同的方法獲得

  有了個插值表下面就可以生成放大和縮小後的圖像了

  
  short[] desBuf = new short[desW * desH];
  int dx = ;
  int dy = ;
  int sx = ;
  int sy = ;
  int oldy = ;
  for (int i = ; i < desH; i++) {
  if (oldy == tabY[i]) { /**********情況一**********/
  Systemarraycopy(desBuf dy  desW desBuf dy desW);
  } else { /**********情況二**********/
  dx = ;
  for (int j = ; j < desW; j++) {
  desBuf[dy + dx] = srcBuf[sy + tabX[j]];
  dx++;
  }
  sy += (tabY[i]  oldy) * srcW;
  }
  oldy = tabY[i];
  dy += desW;
  }

  desBuf是用來保存放大縮小後的圖像數據例如我們把一個*像素的圖像A放大成*的圖像B據前面的介紹我們可以生成個插值表tabX = {}tabY = {}

  在循環中會判斷是否oldy 等於 tabY[i]這個操作等同於tabY[i]是否等於tabY[i]如果等於表示圖像B前一行已經生成的數據和即將要生成的第i行數據相同則只要執行Systemarraycopy(desBuf dy desW desBuf dy desW)把上一行的數據復制過來即可;如果不等則需要對照水平插值表tabX生成這一行的數據

  算法演示過程如下

  

  | i|oldy|tabY[i]|運算情況|

  

  || | | 情況 |

  

  || | | 情況 |

  

  || | | 情況 |

  

  || | | 情況 |

  

  || | | 情況 |

  

  || | | 情況 |

  

  然後我們用desBuf生成最終放大或縮小後的圖片

  
  desImg = ImagecreateImage(desW desH);
  DirectUtilsgetDirectGraphics(desImggetGraphics())
  drawPixels(desBuf true  desW   desW desH  );
  return desImg;

  最後要說明一點的是由於該算法中使用了ImagecreateImage(w h)來創建圖像這個函數會創建一個w*h像素的全白可變圖像所以透明圖片放大縮小後背景不再透明而是白色了這是JME本身的缺憾和算法沒有關系對於這個問題有一個解決辦法就是程序的圖片不采用Image來保存而是采用short[]數組保存畫圖的時候用drawPixels()來畫圖


From:http://tw.wingwit.com/Article/program/Java/hx/201311/26482.html
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.