Advertisement
Guest User

Clojure Sobel Edge Detection, Optimized

a guest
Jul 23rd, 2010
479
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lisp 4.55 KB | None | 0 0
  1. (ns sobel.core)
  2.  
  3. (import
  4.  '(java.awt Robot GraphicsEnvironment GraphicsDevice Rectangle Dimension)
  5.  '(java.awt.image BufferedImage MemoryImageSource)
  6.  '(javax.swing JPanel JFrame))
  7.  
  8. (in-ns 'sobel.core)
  9.  
  10. (def robot (new Robot))
  11.  
  12. (def screen
  13.      (.getDefaultScreenDevice
  14.       (GraphicsEnvironment/getLocalGraphicsEnvironment)))
  15.  
  16. (defn grab-image
  17.   "grab a snapshot of the desktop"
  18.   []
  19.   (let [dm (.getDisplayMode screen)]
  20.     (.createScreenCapture robot
  21.        (new Rectangle
  22.         (.getWidth dm)
  23.         (.getHeight dm)))))
  24.  
  25. (defn panel-to-frame
  26.   "display the supplied JPanel in a JFrame"
  27.   [panel]
  28.   (doto (new JFrame)
  29.     (.add panel)
  30.     (.pack)
  31.     ;(.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
  32.     (.show)))
  33.  
  34. (defn image-to-frame
  35.   "create a JFrame with the given image in it"
  36.   [image]
  37.   (let [panel
  38.     (doto (proxy [JPanel] []
  39.         (paintComponent [g]
  40.                (.drawImage g image 0 0 nil)))
  41.       (.setPreferredSize
  42.        (new Dimension
  43.         (.getWidth image)
  44.         (.getHeight image))))]
  45.     (panel-to-frame panel)))
  46.  
  47. (defn luminance
  48.   "Approximate luminance of an rgb triple"
  49.   [r g b]
  50.   (bit-shift-right
  51.    (+ (+ (+ (+ (+ (+ (+ r r) r) b) g) g) g) g)
  52.    3))
  53.  
  54.  
  55. (defmacro luminance-inline
  56.   [r g b]
  57.   `(let [r# ~r g# ~g b# ~b]
  58.      (bit-shift-right
  59.       (+ (+ (+ (+ (+ (+ (+ r# r#) r#) b#) g#) g#) g#) g#)
  60.       (int 3))))
  61.  
  62. (defn luminance-to-greyscale
  63.   "convert a lumience level to a greyscale rgb"
  64.   [level]
  65.   (+
  66.    (bit-shift-left level 16)
  67.    (bit-shift-left level 8)
  68.    level))
  69.  
  70. (defmacro luminance-to-greyscale-inline
  71.   [level]
  72.   `(let [level# ~level]
  73.      (+
  74.       (bit-shift-left level# (int 16))
  75.       (bit-shift-left level# (int 8))
  76.       level#)))
  77.  
  78. (defn rgb-to-luminance [rgb]
  79.   (let [r (bit-shift-right (bit-and 0xff0000 rgb) 16)
  80.     g (bit-shift-right (bit-and 0xff00 rgb) 8)
  81.     b (bit-and 0xff rgb)]
  82.     (luminance r g b)))
  83.  
  84. (defmacro rgb-to-luminance-inline [rgb]
  85.   `(let [rgb# ~rgb
  86.      r# (bit-shift-right (bit-and (int 0xff0000) rgb#) 16)
  87.      g# (bit-shift-right (bit-and (int 0xff00) rgb#) 8)
  88.      b# (bit-and (int 0xff) rgb#)]
  89.      (luminance-inline r# g# b#)))
  90.  
  91. (defn rgb-to-greyscale
  92.   "convert an rgb value to a greyscale value"
  93.   [rgb]
  94.   (luminance-to-greyscale (rgb-to-luminance rgb))
  95. )
  96.  
  97. (defn clone-image
  98.   "clone a BufferedImage"
  99.   [image]
  100.   (new BufferedImage
  101.        (.getColorModel image)
  102.        (.copyData image nil)
  103.        (.isAlphaPremultiplied image)
  104.        nil))
  105.  
  106. (defn image-to-greyscale
  107.   "convert an image to greyscale"
  108.   [#^BufferedImage image]
  109.   (let [ #^BufferedImage ret (clone-image image)
  110.     width ( int (.getWidth image))
  111.     height ( int (.getHeight image))]
  112.     (doseq [x (range width) y (range height)]
  113.       (.setRGB ret x y
  114.            (rgb-to-greyscale (.getRGB image x y))))
  115.     ret))
  116.  
  117. (def sobel-convolution-matrix-x (int-array [-1 0 1 -2 0 2 -1 0 1]))
  118.  
  119. (def sobel-convolution-matrix-y (int-array [1 2 1 0 0 0 -1 -2 -1]))
  120.  
  121. (defmacro coords-to-offset [x y]
  122.   `(+ (* (int 3) ~x) ~y))
  123.  
  124. ;; evaluates arg more than once
  125. (defmacro unsafe-abs [x]
  126.   `(if (< ~x 0)
  127.      (- ~x)
  128.      ~x))
  129. ;; Assumes input image returns 24bit rgb from .getRGB
  130. ;; Essentially iterates through all the pixels
  131. ;; coverts pixel to greyscale level
  132. ;; does sobel convolution on the greyscale level
  133. ;; converts the resultant level back to greyscale and puts in in an output image
  134. (defn sobel-edge-detection
  135.   "creates an edge detected image from an input image using Sobel edge detection"
  136.   [#^BufferedImage image]
  137.   (let [width (.getWidth image)
  138.     height (.getHeight image)
  139.     convolution-x (int-array [-1 0 1 -2 0 2 -1 0 1])
  140.     convolution-y (int-array [1 2 1 0 0 0 -1 -2 -1])
  141.     #^BufferedImage ret (clone-image image)]
  142.     (doseq [x (range width) y (range height)]
  143.       (.setRGB
  144.        ret x y
  145.        (luminance-to-greyscale
  146.     (if (or (= x 0) (= y 0) (= x (dec width)) (= y (dec height)))
  147.       255
  148.       (loop [i (int  -1) j (int -1) sumX (int 0) sumY (int 0)]
  149.         (if (= i 2)
  150.           (let [level  (+ (unsafe-abs sumX) (unsafe-abs sumY))
  151.             trunc (cond (< level 0) 0
  152.                 (> level 255) 255
  153.                 :else level)]
  154.         (- 255 trunc))
  155.           (if (= j 2)
  156.         (recur (inc i) (int -1) sumX sumY)
  157.         (let [luminance (rgb-to-luminance-inline (.getRGB image (+ x i) (+ y j)))
  158.               offset (coords-to-offset (inc i) (inc j))]
  159.           (recur
  160.            i
  161.            (inc j)
  162.            (+ sumX (* luminance (aget convolution-x offset)))
  163.            (+ sumY (* luminance (aget convolution-y offset))))))))))))
  164.     ret))
  165.  
  166. (defn sobel-test [] (image-to-frame ( sobel-edge-detection (grab-image))))
  167.  
  168. (use '[clojure.contrib.repl-utils :only [expression-info]])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement