@@ -282,9 +282,11 @@ sample-buffer
282282(def sample-reader
283283 (dtype/->reader sample-buffer))
284284
285- ; ; Access elements by index:
285+ ; ; **Important**: Readers act as functions of their index. You can call them directly
286+ ; ; instead of using `dtype/get-value`. This pattern extends to tensors as well—both
287+ ; ; readers and tensors are callable:
286288
287- (dtype/get-value sample-reader 0 )
289+ (sample-reader 0 )
288290
289291; ; Map over readers like sequences:
290292
@@ -378,11 +380,15 @@ writable-buffer
378380
379381; ; **Key insight**: All these are zero-copy views—no data is copied.
380382
381- ; ; ## Element Access: tensor/mget
383+ ; ; ## Element Access: Tensors as Functions
382384
383- ; ; `tensor/mget` reads a single element at given indices:
385+ ; ; Like readers, tensors act as functions of their indices. You can call them directly
386+ ; ; with coordinate arguments:
384387
385- (tensor/mget toy-tensor 1 2 )
388+ (toy-tensor 1 2 )
389+
390+ ; ; This is equivalent to `(tensor/mget toy-tensor 1 2)` but more idiomatic. Both readers
391+ ; ; and tensors follow this pattern—they're callable values, not just data structures.
386392
387393; ; ## Slicing Dimensions: tensor/slice and tensor/slice-right
388394
@@ -544,71 +550,49 @@ flat-tensor
544550
545551; ; ## Extracting Color Channels
546552
547- ; ; There are two main approaches for extracting channels:
548- ; ;
549- ; ; 1. **tensor/select** — Extract specific channels by index
550- ; ; 2. **tensor/slice-right** — Iterate over all channels cleanly
551- ; ;
552- ; ; We'll use `tensor/select` for explicit channel extraction:
553+ ; ; Use `tensor/slice-right` to extract all channels cleanly:
553554
554555(def channels
555556 (let [[blue green red] (tensor/slice-right original-tensor 1 )]
556557 {:blue blue :green green :red red}))
557558
558559; ; Each channel is now `[H W]` instead of `[H W C]`:
559560
560- (:red channels)
561+ (dtype/shape ( :red channels) )
561562
562563; ; **Key insight**: These are **zero-copy views** into the original tensor—no data is copied.
563564; ;
564- ; ; **Alternative with tensor/select**:
565- ; ; Blue channel:
566- (tensor/select original-tensor :all :all 2 )
565+ ; ; **Alternative with tensor/select** (when you need one specific channel):
566+ (def blue-only (tensor/select original-tensor :all :all 0 )) ; Channel 0 = Blue
567+
568+ (dtype/shape blue-only)
567569
568570; ; ## Channel Statistics
569571
570- ; ; Compute mean, standard deviation, min, max for each channel:
572+ ; ; Compute mean, standard deviation, min, max, and percentiles for each channel:
571573
572574(defn channel-stats
573575 " Compute statistics for a single channel tensor.
574576 Takes: [H W] tensor
575- Returns: map with :mean, :std, :min, :max scalars "
577+ Returns: map with :mean, :std, :min, :max, percentiles "
576578 [channel]
577- {:mean (dfn/mean channel)
578- :std (dfn/standard-deviation channel)
579- :min (dfn/reduce-min channel)
580- :max (dfn/reduce-max channel)})
579+ (let [percentiles (dfn/percentiles channel [25 50 75 ])]
580+ {:mean (dfn/mean channel)
581+ :std (dfn/standard-deviation channel)
582+ :min (dfn/reduce-min channel)
583+ :max (dfn/reduce-max channel)
584+ :q25 (percentiles 0 )
585+ :median (percentiles 1 )
586+ :q75 (percentiles 2 )}))
587+
588+ ; ; Apply to our extracted channels:
581589
582590(->> channels
583591 (map (fn [[k v]]
584592 (merge {:channel k}
585593 (channel-stats v))))
586594 tc/dataset)
587595
588- ; ; ## Enhanced Channel Statistics with slice-right
589-
590- ; ; Now let's see a cleaner approach using `tensor/slice-right` with more comprehensive
591- ; ; statistics including percentiles:
592-
593- (tc/dataset
594- (map (fn [color channel]
595- (let [percentiles (dfn/percentiles channel [25 50 75 ])]
596- {:channel color
597- :mean (dfn/mean channel)
598- :std (dfn/standard-deviation channel)
599- :min (dfn/reduce-min channel)
600- :max (dfn/reduce-max channel)
601- :q25 (dtype/get-value percentiles 0 )
602- :median (dtype/get-value percentiles 1 )
603- :q75 (dtype/get-value percentiles 2 )}))
604- [" blue" " green" " red" ]
605- (tensor/slice-right original-tensor 1 )))
606-
607- ; ; **Key advantages of slice-right**:
608- ; ; - Cleaner iteration over all channels
609- ; ; - No need to manually specify indices
610- ; ; - Natural destructuring: `(let [[b g r] (tensor/slice-right img 1)] ...)`
611-
612596; ; ## Brightness Analysis
613597
614598; ; Convert to grayscale using perceptual luminance formula.
@@ -710,6 +694,14 @@ flat-tensor
710694 {:pair " Blue-Red" :correlation (correlation blue red)}
711695 {:pair " Green-Red" :correlation (correlation green red)}]))
712696
697+ (let [[blue green red] (tensor/slice-right (auto-white-balance
698+ original-tensor)
699+ 1 )]
700+ (tc/dataset
701+ [{:pair " Blue-Green" :correlation (correlation blue green)}
702+ {:pair " Blue-Red" :correlation (correlation blue red)}
703+ {:pair " Green-Red" :correlation (correlation green red)}]))
704+
713705; ; **Interpretation**:
714706; ; - Correlation near 1.0: Channels move together (consistent lighting, color cast)
715707; ; - Correlation near 0.0: Channels independent (varied colors, good white balance)
@@ -955,14 +947,14 @@ edges
955947 [tensor-2d]
956948 (let [flat (dtype/as-reader (tensor/reshape tensor-2d [(dtype/ecount tensor-2d)]))
957949 [h w] (dtype/shape tensor-2d)
958- max-idx (apply max-key #(dtype/get-value flat %) (range (dtype/ecount flat)))
959- min-idx (apply min-key #(dtype/get-value flat %) (range (dtype/ecount flat)))]
950+ max-idx (apply max-key #(flat %) (range (dtype/ecount flat)))
951+ min-idx (apply min-key #(flat %) (range (dtype/ecount flat)))]
960952 {:brightest {:block-y (quot max-idx w)
961953 :block-x (rem max-idx w)
962- :value (dtype/get-value flat max-idx)}
954+ :value (flat max-idx)}
963955 :darkest {:block-y (quot min-idx w)
964956 :block-x (rem min-idx w)
965- :value (dtype/get-value flat min-idx)}}))
957+ :value (flat min-idx)}}))
966958
967959(find-block-extremes brightness-map)
968960
@@ -1006,7 +998,7 @@ edges
1006998 ; ; Scale each channel (vectorized operations per channel)
1007999 scaled-channels (mapv (fn [ch]
10081000 (let [channel (tensor/select img-tensor :all :all ch)
1009- scale (dtype/get-value scale-factors ch)]
1001+ scale (scale-factors ch)]
10101002 (dtype/elemwise-cast
10111003 (dfn/min 255 (dfn/* channel scale))
10121004 :uint8 )))
@@ -1016,7 +1008,7 @@ edges
10161008 (tensor/compute-tensor
10171009 [h w c]
10181010 (fn [y x ch]
1019- (tensor/mget (nth scaled-channels ch) y x))
1011+ ((nth scaled-channels ch) y x))
10201012 :uint8 )))
10211013
10221014(kind/table
@@ -1059,7 +1051,7 @@ edges
10591051 (tensor/compute-tensor
10601052 [h w c]
10611053 (fn [y x ch]
1062- (tensor/mget (nth enhanced-channels ch) y x))
1054+ ((nth enhanced-channels ch) y x))
10631055 :uint8 )))
10641056
10651057(def contrasted (enhance-contrast original-tensor 1.5 ))
@@ -1149,9 +1141,9 @@ edges
11491141 [h w 3 ]
11501142 (fn [y x c]
11511143 (case c
1152- 0 (tensor/mget new-b-clamped y x) ; Blue channel 0
1153- 1 (tensor/mget new-g-clamped y x) ; Green channel 1
1154- 2 (tensor/mget new-r-clamped y x))) ; Red channel 2
1144+ 0 (new-b-clamped y x) ; Blue channel 0
1145+ 1 (new-g-clamped y x) ; Green channel 1
1146+ 2 (new-r-clamped y x))) ; Red channel 2
11551147 :uint8 )))
11561148
11571149(defn simulate-color-blindness
@@ -1248,8 +1240,8 @@ kernel-3x3
12481240 in-bounds? (and (>= img-y 0 ) (< img-y h)
12491241 (>= img-x 0 ) (< img-x w))
12501242 new-sum (if in-bounds?
1251- (+ sum (* (tensor/mget kernel ky kx)
1252- (tensor/mget img-2d img-y img-x)))
1243+ (+ sum (* (kernel ky kx)
1244+ (img-2d img-y img-x)))
12531245 sum)
12541246 [next-ky next-kx] (if (>= (inc kx) kw)
12551247 [(inc ky) 0 ]
@@ -1573,12 +1565,12 @@ gaussian-5x5
15731565; ; - `dtype/elemwise-cast` — Convert between types
15741566; ; - `dtype/ecount` — Total element count
15751567; ; - `dtype/as-reader` — Convert to readable sequence
1576- ; ; - ` dtype/get-value` — Extract scalar value
1568+ ; ; - Readers act as functions: `(reader idx)` instead of `( dtype/get-value reader idx)`
15771569
15781570; ; **tensor namespace (tech.v3.tensor):**
15791571; ; - `tensor/compute-tensor` — Functionally construct tensors
15801572; ; - `tensor/select` — Extract slices, channels (zero-copy)
1581- ; ; - ` tensor/mget` — Read single elements
1573+ ; ; - Tensors act as functions: `( tensor y x)` instead of `(tensor/mget tensor y x)`
15821574; ; - `tensor/reshape` — Reinterpret tensor shape (zero-copy)
15831575; ; - `tensor/reduce-axis` — Reduce along specific dimension
15841576
0 commit comments