You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mxnet.apache.org by cm...@apache.org on 2018/11/11 13:43:50 UTC

[incubator-mxnet] branch master updated: Port of scala Image API to clojure (#13107)

This is an automated email from the ASF dual-hosted git repository.

cmeier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-mxnet.git


The following commit(s) were added to refs/heads/master by this push:
     new b441628  Port of scala Image API to clojure (#13107)
b441628 is described below

commit b4416288ff6c7bab3293e73fe7d526a716630677
Author: Kedar Bellare <ke...@gmail.com>
AuthorDate: Sun Nov 11 05:43:22 2018 -0800

    Port of scala Image API to clojure (#13107)
    
    * Port of scala Image API to clojure
    
    * Minor style changes
    
    * Add specs and other minor fixes
    
    * Fix unit tests (:facepalm:)
---
 .../src/org/apache/clojure_mxnet/image.clj         | 139 +++++++++++++++++++++
 .../test/org/apache/clojure_mxnet/image_test.clj   |  79 ++++++++++++
 2 files changed, 218 insertions(+)

diff --git a/contrib/clojure-package/src/org/apache/clojure_mxnet/image.clj b/contrib/clojure-package/src/org/apache/clojure_mxnet/image.clj
new file mode 100644
index 0000000..6e726eb
--- /dev/null
+++ b/contrib/clojure-package/src/org/apache/clojure_mxnet/image.clj
@@ -0,0 +1,139 @@
+;;
+;; Licensed to the Apache Software Foundation (ASF) under one or more
+;; contributor license agreements.  See the NOTICE file distributed with
+;; this work for additional information regarding copyright ownership.
+;; The ASF licenses this file to You under the Apache License, Version 2.0
+;; (the "License"); you may not use this file except in compliance with
+;; the License.  You may obtain a copy of the License at
+;;
+;;    http://www.apache.org/licenses/LICENSE-2.0
+;;
+;; Unless required by applicable law or agreed to in writing, software
+;; distributed under the License is distributed on an "AS IS" BASIS,
+;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;; See the License for the specific language governing permissions and
+;; limitations under the License.
+;;
+
+(ns org.apache.clojure-mxnet.image
+  (:require [t6.from-scala.core :refer [$ $$] :as $]
+            [org.apache.clojure-mxnet.dtype :as dtype]
+            [org.apache.clojure-mxnet.ndarray :as ndarray]
+            [org.apache.clojure-mxnet.util :as util]
+            [clojure.spec.alpha :as s])
+  (:import (org.apache.mxnet Image NDArray)
+           (java.io InputStream)))
+
+;; Flags for conversion of images
+(def GRAYSCALE 0)
+(def COLOR 1)
+
+(s/def ::input-stream #(instance? InputStream %))
+(s/def ::color-flag #{GRAYSCALE COLOR})
+(s/def ::to-rgb boolean?)
+(s/def ::ndarray #(instance? NDArray %))
+(s/def ::output (s/or :empty nil? :ndarray ::ndarray))
+(s/def ::decode-image-opts
+  (s/keys :opt-un [::color-flag ::to-rgb ::output]))
+
+(defn decode-image
+  "Decodes an image from an input stream"
+  ([input-stream {:keys [color-flag to-rgb output]
+                  :or {color-flag COLOR to-rgb true output nil}
+                  :as opts}]
+   (util/validate! ::input-stream input-stream "Invalid input stream")
+   (util/validate! ::decode-image-opts opts "Invalid options for decoding")
+   (Image/imDecode input-stream color-flag to-rgb ($/option output)))
+  ([input-stream]
+   (decode-image input-stream {})))
+
+(s/def ::filename string?)
+(s/def ::optional-color-flag
+  (s/or :none nil? :some ::color-flag))
+(s/def ::optional-to-rgb
+  (s/or :none nil? :some ::to-rgb))
+
+(defn read-image
+  "Reads an image file and returns an ndarray"
+  ([filename {:keys [color-flag to-rgb output]
+              :or {color-flag nil to-rgb nil output nil}
+              :as opts}]
+   (util/validate! ::filename filename "Invalid filename")
+   (util/validate! ::optional-color-flag color-flag "Invalid color flag")
+   (util/validate! ::optional-to-rgb to-rgb "Invalid conversion flag")
+   (util/validate! ::output output "Invalid output")
+   (Image/imRead 
+    filename 
+    ($/option color-flag)
+    ($/option to-rgb)
+    ($/option output)))
+  ([filename]
+   (read-image filename {})))
+
+(s/def ::int int?)
+(s/def ::optional-int (s/or :none nil? :some int?))
+
+(defn resize-image
+  "Resizes the image array to (width, height)"
+  ([input w h {:keys [interpolation output]
+               :or {interpolation nil output nil}
+               :as opts}]
+   (util/validate! ::ndarray input "Invalid input array")
+   (util/validate! ::int w "Invalid width")
+   (util/validate! ::int h "Invalid height")
+   (util/validate! ::optional-int interpolation "Invalid interpolation")
+   (util/validate! ::output output "Invalid output")
+   (Image/imResize input w h ($/option interpolation) ($/option output)))
+  ([input w h]
+   (resize-image input w h {})))
+
+(defn apply-border
+  "Pad image border"
+  ([input top bottom left right 
+    {:keys [fill-type value values output]
+     :or {fill-type nil value nil values nil output nil}
+     :as opts}]
+   (util/validate! ::ndarray input "Invalid input array")
+   (util/validate! ::int top "Invalid top margin")
+   (util/validate! ::int bottom "Invalid bottom margin")
+   (util/validate! ::int left "Invalid left margin")
+   (util/validate! ::int right "Invalid right margin")
+   (util/validate! ::optional-int fill-type "Invalid fill type")
+   (util/validate! ::output output "Invalid output")
+   (Image/copyMakeBorder input top bottom left right
+                         ($/option fill-type)
+                         ($/option value)
+                         ($/option values)
+                         ($/option output)))
+  ([input top bottom left right]
+   (apply-border input top bottom left right {})))
+
+(defn fixed-crop
+  "Return a fixed crop of the image"
+  [input x0 y0 w h]
+  (util/validate! ::ndarray input "Invalid input array")
+  (util/validate! ::int x0 "Invalid starting x coordinate")
+  (util/validate! ::int y0 "Invalid starting y coordinate")
+  (util/validate! ::int w "Invalid width")
+  (util/validate! ::int h "Invalid height")
+  (Image/fixedCrop input x0 y0 w h))
+
+(defn rgb-array?
+  "Returns whether the ndarray is in the RGB format"
+  [input]
+  (util/validate! ::ndarray input "Invalid input array")
+  (let [shape (ndarray/shape-vec input)]
+    (and
+     (= 3 (count shape))
+     (= 3 (shape 2)))))
+
+(s/def ::all-bytes #(= dtype/UINT8 (ndarray/dtype %)))
+(s/def ::rgb-array rgb-array?)
+(s/def ::to-image-ndarray
+  (s/and ::ndarray ::all-bytes ::rgb-array))
+
+(defn to-image
+  "Convert a NDArray image in RGB format to a real image"
+  [input]
+  (util/validate! ::to-image-ndarray input "Invalid input array")
+  (Image/toImage input))
diff --git a/contrib/clojure-package/test/org/apache/clojure_mxnet/image_test.clj b/contrib/clojure-package/test/org/apache/clojure_mxnet/image_test.clj
new file mode 100644
index 0000000..38ab11c
--- /dev/null
+++ b/contrib/clojure-package/test/org/apache/clojure_mxnet/image_test.clj
@@ -0,0 +1,79 @@
+;;
+;; Licensed to the Apache Software Foundation (ASF) under one or more
+;; contributor license agreements.  See the NOTICE file distributed with
+;; this work for additional information regarding copyright ownership.
+;; The ASF licenses this file to You under the Apache License, Version 2.0
+;; (the "License"); you may not use this file except in compliance with
+;; the License.  You may obtain a copy of the License at
+;;
+;;    http://www.apache.org/licenses/LICENSE-2.0
+;;
+;; Unless required by applicable law or agreed to in writing, software
+;; distributed under the License is distributed on an "AS IS" BASIS,
+;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;; See the License for the specific language governing permissions and
+;; limitations under the License.
+;;
+
+(ns org.apache.clojure-mxnet.image-test
+  (:require [org.apache.clojure-mxnet.image :as image]
+            [org.apache.clojure-mxnet.ndarray :as ndarray]
+            [clojure.java.io :as io]
+            [clojure.test :refer :all])
+  (:import (javax.imageio ImageIO)))
+
+(def tmp-dir (System/getProperty "java.io.tmpdir"))
+(def image-path (.getAbsolutePath (io/file tmp-dir "Pug-Cookie.jpg")))
+
+(defn download-image []
+  (with-open [in (io/input-stream "https://s3.amazonaws.com/model-server/inputs/Pug-Cookie.jpg")
+              out (io/output-stream (io/file image-path))]
+    (io/copy in out)))
+
+(defn delete-image []
+  (io/delete-file image-path))
+
+(defn with-downloaded-image [f]
+  (download-image)
+  (f)
+  (delete-image))
+
+(use-fixtures :once with-downloaded-image)
+
+(deftest test-decode-image
+  (let [img-arr (image/decode-image 
+                 (io/input-stream image-path))
+        img-arr-2 (image/decode-image 
+                   (io/input-stream image-path)
+                   {:color-flag image/GRAYSCALE})]
+    (is (= [576 1024 3] (ndarray/shape-vec img-arr)))
+    (is (= [576 1024 1] (ndarray/shape-vec img-arr-2)))))
+
+(deftest test-read-image
+  (let [img-arr (image/read-image image-path)
+        img-arr-2 (image/read-image
+                   image-path
+                   {:color-flag image/GRAYSCALE})]
+    (is (= [576 1024 3] (ndarray/shape-vec img-arr)))
+    (is (= [576 1024 1] (ndarray/shape-vec img-arr-2)))))
+
+(deftest test-resize-image
+  (let [img-arr (image/read-image image-path)
+        resized-arr (image/resize-image img-arr 224 224)]
+    (is (= [224 224 3] (ndarray/shape-vec resized-arr)))))
+
+(deftest test-crop-image
+  (let [img-arr (image/read-image image-path)
+        cropped-arr (image/fixed-crop img-arr 0 0 224 224)]
+    (is (= [224 224 3] (ndarray/shape-vec cropped-arr)))))
+
+(deftest test-apply-border
+  (let [img-arr (image/read-image image-path)
+        padded-arr (image/apply-border img-arr 1 1 1 1)]
+    (is (= [578 1026 3] (ndarray/shape-vec padded-arr)))))
+
+(deftest test-to-image
+  (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"))))))