tech.datatype
contains support for loading/saving buffered images
and creating tensors from buffered images.
user> (require '[tech.v2.datatype :as dtype])
nil
user> (require '[tech.libs.buffered-image :as bufimg])
nil
user> (def test-img (bufimg/load "../tech.opencv/test/data/test.jpg"))
#'user/test-img
user> test-img
#object[java.awt.image.BufferedImage 0x71374470 "BufferedImage@71374470: type = 5 ColorModel: #pixelBits = 24 numComponents = 3 color space = java.awt.color.ICC_ColorSpace@27f821b6 transparency = 1 has alpha = false isAlphaPre = false ByteInterleavedRaster: width = 512 height = 288 #numDataElements 3 dataOff[0] = 2"]
user> (dtype/get-datatype test-img)
:uint8
user> (dtype/shape test-img)
[288 512 3]
user> (bufimg/image-channel-format test-img)
:bgr
user> (require '[tech.v2.tensor :as dtt])
nil
;;It is safe to print tensors to repl. They will elide data in a similar fashion
;;as numpy arrays.
user> (dtt/ensure-tensor test-img)
#tech.v2.tensor<uint8>[288 512 3]
[[[172 170 170]
[172 170 170]
[171 169 169]
...
[ 24 18 23]
[ 24 18 23]
[ 24 18 23]]
...
;;You can get a fully-typed reader from a tensor to read indiviudal bytes:
user> (def test-rdr (tens-typecast/datatype->tensor-reader :uint8 (dtt/ensure-tensor test-img)))
#'user/test-rdr
user> (.read3d test-rdr 0 0 1)
170
user> (.read3d test-rdr 0 0 2)
170
user> (.read3d test-rdr 0 0 3)
172
;;If you have images of other base storage types you may get a different tensor than
;;you want:
user> (vec(keys bufimg/image-types))
[:int-bgr
:byte-gray
:byte-binary
:ushort-gray
:ushort-555-rgb
:int-argb-pre
:byte-indexed
:custom
:byte-bgr
:byte-abgr-pre
:int-rgb
:ushort-565-rgb
:byte-abgr
:int-argb]
user> (def test-img (bufimg/new-image 4 4 :int-bgr))
#'user/test-img
user> (dtt/ensure-tensor test-img)
#tech.v2.tensor<int32>[4 4 1]
[[[0]
[0]
[0]
[0]]
[[0]
[0]
[0]
[0]]
[[0]
[0]
[0]
[0]]
[[0]
[0]
[0]
[0]]]
;;So we have a convenience method that will always return a uint8 tensor:
user> (bufimg/as-ubyte-tensor test-img)
#tech.v2.tensor<uint8>[4 4 3]
[[[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]]
[[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]]
[[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]]
[[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]]]
;;You can use this as you can any other tensor. See the cheatsheet.
(def img-writer (tens-typecast/datatype->tensor-writer
:uint8
(bufimg/as-ubyte-tensor test-img)))
#'user/img-writer
user> (.write3d img-writer 2 2 1 255)
nil
user> (dtype/->reader test-img)
[0 0 0 0 0 0 0 0 0 0 65280 0 0 0 0 0]
user> (bufimg/as-ubyte-tensor test-img)
#tech.v2.tensor<uint8>[4 4 3]
[[[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]]
[[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]]
[[0 0 0]
[0 0 0]
[0 255 0]
[0 0 0]]
[[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]]]
;;Having images be tensors is useful for a few things, but stats is one of them.
user> (def planar-tens (dtt/transpose test-tens [2 0 1]))
#'user/planar-tens
user> planar-tens
#tech.v2.tensor<uint8>[3 288 512]
[[[172 172 171 ... 24 24 24]
[173 174 173 ... 23 23 23]
[174 175 174 ... 23 22 22]
...
[ 37 37 37 ... 55 54 55]
[ 36 35 35 ... 52 50 53]
[ 39 37 34 ... 51 49 53]]
[[170 170 169 ... 18 18 18]
[171 172 171 ... 17 17 17]
[172 173 172 ... 17 16 16]
...
[ 46 46 46 ... 51 50 51]
[ 45 44 44 ... 51 49 52]
[ 48 46 43 ... 50 48 52]]
[[170 170 169 ... 23 23 23]
[171 172 171 ... 22 22 22]
[172 173 172 ... 22 21 21]
...
[ 84 84 83 ... 56 55 56]
[ 83 82 81 ... 55 53 56]
[ 86 84 80 ... 54 52 56]]]
user> (require '[tech.v2.datatype.functional :as dfn])
nil
user> (map dfn/descriptive-stats planar-tens)
({:min 0.0,
:mean 97.47846137154495,
:ecount 147456,
:standard-deviation 60.735870710272195,
:median 97.0,
:max 248.0}
{:min 5.0,
:mean 101.00441487631271,
:ecount 147456,
:standard-deviation 58.55138215866227,
:median 102.0,
:max 255.0}
{:min 5.0,
:mean 113.43905978729688,
:ecount 147456,
:standard-deviation 57.79730239195752,
:median 115.0,
:max 255.0})
;;Drawing images work well in order to copy parts of one:
(def new-img (bufimg/new-image 512 512 :int-argb))
#'user/new-img
user> (bufimg/draw-image! test-img new-img :dst-y-offset 128)
#object[java.awt.image.BufferedImage 0x1ec0f94c "BufferedImage@1ec0f94c: type = 2 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=ff000000 IntegerInterleavedRaster: width = 512 height = 512 #Bands = 4 xOff = 0 yOff = 0 dataOffset[0] 0"]
;;But so does selecting subrects of tensors
user> (def copy-tens (dtt/select (bufimg/as-ubyte-tensor new-img) (range 128 (+ 288 128)) :all [0 1 2]))
#'user/copy-tens
user> copy-tens
#tech.v2.tensor<uint8>[288 512 3]
[[[172 170 170]
[172 170 170]
[171 169 169]
...
[ 24 18 23]
[ 24 18 23]
[ 24 18 23]]
user> (dtype/copy! test-img copy-tens)
#tech.v2.tensor<uint8>[288 512 3]
[[[172 170 170]
[172 170 170]
[171 169 169]
...
[ 24 18 23]
[ 24 18 23]
[ 24 18 23]]
...
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close