Permalink
Browse files

Added changes to convolution.

  • Loading branch information...
1 parent 4584279 commit d5b7203d18167cf3c2a154a562bacf4cc7e09508 @Serabe committed Oct 27, 2010
@@ -13,17 +13,17 @@
"Convolves img using the given kernel and the convolve-op. If there is no convolve-op, zero-fill-op is used.
If kernel is not valid (see check-kernel), nil is returned."
[img kern & opt]
- (if (check-kernel kern)
+ (if (valid? kern)
(let [conv-op (if (map? (first opt))
zero-fill-op
(first opt))
rh (apply create-rendering-hint
(if (map? (first opt))
- (rest opt)
- opt))
+ opt
+ (rest opt)))
[ix iy] (orig-img-starting-pixel kern)
ni (conv-op img kern)
- res-bi (.filter (ConvolveOp. (to-java-kernel kern)
+ res-bi (.filter (ConvolveOp. (to-java kern)
ConvolveOp/EDGE_NO_OP
rh)
(:image ni) nil)]
@@ -1,39 +1,109 @@
-(ns rinzelight.effects.convolve.kernel
- (:import (java.awt.image Kernel)))
+(ns rinzelight.effects.convolve.kernel)
+(defprotocol ConvolutionKernel
+ "Encapsulates both rinzelight kernel struct and java.awt.image.Kernel"
+ (to-java [this]
+ "Given a kernel, returns a java.awt.image.Kernel")
+ (valid? [this])
+ (^floats kernel [this]
+ "Returns an array of floats representing the data")
+ (width [this]
+ "Returns the width of the kernel")
+ (height [this]
+ "Returns the height of the kernel")
-(defstruct kernel :kernel :width :height)
+ (x-orig [this]
+ "Returns the X origin in the kernel")
-(defn to-java-kernel
- "Retrieves the java representation of the kernel."
- [kern]
- (Kernel. (:width kern)
- (:height kern)
- (into-array Float/TYPE (:kernel kern))))
+ (y-orig [this]
+ "Return the Y origin in the kernel")
+
+ (change-kernel [this new-kern]
+ "Return a new kernel with new-kern data in. It doesn't check if it is valid or not."))
-(defmacro check-kernel
- "Checks that both width and height are odd numbers."
- [kern]
- (let [checker (fn [w h arr-s]
- (and (odd? w) ; width must be odd
- (odd? h) ; height must be odd
- (= (* w h)
- (alength arr-s))))] ; array size must be equal to w*h
- `(if (isa? (class ~kern) java.awt.image.Kernel)
- (~checker (.getWidth ~kern)
- (.getHeight ~kern)
- (.getKernelData ~kern nil))
- (~checker (:width ~kern)
- (:height ~kern)
- (:kernel ~kern)))))
+(extend-protocol ConvolutionKernel
+ java.awt.image.Kernel
+ (to-java [this]
+ this)
+
+ (valid? [this]
+ (and (odd? (.getWidth this))
+ (odd? (.getHeight this))))
+
+ (kernel [this] (.getKernelData this nil))
+
+ (width [this] (.getWidth this))
+
+ (height [this] (.getHeight this))
+
+ (x-orig [this] (.getXOrigin this))
+
+ (y-orig [this] (.getYOrigin this))
+
+ (change-kernel [this new-kern]
+ (java.awt.image.Kernel. (.getWidth this)
+ (.getHeight this)
+ new-kern)))
+
+
+(defmacro origin-element-for-length
+ "Returns the default origin given a length"
+ [length]
+ `(dec (if (odd? ~length)
+ (/ (inc ~length) 2)
+ (/ ~length 2))))
+
+(extend-protocol ConvolutionKernel
+ clojure.lang.IPersistentMap
+ (to-java [this]
+ (java.awt.image.Kernel. (:width this)
+ (:height this)
+ (:kernel this)))
+
+ (valid? [this]
+ (and (odd? (:width this))
+ (odd? (:height this))
+ (== (alength (:kernel this))
+ (* (:width this) (:height this)))))
+
+ (kernel [this] (:kernel this))
+
+ (width [this] (:width this))
+
+ (height [this] (:height this))
+
+ (x-orig [this] (origin-element-for-length (:width this)))
+
+ (y-orig [this] (origin-element-for-length (:height this)))
+
+ (change-kernel [this new-kern]
+ (assoc this :kernel new-kern)))
+
+(defstruct kernel-struct :kernel :width :height)
+
+(defn create-kernel
+ "Creates a new kernel. Please, don't use direct maps."
+ [width height coll]
+ (struct kernel-struct (into-array Float/TYPE coll)
+ width height))
+
+(defn- gamma
+ [^floats arr]
+ (let [pre-g (areduce arr idx res 0 (+ res (aget arr idx)))]
+ (if (== pre-g 0.0)
+ (float 1.0)
+ (float (/ 1.0 pre-g)))))
+
+(defn- ^floats mult-by-gamma
+ [^floats arr g]
+ (amap arr idx ret
+ (aset ret idx (* g (aget arr idx)))))
(defn normalize-kernel
"Normalizes a kernel. Normalizing a kernel is to divide each component by the sum of all of them."
[kern]
- (let [data (:kernel kern)
- gamma (/ 1.0 (areduce data idx res 0 (+ res (aget data idx))))]
- (if (== gamma 1.0)
+ (let [data (kernel kern)
+ g (gamma data)]
+ (if (== g 1.0)
kern
- (assoc kern :kernel
- (amap data idx ret
- (aset ret idx (* gamma (aget data idx))))))))
+ (change-kernel kern (mult-by-gamma data g)))))
@@ -8,13 +8,13 @@
(defn helper-image-size
"Retrieves the size of the auxiliar image."
[img kern]
- [(+ (:width img) (dec (:width kern)))
- (+ (:height img) (dec (:height kern)))])
+ [(+ (:width img) (dec (width kern)))
+ (+ (:height img) (dec (height kern)))])
(defn orig-img-starting-pixel
[kern]
- [(/ (inc (:width kern)) 2)
- (/ (inc (:height kern)) 2)])
+ [(/ (inc (width kern)) 2)
+ (/ (inc (height kern)) 2)])
(defmacro set-to-image
[img]
@@ -7,17 +7,42 @@
([w h]
(create-kernel-by-size w h (* w h)))
([w h size]
- (struct kernel (float-array size)
- w h)))
+ (create-kernel w h (float-array size))))
(def kernels [[(create-kernel-by-size 4 3) [false false]]
[(create-kernel-by-size 3 4) [false false]]
[(create-kernel-by-size 3 3 11) [false true]]
[(create-kernel-by-size 5 5) [true true]]])
-(deftest check-kernel-facts
+(def java-kernels (map #(to-java (first %)) kernels))
+
+(deftest valid-kernel-facts
(doseq [[kern [valid-r valid-j]] kernels]
(fact "Checked as a rinzelight struct, it should be valid (or not)"
- (check-kernel kern) => valid-r)
+ (valid? kern) => valid-r)
(fact "Checked as a java Kernel, it should be valid (or not)"
- (check-kernel (to-java-kernel kern)) => valid-j)))
+ (valid? (to-java kern)) => valid-j)))
+
+(deftest to-java-facts
+ (doseq [kern java-kernels]
+ (fact "Returns the very same object if called with a Kernel object"
+ (to-java kern) => kern))
+
+ (doseq [[kern _] kernels]
+ (let [jk (to-java kern)]
+ (fact "It keeps x-orig and y-orig"
+ (x-orig jk) => (x-orig kern)
+ (y-orig jk) => (y-orig kern)))))
+
+(deftest normalize-kernel-facts
+
+ (doseq [kern java-kernels]
+ (fact "Return the same kernel if gamma is zero."
+ (normalize-kernel kern) => kern))
+
+ (let [kern (to-java {:width 3
+ :height 3
+ :kernel (float-array 9 1.0)})
+ nk (normalize-kernel kern)]
+ (fact "Normalized kernel's gamma must be one"
+ (normalize-kernel nk) => nk)))

0 comments on commit d5b7203

Please sign in to comment.