2010-12-06 220 views
5

我寫了一個程序,需要一個'照片',併爲每個像素選擇插入一系列其他照片的圖像。所選圖像是平均顏色與照片中最接近原始像素的照片。附加到圖像文件

我已經完成了這一工作,首先對'股票'圖像中每個像素的RGB值進行平均,然後將其轉換爲CIE LAB,這樣我就可以計算出它在人類感知方面的「接近」的顏色。

我已經編輯了一幅圖像,其中原始「照片」圖像中的每個像素已被替換爲「最接近」的圖像。

它工作得很好,效果很好,但是股票圖像的大小是300×300像素,甚至是「-Xms2048m -Xmx2048m」的虛擬機標誌,這是我知道的嘲笑,在555px×540px圖像I只能在我得到內存不足錯誤之前將庫存圖像縮小到50 px。

所以基本上我試圖想出解決方案。首先,我認爲圖像效果本身可以通過將原始圖像的每4個像素(2×2平方)平均爲單個像素,然後用該圖像替換該像素來改善,因爲這樣小的照片將在單個打印中更明顯。這也應該允許我以更大的尺寸繪製圖像。有沒有人有這種圖像處理方面的經驗?如果是的話,你發現了什麼技巧來產生一個不錯的形象。

最終我認爲減少內存錯誤的方法是將圖像反覆保存到磁盤,並將下一行圖像附加到文件,同時不斷從內存中刪除舊的渲染圖像。如何才能做到這一點?是否類似於追加一個普通的文件。

任何幫助在這最後的事情將不勝感激。

感謝,

亞歷

回答

3

我建議尋找Java高級成像(JAI)API。您現在可能正在使用BufferedImage,它將所有內容都保存在內存中:源圖像和輸出圖像。這被稱爲「即時模式」處理。當您調用調整圖像大小的方法時,會立即發生。因此,您仍然將庫存圖像保存在內存中。

有了JAI,您可以利用兩個好處。

  1. 延期模式處理。
  2. 平鋪計算。

延遲模式意味着當您調用圖像上的方法時,輸出圖像無法正確計算。相反,調用圖像大小的調用會創建一個小的「運算符」對象,以便稍後調整大小。這使您可以構建鏈,樹或操作管道。因此,您的工作將爲每個庫存圖像構建一個操作樹,如「裁剪,調整大小,合成」。好的部分是操作只是命令對象,所以在構建命令時不會佔用所有內存。

此API是基於拉的。它延遲計算,直到某些輸出動作從操作員處拉出像素。這可以避免無用的像素操作,從而快速節省時間和內存。

例如,假設您需要一個2048 x 2048像素的輸出圖像,從1600x512像素的源圖像中的512x512裁剪中放大。顯然,放大整個1600x512的源圖像是沒有意義的,只是扔掉2/3像素。相反,縮放運算符將根據其輸出維度具有「感興趣區域」(ROI)。縮放運算符將ROI投影到源圖像上,並僅計算這些像素。

該命令最終必須得到評估。這在少數情況下發生,主要與最終圖像的輸出有關。因此,要求BufferedImage在屏幕上顯示輸出將強制所有命令進行評估。同樣,將輸出圖像寫入磁盤將強制評估。

在某些情況下,您可以保留基於圖塊渲染的JAI的第二個好處。儘管BufferedImage在所有像素中都立即執行了所有工作,但瓦片渲染一次只對圖像的矩形部分進行操作。

使用之前的示例,2048x2048輸出圖像將被分解爲圖塊。假設這些是256x256,那麼整個圖像會被分成64個圖塊。 JAI操作對象知道如何在瓦片上工作瓦片。因此,縮放源圖像的512x512部分實際上每次在64x64源像素上發生64次。

每次計算一個tile意味着在tile之間循環,這似乎需要更多時間。然而,在進行瓦片計算時,有兩件事對你有利。首先,瓷磚可以同時在多個線程上評估。其次,瞬時內存使用量遠遠低於即時模式計算。

所有這些都是你爲什麼要使用JAI來處理這類圖像的長篇大論。


有兩點要注意和警告:

  1. 你能打敗基於區塊的渲染沒有意識到這一點。無論你在工作流中獲得BufferedImage,它都不能用作瓦片源或接收器。
  2. 如果使用JPEG的JAI或JAI圖像I/O操作符渲染到磁盤,那麼您的狀態良好。如果您嘗試使用JDK的內置圖像類,則需要全部內存。 (基本上,避免混合兩種類型的圖像處理,即時模式和延遲模式不能很好地混合。)
  3. 所有具有感興趣區域,切片和延遲模式的花哨材料對程序都是透明的。您只需在JAI類上進行API調用。如果您需要更多控制瓦片大小,緩存和併發等功能,則只需處理機器。
0

每次你追加'你也許隱式創建一個多個像素的新對象,以取代舊的(即平行於反覆追加的經典問題到一個字符串,而不是使用StringBuilder)?

如果您發佈代碼的存儲和附加部分,有人可能會幫助您找到一種有效的重新編碼方式。

2

下面是一個可能有用的建議;

嘗試將兩個主要任務分離爲單個程序。你的第一個任務是決定哪些圖像去哪裏,這可以是座標的文件名一個簡單的映射,它可以表示爲文本行:在那之後任務完成

0,0,image123.jpg 
0,1,image542.jpg 
..... 

(這聽起來像你處理得好),那麼你可以有一個單獨的程序處理編譯。

此編譯可以通過附加到圖像來完成,但您可能不想自己弄亂文件格式。最好讓你的編程環境通過使用某種Java Image對象來完成它。您可以在內存中最大的一個像素爲2GB,最大高度和寬度爲sqrt(2x10^9)。從這個數字除以用於高度和寬度的圖像數量,您將獲得允許的每個子圖像的整體像素,並且可以將它們繪製到適當的位置。