rlm@356: #+title: Fun with Gabor Filters rlm@356: #+author: Robert McIntyre rlm@356: #+email: rlm@mit.edu rlm@356: #+description: gabor filters in clojure with opencv rlm@356: #+keywords: computer vision, jMonkeyEngine3, clojure, opencv rlm@356: #+SETUPFILE: ../../aurellem/org/setup.org rlm@356: #+INCLUDE: ../../aurellem/org/level-0.org rlm@356: #+babel: :mkdirp yes :noweb yes :exports both rlm@356: rlm@356: rlm@356: rlm@356: #+name: gabor rlm@356: #+begin_src clojure rlm@357: (ns cortex.gabor rlm@357: (:import org.opencv.core.CvType) rlm@357: (:import java.awt.image.BufferedImage) rlm@357: (:import ij.ImagePlus) rlm@358: (:import org.opencv.core.Mat) rlm@363: (:use (cortex world sense util vision)) rlm@363: (:import com.jme3.post.SceneProcessor) rlm@363: (:import (com.jme3.util BufferUtils Screenshots)) rlm@363: (:import java.nio.ByteBuffer) rlm@363: (:import java.awt.image.BufferedImage) rlm@363: (:import (com.jme3.renderer ViewPort Camera)) rlm@363: (:import (com.jme3.math ColorRGBA Vector3f Matrix3f Vector2f)) rlm@363: (:import com.jme3.renderer.Renderer) rlm@363: (:import com.jme3.app.Application) rlm@363: (:import com.jme3.texture.FrameBuffer) rlm@363: (:import (com.jme3.scene Node Spatial))) rlm@363: rlm@363: rlm@363: (cortex.import/mega-import-jme3) rlm@356: rlm@356: (defn load-opencv rlm@356: "Load the opencv native library. Must be called before any OpenCV rlm@356: stuff is used." rlm@356: [] rlm@356: (clojure.lang.RT/loadLibrary "opencv_java249")) rlm@356: rlm@359: (defn gabor-kernel [sigma aspect-ratio theta wavelength phase-offset] rlm@359: rlm@359: ;; first, find the size of the kernel which is required rlm@359: (let [square #(expt % 2) rlm@359: rotated (fn [[x y]] rlm@359: [(+ (* x (Math/cos theta)) (* y (Math/sin theta))) rlm@359: (- (* y (Math/cos theta)) (* x (Math/sin theta)))]) rlm@359: rlm@359: gaussian (fn [[x y]] rlm@359: (let [[x' y'] (rotated [x y])] rlm@359: (Math/exp (- (/ (+ (square x') rlm@359: (square (* aspect-ratio y'))) rlm@359: (* 2 (square sigma))))))) rlm@359: sinusoid (fn [[x y]] rlm@359: (let [[x' y'] (rotated [x y])] rlm@359: (Math/cos rlm@359: (+ (* 2 Math/PI (/ x' wavelength)) rlm@359: phase-offset)))) rlm@359: rlm@361: half-width rlm@361: (let [std-dev-capture 5] rlm@361: (max rlm@361: (int (* std-dev-capture (/ sigma aspect-ratio))) rlm@361: (int (* std-dev-capture sigma)) rlm@361: (int (* std-dev-capture (/ aspect-ratio sigma))))) rlm@359: rlm@359: grid (let [axis (range (- half-width) (inc half-width))] rlm@359: (for [y (reverse axis) x axis] (vector x y))) rlm@359: rlm@359: scale (reduce + (map gaussian grid)) rlm@359: rlm@359: gabor (fn [[x y :as coord]] rlm@360: (* (sinusoid coord) (gaussian coord) (/ scale))) rlm@359: rlm@359: mat-width (+ 1 (* 2 half-width)) rlm@359: mat (Mat. mat-width mat-width CvType/CV_32F)] rlm@359: rlm@359: (.put mat 0 0 (float-array (map gabor grid))) rlm@361: mat)) rlm@359: rlm@359: rlm@361: (defn draw-kernel! [kernel img-path] rlm@361: (let [output img-path rlm@360: size (.size kernel) rlm@360: width (int (.width size)) rlm@360: height (int (.height size)) rlm@360: tmp-array (float-array (* width height))] rlm@360: rlm@360: ;; read values from matrix. rlm@360: (.get kernel 0 0 tmp-array) rlm@360: rlm@360: ;; find overall dynamic range of the filter rlm@360: (let [vals (vec tmp-array) rlm@360: low (apply min vals) rlm@360: high (apply max vals) rlm@360: scaled-vals (map #(* 255 (- % low) (/ (- high low))) vals) rlm@360: new-mat (Mat. height width CvType/CV_32F)] rlm@360: (.put new-mat 0 0 (float-array scaled-vals)) rlm@361: (org.opencv.highgui.Highgui/imwrite output new-mat)))) rlm@361: rlm@361: (defn show-kernel [kernel] rlm@361: (let [img-path "/home/r/proj/cortex/tmp/kernel.png"] rlm@362: (draw-kernel! kernel img-path) rlm@361: (view (ImagePlus. output)))) rlm@359: rlm@359: (defn print-kernel [kernel] rlm@359: (println (.dump kernel))) rlm@359: rlm@363: rlm@363: (def brick-length 0.48) rlm@363: (def brick-width 0.24) rlm@363: (def brick-height 0.12) rlm@363: (def gravity (Vector3f. 0 -9.81 0)) rlm@363: rlm@363: rlm@363: (defn brick* [position] rlm@363: (println "get brick.") rlm@363: (doto (box brick-length brick-height brick-width rlm@363: :position position :name "brick" rlm@363: :material "Common/MatDefs/Misc/Unshaded.j3md" rlm@363: :texture "Textures/Terrain/BrickWall/BrickWall.jpg" rlm@363: :mass 34) rlm@363: (-> rlm@363: (.getMesh) rlm@363: (.scaleTextureCoordinates (Vector2f. 1 0.5))) rlm@363: (.setShadowMode RenderQueue$ShadowMode/CastAndReceive) rlm@363: ) rlm@363: ) rlm@363: rlm@363: rlm@363: (defn floor* rlm@363: "make a sturdy, unmovable physical floor" rlm@363: [] rlm@363: (box 10 0.1 5 :name "floor" :mass 0 :color ColorRGBA/Gray :position (Vector3f. 0 0 0))) rlm@363: rlm@363: (defn floor* [] rlm@363: (doto (box 10 0.1 5 :name "floor" ;10 0.1 5 ; 240 0.1 240 rlm@363: :material "Common/MatDefs/Misc/Unshaded.j3md" rlm@363: :texture "Textures/BronzeCopper030.jpg" rlm@363: :position (Vector3f. 0 0 0 ) rlm@363: :mass 0) rlm@363: (-> rlm@363: (.getMesh) rlm@363: (.scaleTextureCoordinates (Vector2f. 3 6)));64 64 rlm@363: (-> rlm@363: (.getMaterial) rlm@363: (.getTextureParam "ColorMap") rlm@363: (.getTextureValue) rlm@363: (.setWrap Texture$WrapMode/Repeat)) rlm@363: (.setShadowMode RenderQueue$ShadowMode/Receive) rlm@363: )) rlm@363: rlm@363: rlm@363: (defn brick-wall* [] rlm@363: (let [node (Node. "brick-wall")] rlm@363: (dorun rlm@363: (map rlm@363: (comp #(.attachChild node %) brick*) rlm@363: (for [y (range 10) rlm@363: x (range 4) rlm@363: z (range 1)] rlm@363: (Vector3f. rlm@363: (+ (* 2 x brick-length) rlm@363: (if (even? (+ y z)) rlm@363: (/ brick-length 4) (/ brick-length -4))) rlm@363: (+ (* brick-height (inc (* 2 y)))) rlm@363: (* 2 z brick-width) )))) rlm@363: (.setShadowMode node RenderQueue$ShadowMode/CastAndReceive) rlm@363: node)) rlm@363: rlm@363: (import com.aurellem.capture.Capture) rlm@363: rlm@363: (import java.io.File) rlm@363: rlm@363: rlm@363: (defn brick-wall-game-run [record?] rlm@363: (doto rlm@363: (world rlm@363: (doto (Node.) (.attachChild (floor*)) rlm@363: (.attachChild (brick-wall*)) rlm@363: ) rlm@363: {"key-f" (fn [game value] rlm@363: (if (not value) (add-element game (brick-wall*)))) rlm@363: "key-space" (fire-cannon-ball )} rlm@363: (fn [world] rlm@363: (position-camera world rlm@363: (Vector3f. 1.382548, 4.0383573, 5.994235) rlm@363: (Quaternion. 0.0013082094, 0.98581666, -0.1676442, 0.0076932586)) rlm@363: rlm@363: ;;(speed-up world) rlm@363: rlm@363: (if record? rlm@363: (Capture/captureVideo rlm@363: world rlm@363: (File. rlm@363: "/home/r/proj/cortex/render/gabor-1/main"))) rlm@363: (add-camera! world (.getCamera world) no-op)) rlm@363: (fn [& _])) rlm@363: (.start))) rlm@363: rlm@363: (defn convolve-practice [kernel] rlm@363: (let [input "/home/r/proj/cortex/render/gabor-1/main/0000032.png" rlm@357: rlm@357: rlm@357: output "/home/r/ppp.png" rlm@356: rlm@357: i (org.opencv.highgui.Highgui/imread input) rlm@358: rlm@360: kernel (gabor-kernel 10 1 (/ Math/PI 2) 10 0) rlm@358: rlm@358: new-mat (Mat.) rlm@358: rlm@357: ] rlm@356: rlm@360: (org.opencv.imgproc.Imgproc/filter2D i new-mat CvType/CV_32F kernel) rlm@358: rlm@358: (org.opencv.highgui.Highgui/imwrite "/home/r/ppp.png" new-mat) rlm@358: rlm@357: (view (ImagePlus. input)) rlm@361: (view (ImagePlus. output)))) rlm@357: rlm@363: rlm@363: rlm@363: (defn generate-gabor-images [] rlm@363: (gabor-kernel 2.8 1 0 3.5 0) rlm@363: rlm@363: rlm@363: rlm@363: rlm@356: #+end_src rlm@356: rlm@356: rlm@356: rlm@356: * COMMENT Generate Source rlm@356: #+begin_src clojure :tangle ../src/cortex/gabor.clj rlm@356: <> rlm@356: #+end_src