-
Notifications
You must be signed in to change notification settings - Fork 6.8k
[Clojure] enhance draw bounding box #14567
Changes from 2 commits
1a74525
32bdf6c
5fec0cf
5e18d8e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,13 +17,15 @@ | |
(ns infer.objectdetector-example | ||
(:require [org.apache.clojure-mxnet.context :as context] | ||
[org.apache.clojure-mxnet.dtype :as dtype] | ||
[org.apache.clojure-mxnet.image :as image] | ||
[org.apache.clojure-mxnet.infer :as infer] | ||
[org.apache.clojure-mxnet.layout :as layout] | ||
[clojure.java.io :as io] | ||
[infer.draw :as draw] | ||
[clojure.string :refer [join]] | ||
[clojure.string :as string] | ||
[clojure.tools.cli :refer [parse-opts]]) | ||
(:gen-class)) | ||
(:gen-class) | ||
(:import (javax.imageio ImageIO) | ||
(java.io File))) | ||
|
||
(defn check-valid-dir | ||
"Check that the input directory exists" | ||
|
@@ -54,27 +56,30 @@ | |
:validate [check-valid-dir "Input directory not found"]] | ||
["-h" "--help"]]) | ||
|
||
(defn result->map [{:keys [class prob x-min y-min x-max y-max]}] | ||
(hash-map | ||
:label class | ||
:confidence (int (* 100 prob)) | ||
:top-left [x-min y-min] | ||
:bottom-right [x-max y-max])) | ||
|
||
(defn print-results [results] | ||
(doseq [_r results] | ||
(println (format "Class: %s Confidence=%s Coords=(%s, %s)" | ||
(_r :label) | ||
(_r :confidence) | ||
(_r :top-left) | ||
(_r :bottom-right))))) | ||
|
||
(defn process-results [images results output-dir] | ||
(dotimes [i (count images)] | ||
(let [image (nth images i) _results (map result->map (nth results i))] | ||
(println "processing: " image) | ||
(print-results _results) | ||
(draw/draw-bounds image _results output-dir)))) | ||
(mapv (fn [image-path result] | ||
gigasquid marked this conversation as resolved.
Show resolved
Hide resolved
|
||
(println "looking at image" image-path) | ||
(println "result: " result) | ||
(let [buf (ImageIO/read (new File image-path)) | ||
width (.getWidth buf) | ||
height (.getHeight buf) | ||
names (mapv :class result) | ||
coords (mapv (fn [result] | ||
(-> result | ||
(update :x-min #(* width %)) | ||
(update :x-max #(* width %)) | ||
(update :y-min #(* height %)) | ||
(update :y-max #(* height %)))) | ||
result) | ||
gigasquid marked this conversation as resolved.
Show resolved
Hide resolved
|
||
new-img (-> (ImageIO/read (new File image-path)) | ||
(image/draw-bounding-box! coords | ||
{:stroke 2 | ||
:names (mapv #(str (:class %) "-" (:prob %)) | ||
result) | ||
:transparency 0.5 | ||
:font-size-mult 1.0}))] | ||
(ImageIO/write new-img "jpg" (io/file output-dir (last (string/split image-path #"\/")))))) | ||
gigasquid marked this conversation as resolved.
Show resolved
Hide resolved
|
||
images results)) | ||
|
||
(defn detect-single-image | ||
"Detect objects in a single image and print top-5 predictions" | ||
|
@@ -109,7 +114,7 @@ | |
(apply concat | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need a concat here? Cant we use a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good idea, but it's also used in the example test to verify the results. |
||
(for [image-files image-file-batches] | ||
(let [image-batch (infer/load-image-paths image-files) | ||
topk 5 | ||
topk 5 | ||
res (infer/detect-objects-batch detector image-batch topk) ] | ||
(process-results | ||
image-files | ||
|
@@ -143,5 +148,5 @@ | |
(parse-opts args cli-options)] | ||
(cond | ||
(:help options) (println summary) | ||
(some? errors) (println (join "\n" errors)) | ||
(some? errors) (println (string/join "\n" errors)) | ||
:else (run-detector options)))) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -202,11 +202,11 @@ | |
(Image/toImage input)) | ||
|
||
(s/def ::buffered-image #(instance? BufferedImage %)) | ||
(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 ::x-min number?) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for improving this! |
||
(s/def ::x-max number?) | ||
(s/def ::y-min number?) | ||
(s/def ::y-max number?) | ||
(s/def ::coordinate (s/keys :req-un [::x-min ::x-max ::y-min ::y-max])) | ||
(s/def ::coordinates (s/coll-of ::coordinate)) | ||
(s/def ::names (s/nilable (s/coll-of string?))) | ||
(s/def ::stroke (s/and integer? pos?)) | ||
|
@@ -217,11 +217,11 @@ | |
|
||
(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)}) | ||
[{:keys [x-min x-max y-min y-max]}] | ||
{:xmin (int x-min) | ||
:xmax (int x-max) | ||
:ymin (int y-min) | ||
:ymax (int y-max)}) | ||
|
||
(defn draw-bounding-box! | ||
"Draw bounding boxes on `buffered-image` and Mutate the input image. | ||
|
@@ -233,9 +233,9 @@ | |
`transparency`: float in (0.0, 1.0) - Transparency of the bounding box | ||
returns: Modified `buffered-image` | ||
Ex: | ||
(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}] | ||
(draw-bounding-box! img [{:x-min 0 :x-max 100 :y-min 0 :y-max 100}]) | ||
(draw-bounding-box! [{:x-min 190 :x-max 850 :y-min 50 :y-max 450} | ||
{:x-min 200 :x-max 350 :y-min 440 :y-max 530}] | ||
{:stroke 2 | ||
:names [\"pug\" \"cookie\"] | ||
:transparency 0.8 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,7 +20,8 @@ | |
[org.apache.clojure-mxnet.ndarray :as ndarray] | ||
[clojure.java.io :as io] | ||
[clojure.test :refer :all]) | ||
(:import (javax.imageio ImageIO))) | ||
(:import (javax.imageio ImageIO) | ||
(java.io File))) | ||
|
||
(def tmp-dir (System/getProperty "java.io.tmpdir")) | ||
(def image-path (.getAbsolutePath (io/file tmp-dir "Pug-Cookie.jpg"))) | ||
|
@@ -76,4 +77,14 @@ | |
(let [img-arr (image/read-image image-path) | ||
resized-arr (image/resize-image img-arr 224 224) | ||
new-img (image/to-image resized-arr)] | ||
(is (= true (ImageIO/write new-img "png" (io/file tmp-dir "out.png")))))) | ||
(is (true? (ImageIO/write new-img "png" (io/file tmp-dir "out.png")))))) | ||
gigasquid marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
(deftest test-draw-bounding-box! | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you so much for adding this test! |
||
(let [new-img (-> (ImageIO/read (new File image-path)) | ||
(image/draw-bounding-box! [{:x-min 190 :x-max 850 :y-min 50 :y-max 450} | ||
{:x-min 200 :x-max 350 :y-min 440 :y-max 530}] | ||
{:stroke 2 | ||
:names ["pug" "cookie"] | ||
:transparency 0.8 | ||
:font-size-mult 2.0}))] | ||
(is (true? (ImageIO/write new-img "png" (io/file tmp-dir "out.png")))))) | ||
gigasquid marked this conversation as resolved.
Show resolved
Hide resolved
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉