获取SubImage的像素

时间:2016-08-04 11:53:12

标签: java image-processing clojure io interop

考虑以下简单的Clojure到Java interop来读取图像的像素数据:

(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个像素。哪个是缺陷?

欢迎任何关于将图像数据作为惰性序列处理的一般方法的评论。

1 个答案:

答案 0 :(得分: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

你得到整个图像的数据缓冲区。

我当然没有测试,但是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

编辑:Anton Harald的(op)最终测试答案

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