Skip to content
This repository has been archived by the owner on Nov 17, 2023. It is now read-only.

[clojure][image] add draw-bounding-box interop #14533

Merged
merged 2 commits into from
Mar 29, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions contrib/clojure-package/src/org/apache/clojure_mxnet/image.clj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
[org.apache.clojure-mxnet.util :as util]
[clojure.spec.alpha :as s])
(:import (org.apache.mxnet Image NDArray)
(java.awt.image BufferedImage)
(java.io InputStream)))

;; Flags for conversion of images
Expand Down Expand Up @@ -199,3 +200,68 @@
[input]
(util/validate! ::to-image-ndarray input "Invalid input array")
(Image/toImage input))

(s/def ::buffered-image #(instance? BufferedImage %))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice specs 😍

(s/def ::xmin integer?)
(s/def ::xmax integer?)
(s/def ::ymin integer?)
(s/def ::ymax integer?)
(s/def ::coordinate (s/keys :req-un [::xmin ::xmax ::ymin ::ymax]))
(s/def ::coordinates (s/coll-of ::coordinate))
(s/def ::names (s/nilable (s/coll-of string?)))
(s/def ::stroke (s/and integer? pos?))
(s/def ::font-size-mult (s/and float? pos?))
(s/def ::transparency (s/and float? #(<= 0.0 % 1.0)))
(s/def ::coordinates-names
(fn [[coordinates names]] (= (count coordinates) (count names))))

(defn- convert-coordinate
"Convert bounding box coordinate to Scala correct types."
[{:keys [xmin xmax ymin ymax]}]
{:xmin (int xmin)
:xmax (int xmax)
:ymin (int ymin)
:ymax (int ymax)})

(defn draw-bounding-box!
"Draw bounding boxes on `buffered-image` and Mutate the input image.
`buffered-image`: BufferedImage
`coordinates`: collection of {:xmin int :xmax int :ymin int :ymax int}
`font-size-mult`: positive float - Font size multiplier
`names`: collection of strings - List of names for the bounding boxes
`stroke`: positive integer - thickness of the bounding box
`transparency`: float in (0.0, 1.0) - Transparency of the bounding box
returns: Modified `buffered-image`
Ex:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like the examples in the docstring

(draw-bounding-box! img [{:xmin 0 :xmax 100 :ymin 0 :ymax 100}])
(draw-bounding-box! [{:xmin 190 :xmax 850 :ymin 50 :ymax 450}
{:xmin 200 :xmax 350 :ymin 440 :ymax 530}]
{:stroke 2
:names [\"pug\" \"cookie\"]
:transparency 0.8
:font-size-mult 2.0})"
([buffered-image coordinates]
(draw-bounding-box! buffered-image coordinates {}))
([buffered-image coordinates
{:keys [names stroke font-size-mult transparency]
:or {stroke 3 font-size-mult 1.0 transparency 1.0}
:as opts}]
(util/validate! ::buffered-image buffered-image "Invalid input image")
(util/validate! ::coordinates coordinates "Invalid input coordinates")
(util/validate! ::names names "Invalid input names")
(util/validate! ::stroke stroke "Invalid input stroke")
(util/validate! ::font-size-mult font-size-mult "Invalid input font-size-mult")
(util/validate! ::transparency transparency "Invalid input transparency")
(when (pos? (count names))
(util/validate! ::coordinates-names [coordinates names] "Invalid number of names"))
(Image/drawBoundingBox
buffered-image
(->> coordinates
(map convert-coordinate)
(map util/convert-map)
(into-array))
(util/->option (into-array names))
(util/->option (int stroke))
(util/->option (float font-size-mult))
(util/->option (float transparency)))
buffered-image))