考虑以下简单的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个像素。哪个是缺陷?
欢迎任何关于将图像数据作为惰性序列处理的一般方法的评论。
答案 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的新栅格,然后按照你的方式执行
编辑:Anton Harald的(op)最终测试答案
(defn get-data [img x y w h]
(-> (.getData img (Rectangle. x y w h))
.getDataBuffer
.getData))