rlm@356
|
1 #+title: Fun with Gabor Filters
|
rlm@356
|
2 #+author: Robert McIntyre
|
rlm@356
|
3 #+email: rlm@mit.edu
|
rlm@356
|
4 #+description: gabor filters in clojure with opencv
|
rlm@356
|
5 #+keywords: computer vision, jMonkeyEngine3, clojure, opencv
|
rlm@356
|
6 #+SETUPFILE: ../../aurellem/org/setup.org
|
rlm@356
|
7 #+INCLUDE: ../../aurellem/org/level-0.org
|
rlm@356
|
8 #+babel: :mkdirp yes :noweb yes :exports both
|
rlm@356
|
9
|
rlm@356
|
10
|
rlm@356
|
11
|
rlm@356
|
12 #+name: gabor
|
rlm@356
|
13 #+begin_src clojure
|
rlm@357
|
14 (ns cortex.gabor
|
rlm@357
|
15 (:import org.opencv.core.CvType)
|
rlm@357
|
16 (:import java.awt.image.BufferedImage)
|
rlm@357
|
17 (:import ij.ImagePlus)
|
rlm@358
|
18 (:import org.opencv.core.Mat)
|
rlm@363
|
19 (:use (cortex world sense util vision))
|
rlm@363
|
20 (:import com.jme3.post.SceneProcessor)
|
rlm@363
|
21 (:import (com.jme3.util BufferUtils Screenshots))
|
rlm@363
|
22 (:import java.nio.ByteBuffer)
|
rlm@363
|
23 (:import java.awt.image.BufferedImage)
|
rlm@363
|
24 (:import (com.jme3.renderer ViewPort Camera))
|
rlm@363
|
25 (:import (com.jme3.math ColorRGBA Vector3f Matrix3f Vector2f))
|
rlm@363
|
26 (:import com.jme3.renderer.Renderer)
|
rlm@363
|
27 (:import com.jme3.app.Application)
|
rlm@363
|
28 (:import com.jme3.texture.FrameBuffer)
|
rlm@363
|
29 (:import (com.jme3.scene Node Spatial)))
|
rlm@363
|
30
|
rlm@363
|
31
|
rlm@363
|
32 (cortex.import/mega-import-jme3)
|
rlm@356
|
33
|
rlm@356
|
34 (defn load-opencv
|
rlm@356
|
35 "Load the opencv native library. Must be called before any OpenCV
|
rlm@356
|
36 stuff is used."
|
rlm@356
|
37 []
|
rlm@356
|
38 (clojure.lang.RT/loadLibrary "opencv_java249"))
|
rlm@356
|
39
|
rlm@359
|
40 (defn gabor-kernel [sigma aspect-ratio theta wavelength phase-offset]
|
rlm@359
|
41
|
rlm@359
|
42 ;; first, find the size of the kernel which is required
|
rlm@359
|
43 (let [square #(expt % 2)
|
rlm@359
|
44 rotated (fn [[x y]]
|
rlm@359
|
45 [(+ (* x (Math/cos theta)) (* y (Math/sin theta)))
|
rlm@359
|
46 (- (* y (Math/cos theta)) (* x (Math/sin theta)))])
|
rlm@359
|
47
|
rlm@359
|
48 gaussian (fn [[x y]]
|
rlm@359
|
49 (let [[x' y'] (rotated [x y])]
|
rlm@359
|
50 (Math/exp (- (/ (+ (square x')
|
rlm@359
|
51 (square (* aspect-ratio y')))
|
rlm@359
|
52 (* 2 (square sigma)))))))
|
rlm@359
|
53 sinusoid (fn [[x y]]
|
rlm@359
|
54 (let [[x' y'] (rotated [x y])]
|
rlm@359
|
55 (Math/cos
|
rlm@359
|
56 (+ (* 2 Math/PI (/ x' wavelength))
|
rlm@359
|
57 phase-offset))))
|
rlm@359
|
58
|
rlm@361
|
59 half-width
|
rlm@361
|
60 (let [std-dev-capture 5]
|
rlm@361
|
61 (max
|
rlm@361
|
62 (int (* std-dev-capture (/ sigma aspect-ratio)))
|
rlm@361
|
63 (int (* std-dev-capture sigma))
|
rlm@361
|
64 (int (* std-dev-capture (/ aspect-ratio sigma)))))
|
rlm@359
|
65
|
rlm@359
|
66 grid (let [axis (range (- half-width) (inc half-width))]
|
rlm@359
|
67 (for [y (reverse axis) x axis] (vector x y)))
|
rlm@359
|
68
|
rlm@359
|
69 scale (reduce + (map gaussian grid))
|
rlm@359
|
70
|
rlm@359
|
71 gabor (fn [[x y :as coord]]
|
rlm@360
|
72 (* (sinusoid coord) (gaussian coord) (/ scale)))
|
rlm@359
|
73
|
rlm@359
|
74 mat-width (+ 1 (* 2 half-width))
|
rlm@359
|
75 mat (Mat. mat-width mat-width CvType/CV_32F)]
|
rlm@359
|
76
|
rlm@359
|
77 (.put mat 0 0 (float-array (map gabor grid)))
|
rlm@361
|
78 mat))
|
rlm@359
|
79
|
rlm@359
|
80
|
rlm@361
|
81 (defn draw-kernel! [kernel img-path]
|
rlm@361
|
82 (let [output img-path
|
rlm@360
|
83 size (.size kernel)
|
rlm@360
|
84 width (int (.width size))
|
rlm@360
|
85 height (int (.height size))
|
rlm@360
|
86 tmp-array (float-array (* width height))]
|
rlm@360
|
87
|
rlm@360
|
88 ;; read values from matrix.
|
rlm@360
|
89 (.get kernel 0 0 tmp-array)
|
rlm@360
|
90
|
rlm@360
|
91 ;; find overall dynamic range of the filter
|
rlm@360
|
92 (let [vals (vec tmp-array)
|
rlm@360
|
93 low (apply min vals)
|
rlm@360
|
94 high (apply max vals)
|
rlm@360
|
95 scaled-vals (map #(* 255 (- % low) (/ (- high low))) vals)
|
rlm@360
|
96 new-mat (Mat. height width CvType/CV_32F)]
|
rlm@360
|
97 (.put new-mat 0 0 (float-array scaled-vals))
|
rlm@361
|
98 (org.opencv.highgui.Highgui/imwrite output new-mat))))
|
rlm@361
|
99
|
rlm@361
|
100 (defn show-kernel [kernel]
|
rlm@361
|
101 (let [img-path "/home/r/proj/cortex/tmp/kernel.png"]
|
rlm@362
|
102 (draw-kernel! kernel img-path)
|
rlm@361
|
103 (view (ImagePlus. output))))
|
rlm@359
|
104
|
rlm@359
|
105 (defn print-kernel [kernel]
|
rlm@359
|
106 (println (.dump kernel)))
|
rlm@359
|
107
|
rlm@363
|
108
|
rlm@363
|
109 (def brick-length 0.48)
|
rlm@363
|
110 (def brick-width 0.24)
|
rlm@363
|
111 (def brick-height 0.12)
|
rlm@363
|
112 (def gravity (Vector3f. 0 -9.81 0))
|
rlm@363
|
113
|
rlm@363
|
114
|
rlm@363
|
115 (defn brick* [position]
|
rlm@363
|
116 (println "get brick.")
|
rlm@363
|
117 (doto (box brick-length brick-height brick-width
|
rlm@363
|
118 :position position :name "brick"
|
rlm@363
|
119 :material "Common/MatDefs/Misc/Unshaded.j3md"
|
rlm@363
|
120 :texture "Textures/Terrain/BrickWall/BrickWall.jpg"
|
rlm@363
|
121 :mass 34)
|
rlm@363
|
122 (->
|
rlm@363
|
123 (.getMesh)
|
rlm@363
|
124 (.scaleTextureCoordinates (Vector2f. 1 0.5)))
|
rlm@363
|
125 (.setShadowMode RenderQueue$ShadowMode/CastAndReceive)
|
rlm@363
|
126 )
|
rlm@363
|
127 )
|
rlm@363
|
128
|
rlm@363
|
129
|
rlm@363
|
130 (defn floor*
|
rlm@363
|
131 "make a sturdy, unmovable physical floor"
|
rlm@363
|
132 []
|
rlm@363
|
133 (box 10 0.1 5 :name "floor" :mass 0 :color ColorRGBA/Gray :position (Vector3f. 0 0 0)))
|
rlm@363
|
134
|
rlm@363
|
135 (defn floor* []
|
rlm@363
|
136 (doto (box 10 0.1 5 :name "floor" ;10 0.1 5 ; 240 0.1 240
|
rlm@363
|
137 :material "Common/MatDefs/Misc/Unshaded.j3md"
|
rlm@363
|
138 :texture "Textures/BronzeCopper030.jpg"
|
rlm@363
|
139 :position (Vector3f. 0 0 0 )
|
rlm@363
|
140 :mass 0)
|
rlm@363
|
141 (->
|
rlm@363
|
142 (.getMesh)
|
rlm@363
|
143 (.scaleTextureCoordinates (Vector2f. 3 6)));64 64
|
rlm@363
|
144 (->
|
rlm@363
|
145 (.getMaterial)
|
rlm@363
|
146 (.getTextureParam "ColorMap")
|
rlm@363
|
147 (.getTextureValue)
|
rlm@363
|
148 (.setWrap Texture$WrapMode/Repeat))
|
rlm@363
|
149 (.setShadowMode RenderQueue$ShadowMode/Receive)
|
rlm@363
|
150 ))
|
rlm@363
|
151
|
rlm@363
|
152
|
rlm@363
|
153 (defn brick-wall* []
|
rlm@363
|
154 (let [node (Node. "brick-wall")]
|
rlm@363
|
155 (dorun
|
rlm@363
|
156 (map
|
rlm@363
|
157 (comp #(.attachChild node %) brick*)
|
rlm@363
|
158 (for [y (range 10)
|
rlm@363
|
159 x (range 4)
|
rlm@363
|
160 z (range 1)]
|
rlm@363
|
161 (Vector3f.
|
rlm@363
|
162 (+ (* 2 x brick-length)
|
rlm@363
|
163 (if (even? (+ y z))
|
rlm@363
|
164 (/ brick-length 4) (/ brick-length -4)))
|
rlm@363
|
165 (+ (* brick-height (inc (* 2 y))))
|
rlm@363
|
166 (* 2 z brick-width) ))))
|
rlm@363
|
167 (.setShadowMode node RenderQueue$ShadowMode/CastAndReceive)
|
rlm@363
|
168 node))
|
rlm@363
|
169
|
rlm@363
|
170 (import com.aurellem.capture.Capture)
|
rlm@363
|
171
|
rlm@363
|
172 (import java.io.File)
|
rlm@363
|
173
|
rlm@363
|
174
|
rlm@363
|
175 (defn brick-wall-game-run [record?]
|
rlm@363
|
176 (doto
|
rlm@363
|
177 (world
|
rlm@363
|
178 (doto (Node.) (.attachChild (floor*))
|
rlm@363
|
179 (.attachChild (brick-wall*))
|
rlm@363
|
180 )
|
rlm@363
|
181 {"key-f" (fn [game value]
|
rlm@363
|
182 (if (not value) (add-element game (brick-wall*))))
|
rlm@363
|
183 "key-space" (fire-cannon-ball )}
|
rlm@363
|
184 (fn [world]
|
rlm@363
|
185 (position-camera world
|
rlm@363
|
186 (Vector3f. 1.382548, 4.0383573, 5.994235)
|
rlm@363
|
187 (Quaternion. 0.0013082094, 0.98581666, -0.1676442, 0.0076932586))
|
rlm@363
|
188
|
rlm@363
|
189 ;;(speed-up world)
|
rlm@363
|
190
|
rlm@363
|
191 (if record?
|
rlm@363
|
192 (Capture/captureVideo
|
rlm@363
|
193 world
|
rlm@363
|
194 (File.
|
rlm@363
|
195 "/home/r/proj/cortex/render/gabor-1/main")))
|
rlm@363
|
196 (add-camera! world (.getCamera world) no-op))
|
rlm@363
|
197 (fn [& _]))
|
rlm@363
|
198 (.start)))
|
rlm@363
|
199
|
rlm@363
|
200 (defn convolve-practice [kernel]
|
rlm@363
|
201 (let [input "/home/r/proj/cortex/render/gabor-1/main/0000032.png"
|
rlm@357
|
202
|
rlm@357
|
203
|
rlm@357
|
204 output "/home/r/ppp.png"
|
rlm@356
|
205
|
rlm@357
|
206 i (org.opencv.highgui.Highgui/imread input)
|
rlm@358
|
207
|
rlm@360
|
208 kernel (gabor-kernel 10 1 (/ Math/PI 2) 10 0)
|
rlm@358
|
209
|
rlm@358
|
210 new-mat (Mat.)
|
rlm@358
|
211
|
rlm@357
|
212 ]
|
rlm@356
|
213
|
rlm@360
|
214 (org.opencv.imgproc.Imgproc/filter2D i new-mat CvType/CV_32F kernel)
|
rlm@358
|
215
|
rlm@358
|
216 (org.opencv.highgui.Highgui/imwrite "/home/r/ppp.png" new-mat)
|
rlm@358
|
217
|
rlm@357
|
218 (view (ImagePlus. input))
|
rlm@361
|
219 (view (ImagePlus. output))))
|
rlm@357
|
220
|
rlm@363
|
221
|
rlm@363
|
222
|
rlm@363
|
223 (defn generate-gabor-images []
|
rlm@363
|
224 (gabor-kernel 2.8 1 0 3.5 0)
|
rlm@363
|
225
|
rlm@363
|
226
|
rlm@363
|
227
|
rlm@363
|
228
|
rlm@356
|
229 #+end_src
|
rlm@356
|
230
|
rlm@356
|
231
|
rlm@356
|
232
|
rlm@356
|
233 * COMMENT Generate Source
|
rlm@356
|
234 #+begin_src clojure :tangle ../src/cortex/gabor.clj
|
rlm@356
|
235 <<gabor>>
|
rlm@356
|
236 #+end_src
|