|
10 | 10 |
|
11 | 11 | (ns gis.geotiff |
12 | 12 | (:require |
13 | | - [scicloj.kindly.v4.kind :as kind])) |
| 13 | + [scicloj.kindly.v4.kind :as kind] |
| 14 | + [tech.v3.datatype :as dtype] |
| 15 | + [tech.v3.tensor :as tensor] |
| 16 | + [tech.v3.tensor.dimensions :as dims] |
| 17 | + [tech.v3.libs.buffered-image :as bufimg] |
| 18 | + [tablecloth.api :as tc] |
| 19 | + [clojure.java.io :as io])) |
14 | 20 | ;; # Cloud Optimized GeoTIFFs in JVM Clojure |
15 | 21 | ;; ## Motivation |
16 | 22 | ;; This document shows several different methods for handling COGs in JVM Clojure without |
|
33 | 39 | [:img {:src "resources/tiff_geotiff_cog.png" |
34 | 40 | :style {:width "60%"}}]) |
35 | 41 |
|
| 42 | + |
| 43 | + |
36 | 44 | ;; More about the internal structure of COGs can be learned [in the Cloud Native Geo Guide](https://guide.cloudnativegeo.org/cloud-optimized-geotiffs/intro.html) and at [COGeo](https://cogeo.org/). |
37 | 45 |
|
38 | 46 | ;; # TIFF handling with built-in Java libraries |
|
79 | 87 | num-bands (.getNumBands raster) |
80 | 88 | pixel (double-array num-bands)] |
81 | 89 | (.getPixel raster x y pixel) |
82 | | - (vec pixel))) |
| 90 | + ;; A dtype-next read-only buffer as a view of the Java array: |
| 91 | + (dtype/as-reader pixel))) |
83 | 92 |
|
84 | 93 | ;; Now we use the above helper functions to handle our locally held TIFF. |
85 | 94 |
|
|
128 | 137 |
|
129 | 138 | (require '[tablecloth.api :as tc]) |
130 | 139 |
|
131 | | -(defn buffered-image->dataset [^BufferedImage img] |
132 | | - (let [width (.getWidth img) |
133 | | - height (.getHeight img) |
134 | | - raster (.getRaster img) |
135 | | - num-bands (.getNumBands raster) |
| 140 | +(repeatedly 5 #(double-array 2 3)) |
136 | 141 |
|
137 | | - ;; Pre-allocate arrays for each band's pixel data |
138 | | - band-arrays (vec (repeatedly num-bands #(double-array (* width height)))) |
139 | 142 |
|
140 | | - ;; Read each band's data |
141 | | - _ (doseq [band (range num-bands)] |
142 | | - (.getSamples raster 0 0 width height band (nth band-arrays band))) |
143 | 143 |
|
144 | | - ;; Create coordinate arrays |
145 | | - xs (vec (for [_y (range height) x (range width)] x)) |
146 | | - ys (vec (for [y (range height) _x (range width)] y)) |
| 144 | +(defn buffered-image->dataset [^BufferedImage img] |
| 145 | + (let [width (.getWidth img) |
| 146 | + height (.getHeight img) |
| 147 | + num-bands (.getNumBands (.getRaster img)) |
| 148 | + |
| 149 | + tensor (-> img |
| 150 | + dtype/->array-buffer |
| 151 | + ;; height x width x bands |
| 152 | + (tensor/construct-tensor (dims/dimensions |
| 153 | + [width height num-bands])) |
| 154 | + ;; bands x height x width |
| 155 | + (tensor/transpose [2 0 1])) |
| 156 | + |
| 157 | + xs (dtype/as-reader |
| 158 | + (tensor/compute-tensor [height width] |
| 159 | + (fn [y x] x))) |
| 160 | + ys (dtype/as-reader |
| 161 | + (tensor/compute-tensor [height width] |
| 162 | + (fn [y x] y))) |
147 | 163 |
|
148 | 164 | ;; Build dataset |
149 | 165 | ds-map (into {:x xs :y ys} |
150 | | - (map-indexed |
151 | | - (fn [i arr] [(keyword (str "band-" i)) (vec arr)]) |
152 | | - band-arrays))] |
| 166 | + (for [i (range num-bands)] |
| 167 | + [(keyword (str "band-" i)) |
| 168 | + (dtype/as-reader |
| 169 | + (tensor i))]))] |
153 | 170 | (tc/dataset ds-map))) |
154 | 171 |
|
| 172 | + |
155 | 173 | (defonce ds (-> example-geotiff-medium |
156 | 174 | :images |
157 | 175 | first |
|
408 | 426 | (defonce medium-geotiff |
409 | 427 | (geotools-read-geotiff "src/gis/resources/example_geotiff_medium.tif")) |
410 | 428 |
|
411 | | - |
| 429 | + |
412 | 430 |
|
413 | 431 | (->> medium-geotiff |
414 | 432 | :coverage |
|
0 commit comments