2016-08-04 54 views
0
像素

考慮以下簡單的Clojure到Java的互操作,用於讀取圖像的像素數據:獲取子圖像

(import java.awt.image.BufferedImage) 
(import javax.imageio.ImageIO) 
(require '[clojure.java.io :as io]) 

(defn read-image [path] 
    (ImageIO/read (io/file path))) 

(defn get-sub-image [img x y w h] 
    (.getSubimage img x y w h)) 

;; this assumes that images have no fourth alpha channel: 
(defn get-pixels 
    ([img x y w h] (get-pixels (get-sub-image img x y w h))) 
    ([img] (let [bytes (-> img .getRaster .getDataBuffer .getData)] 
      (map vec (partition 3 bytes))))) 

也能正常工作爲獲得整個圖像的像素,像這樣:

(def all-pixels (get-pixels (read-image "path/to/img.jpg"))) 
(nth all-pixels 0) 
;; [34 56 7] 
(count all-pixels) 
;; 122343 

但是,當試圖使用附加座標參數調用get-pixels時,結果仍包含整個數據:

(def some-pixels (get-pixels (read-image "path/to/img.jpg") 0 0 2 2)) 
(count some-pixels) 
;; 122343 

在這裏,我寧願只接收4個像素。缺陷在哪裏?

此外,還有關於將圖像數據作爲惰性序列處理的一般方法的任何評論都是值得歡迎的。

+0

來自'getSubImage'的文檔:'返回的BufferedImage與原始圖像共享相同的數據數組。'這不是原因嗎? https://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferedImage.html#getSubimage(int,%20int,%20int,%20int) – OlegTheCat

回答

0

這是一個有點難以閱讀的代碼,但如果我們走線槽源代碼:

public BufferedImage More ...getSubimage (int x, int y, int w, int h) { 
     return new BufferedImage (colorModel, 
            raster.createWritableChild(x, y, w, h, 
                  0, 0, null), 
            colorModel.isAlphaPremultiplied(), 
            properties); 
    } 

此方法調用raster.createWritableChild 讓我們來看看...

public WritableRaster More ...createWritableChild(int parentX, int parentY, 
               int w, int h, 
              int childMinX, int childMinY, 
              int bandList[]) { 
     if (parentX < this.minX) { 
      throw new RasterFormatException("parentX lies outside raster"); 
     } 
     if (parentY < this.minY) { 
      throw new RasterFormatException("parentY lies outside raster"); 
     } 
     if ((parentX+w < parentX) || (parentX+w > this.width + this.minX)) { 
      throw new RasterFormatException("(parentX + width) is outside raster"); 
     } 
     if ((parentY+h < parentY) || (parentY+h > this.height + this.minY)) { 
      throw new RasterFormatException("(parentY + height) is outside raster"); 
     } 

     SampleModel sm; 
     // Note: the SampleModel for the child Raster should have the same 
     // width and height as that for the parent, since it represents 
     // the physical layout of the pixel data. The child Raster's width 
     // and height represent a "virtual" view of the pixel data, so 
     // they may be different than those of the SampleModel. 
     if (bandList != null) { 
      sm = sampleModel.createSubsetSampleModel(bandList); 
     } 
     else { 
      sm = sampleModel; 
     } 

     int deltaX = childMinX - parentX; 
     int deltaY = childMinY - parentY; 

     return new WritableRaster(sm, 
            getDataBuffer(), 
            new Rectangle(childMinX,childMinY, 
               w, h), 
            new Point(sampleModelTranslateX+deltaX, 
              sampleModelTranslateY+deltaY), 
           this); 
    } 

正如你所看到的,創建的新光柵具有與其父級相同的DataBuffer(如果更新子圖像,可能允許修改整個圖像),因此當您執行此操作時,

img .getRaster .getDataBuffer 

你得到整個圖像的databuffer。

我沒有當然的測試,但BufferedImage.getData(Rectangle rect)應該返回一個新的光柵有自己的DataBuffer,然後做像你一樣

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/awt/image/BufferedImage.java#BufferedImage.getData%28%29

編輯:安東哈拉爾(OP)最終測試答案

(defn get-data [img x y w h] 
    (-> (.getData img (Rectangle. x y w h)) 
     .getDataBuffer 
     .getData)) 
+0

您的回答非常有幫助。特別是因爲它指出了子圖像的不同含義。如果你想,你可以添加到你的答案:(defn get-data [img xywh]( - >(.getData img(Rectangle。xywh)).getDataBuffer .getData))這是我最終使用的方法,派生自你的建議。 –

+0

感謝您的反饋,我添加了您的答案 –