BufferedImage's .getRaster .getNumBands can be used in figuring out the shape
The namespace tech.v3.libs.buffered-image extends BufferedImage with certain protocols, including the extraction of shape (tech.v3.datatype/shape):
https://github.com/cnuernber/dtype-next/blob/9170e69/src/tech/v3/libs/buffered_image.clj#L160
In unknown image types, it is assumed only one band: https://github.com/cnuernber/dtype-next/blob/9170e69/src/tech/v3/libs/buffered_image.clj#L177
However, the number of bands can be extracted using .getRaster .getNumBands, as @larzeitlin does in an upcoming tutorial about Cloud Optimized GeoTiff:
https://github.com/ClojureCivitas/clojurecivitas.github.io/blob/be26c88/src/gis/geotiff.clj#L135
Example test file: https://github.com/ClojureCivitas/clojurecivitas.github.io/blob/be26c887796258f9ae31756cc3da7b654cf8d11c/src/gis/resources/example_geotiff_medium.tif
You can download it, and use the following code from @larzeitlin's tutorial to read it and extract the number of bands:
(import '[java.awt.image BufferedImage]
'[java.io File]
'[javax.imageio ImageIO]
'[javax.imageio.stream FileImageInputStream])
(defn tiff-reader []
(let [readers (ImageIO/getImageReadersByFormatName "tiff")]
(.next readers)))
(defn read-tiff [file-path]
(let [file (File. file-path)
reader (tiff-reader)]
(with-open [stream (FileImageInputStream. file)]
(.setInput reader stream)
(let [images (doall
;; A single TIFF can store multiple images.
;; This will be significant when we come to
;; GeoTIFFs because of resolution pyramids.
;; See below.
(for [i (range (.getNumImages reader true))]
(let [metadata (.getImageMetadata reader i)
native-format (.getNativeMetadataFormatName metadata)]
{:index i
:native-format native-format
:width (.getWidth reader i)
:height (.getHeight reader i)
:image (.read reader i)
:metadata metadata})))]
{:images images
:reader-format (.getFormatName reader)}))))
(-> "example_geotiff_medium.tif"
read-tiff
:images
first
:image
.getRaster
.getNumBands)
This will also affect tech.v3.tensor/as-tensor and allow it to come up with the right shape of output, this allowing to turn any Raster image to a tensor -- quite important for working with multispectral images.
Zulip discussion with @harold: #tech.ml.dataset.dev > shape of an image
Thanks @daslu - this is great.
The example_geotiff_medium.tif seems to be sort of big (80+MB), and not multi-image or multispectral.
Though it does load and shape returns [4999 5999 1]
I am working on a patch that makes shape return [4999 5999 3], which is an improvement, but I'd like to test it against additional files.
Do you know of any other test images? Perhaps smaller, and maybe w/ more than one image per file, or more than 3 bands per image?
example geotiff: https://github.com/larzeitlin/example_small_ms_geotiff
@larzeitlin - super 🆒, well done, we'll check it out.
AFAIK this should support multiplex ome-tiff, too (open microscopy format). There's example data here. getRaster -> getNumBands appears to be used heavily in QuPath w/o much exception babying. [ ex ]
AFAIK this should support multiplex ome-tiff, too (open microscopy format). There's example data here.
getRaster->getNumBandsappears to be used heavily in QuPath w/o much exception babying. [ ex ]
Great to see you here, the whole buffered-image namespace has roots in our original conversations about multispectral images, so it's nice to see this progressing. This is on our list to look at, thanks for everyone's patience.