diff src/clojureDemo/OpenCv.clj @ 1:6d9bdaf919f7

added clojureDemo source
author Robert McIntyre <rlm@mit.edu>
date Fri, 20 Aug 2010 00:32:44 -0400
parents
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/clojureDemo/OpenCv.clj	Fri Aug 20 00:32:44 2010 -0400
     1.3 @@ -0,0 +1,226 @@
     1.4 +(ns clojureDemo.OpenCv)
     1.5 +  
     1.6 +(import '(java.awt Rectangle Robot Toolkit) )
     1.7 +(import '(java.awt.image BufferedImage) )
     1.8 +(import '(java.awt Graphics2D Panel))
     1.9 +(import '(java.io File) )
    1.10 +(import '(javax.imageio ImageIO) )
    1.11 +(import '(javax.swing JFrame))
    1.12 +(import '(org.apache.commons.io FileUtils))
    1.13 +(import clojure.lang.LazySeq)
    1.14 +(import '(name.audet.samuel.javacv.jna highgui cv cxcore 
    1.15 +				       cxcore$IplImage highgui$CvCapture$PointerByReference  
    1.16 +				       highgui$CvVideoWriter$PointerByReference cxcore$IplImage$PointerByReference))
    1.17 +(import '(name.audet.samuel.javacv CanvasFrame JavaCvErrorCallback))
    1.18 +
    1.19 +(.redirectError (JavaCvErrorCallback.))
    1.20 +
    1.21 +(use 'clojure.contrib.repl-utils)
    1.22 +;(use 'clojureDemo.Defines)
    1.23 +;(use '[clojureDemo.Xuggle :only (cache)])
    1.24 +
    1.25 +;this is still a work in progress, I'll come back to it later when I understand 
    1.26 +;jna more thoroughly.  the important abstraction here is 
    1.27 +;video-seq, which gives a lazy sequence of Intel Image Processing library images.
    1.28 +
    1.29 +(defn naturals [] (iterate inc 0))
    1.30 +
    1.31 +(defn- makePanel [image] (proxy [Panel] [] (paint [g]  (.drawImage g image 0 0 nil))))
    1.32 +
    1.33 +
    1.34 +(defmulti  display "Creates a JFrame and displays a buffered image"  class)
    1.35 +
    1.36 +(defmethod display 
    1.37 +  BufferedImage  [image] 
    1.38 +  (let [panel (makePanel image)
    1.39 +	frame (JFrame. "Oh Yeah!")]
    1.40 +    (.add frame panel) 
    1.41 +    (.pack frame) 
    1.42 +    (.setVisible frame true ) 
    1.43 +    (.setSize frame(.getWidth image) (.getHeight image))))
    1.44 +
    1.45 +(defmethod display
    1.46 +  cxcore$IplImage [image]
    1.47 +  ( display (.getBufferedImage image)))
    1.48 +  
    1.49 +(defmethod display
    1.50 +  String [image]
    1.51 +  (display (highgui/cvLoadImage image highgui/CV_LOAD_IMAGE_COLOR)))
    1.52 +
    1.53 +(defmethod display
    1.54 +  LazySeq [s]
    1.55 +  (display (first s)))
    1.56 +
    1.57 +
    1.58 +
    1.59 +(def ext "jpg") 
    1.60 +;see below for the rationale for this choice of extention.
    1.61 +
    1.62 +(def cache-location "/home/r/Desktop/vision-cache/")
    1.63 +
    1.64 +(defn close-capture
    1.65 +  [capture]
    1.66 +  (highgui/cvReleaseCapture (highgui$CvCapture$PointerByReference. capture)))
    1.67 +
    1.68 +(defn close-writer
    1.69 +  [writer] (highgui/cvReleaseVideoWriter (highgui$CvVideoWriter$PointerByReference. writer))) 
    1.70 +
    1.71 +(defn- cache-path
    1.72 +  [video]
    1.73 +  (File. cache-location (.getName video)))
    1.74 +
    1.75 +(defn- already-cached
    1.76 +  "this is the simplest and most retarded way to do it"
    1.77 +  [video]
    1.78 +  (.exists (cache-path video)))
    1.79 +
    1.80 +(defn write-frame 
    1.81 +  [capture target-dir n]
    1.82 +  (let [image (highgui/cvQueryFrame capture)]
    1.83 +    (if (nil? image) false
    1.84 +	(highgui/cvSaveImage (str (File. target-dir (str n "."  ext))) image))))
    1.85 +
    1.86 +(defn- write-frame-bad
    1.87 +  [capture target-dir n]
    1.88 +  (println (str "saving frame: " n))
    1.89 +  (let [image (highgui/cvQueryFrame capture)]
    1.90 +    (if (nil? image) false
    1.91 +	( ImageIO/write (.getBufferedImage image) ext (File. target-dir (str n "."  ext))))))
    1.92 +
    1.93 +(defn- write-frames
    1.94 +  [video target-dir]
    1.95 +  (let [capture (highgui/cvCreateFileCapture (.getPath video))]
    1.96 +   (dorun 
    1.97 +    (for [n (naturals) :while (write-frame capture target-dir n) ] nil ))
    1.98 +    (highgui/cvReleaseCapture (highgui$CvCapture$PointerByReference. capture))))
    1.99 +
   1.100 +(defn- cache-frames
   1.101 +  [cache-location video]
   1.102 +  (time 
   1.103 +   (do
   1.104 +     (println "\"caching entire video structure... this will take a while... go get a snack or something :)\"")
   1.105 +     (FileUtils/deleteDirectory (cache-path video))
   1.106 +     (FileUtils/forceMkdir (cache-path video))
   1.107 +     (write-frames video  (cache-path video)))))
   1.108 +
   1.109 +;(defn cache
   1.110 +;  [video]
   1.111 +;  (if (already-cached video) nil (cache-frames cache-location video)))
   1.112 + 
   1.113 +(defn video-len 
   1.114 +  [video]
   1.115 +  (alength (.list (cache-path video))))
   1.116 +(def video-len (memoize video-len))
   1.117 + 
   1.118 +(defn video-data
   1.119 +  "since the opencv version is so absolutely unreliable..."
   1.120 +  [video]
   1.121 +  (let
   1.122 +      [capture (highgui/cvCreateFileCapture (.getPath video))
   1.123 +       info {:length      (video-len video)
   1.124 +	     :width       (highgui/cvGetCaptureProperty capture highgui/CV_CAP_PROP_FRAME_WIDTH)
   1.125 +	     :height      (highgui/cvGetCaptureProperty capture highgui/CV_CAP_PROP_FRAME_HEIGHT)
   1.126 +	     :fps         (highgui/cvGetCaptureProperty capture highgui/CV_CAP_PROP_FPS)
   1.127 +	     :codec       (highgui/cvGetCaptureProperty capture highgui/CV_CAP_PROP_FOURCC)}]
   1.128 +    (close-capture capture)
   1.129 +    info))
   1.130 +(def video-data (memoize video-data))
   1.131 +
   1.132 +(defn video-frame-path
   1.133 +     [video n]
   1.134 +     (File. (cache-path video)  (str n "."  ext)))
   1.135 +
   1.136 +
   1.137 +(defn- video-frame-ipl
   1.138 +  [video n] 
   1.139 +;  (cache video)
   1.140 +  (let 
   1.141 +      [c++-managed  (highgui/cvLoadImage (str (File. (cache-path video) (str n "."  ext))) highgui/CV_LOAD_IMAGE_COLOR)
   1.142 +       jvm-managed (.clone c++-managed)] 
   1.143 +	 ;this bit with the cloning is so I can deal with Garbage Collection once and for all.
   1.144 +	 ;the cpp-managed image must be manually Garbage Collected, but it's clone is managed by 
   1.145 +         ;the JVM's Garbage Collector.  By getting rid of the c++ part right here and now, no 
   1.146 +         ;other function has to worry about manual garbage collection ever again.
   1.147 +         ;Unfortunately, this doesn't seem to work for certain types of files. It's not file-size
   1.148 +         ;which is the issue, but something involving the image header.
   1.149 +    (cxcore/cvReleaseImage (.pointerByReference c++-managed))
   1.150 +    jvm-managed
   1.151 +))
   1.152 +  
   1.153 +
   1.154 +(defn- video-frame-buffered
   1.155 +  "takes one frame from a video in constant time"
   1.156 +  [video n]
   1.157 + ; (cache video)
   1.158 +  (ImageIO/read (File. (cache-path video) (str n "."  ext))))
   1.159 +
   1.160 +(defn video-frame [video n] (video-frame-buffered video n))
   1.161 +
   1.162 +(defn- dumb-write 
   1.163 +  [video n writer]
   1.164 +  (let 
   1.165 +      [c++-managed  (highgui/cvLoadImage (str (File. (cache-path video) (str n ext))) highgui/CV_LOAD_IMAGE_COLOR)]
   1.166 +    (highgui/cvWriteFrame writer  c++-managed)
   1.167 +    (cxcore/cvReleaseImage (cxcore$IplImage$PointerByReference. c++-managed))))
   1.168 +
   1.169 +(defn video-seq
   1.170 +  "makes a lazy sequence of IPL images"
   1.171 +  ;additionally, I want to pass metadata around with the sequence.
   1.172 +  [video] ;(cache video)
   1.173 +  (map #(video-frame video %) (range (video-len video))))
   1.174 +(defn video-writer
   1.175 +  "uses data about the video to make a writer"
   1.176 +  [data fileTarget]
   1.177 +  (highgui/cvCreateVideoWriter 
   1.178 +   (str fileTarget)
   1.179 +   
   1.180 +   ;(highgui/CV_FOURCC \P,\I,\M,\1) ;= MPEG-1 codec  (112913.386195 msecs) (104 MB)
   1.181 +   ;(highgui/CV_FOURCC \M,\J,\P,\G) ;= motion-jpeg codec (crashed)
   1.182 +   ;(highgui/CV_FOURCC \M,\P,\4,\2) ;= MPEG-4.2 codec (107184.186774 msecs) (82 MB)
   1.183 +   ;(highgui/CV_FOURCC \D,\I,\V,\3) ;= MPEG-4.3 codec (118308.933328 msecs)  (83 MB)
   1.184 +   (highgui/CV_FOURCC \D,\I,\V,\X) ;= MPEG-4 codec    (99037.738131 msecs)  (85 MB)
   1.185 +   ;(highgui/CV_FOURCC \U,\2,\6,\3) ;= H263 codec     (101141.993551 msecs) (89 MB)
   1.186 +   ;(highgui/CV_FOURCC \I,\2,\6,\3) ;= H263I codec      (crashed)
   1.187 +   ;(highgui/CV_FOURCC \F,\L,\V,\1) ;= FLV1 codec     (104307.567802 msecs) (93 MB)
   1.188 +   ;(:codec data)                    ;= whatever the movie originally had.  (98278.694169 msecs) (1.9 GB)  
   1.189 +
   1.190 +   (:fps data) (cxcore/cvSize (:width data) (:height data)) 
   1.191 +   1; 1 here means that we're writing in color.
   1.192 +    ; you cannot change it to 0 to write in 
   1.193 +    ; black and white. Everything just crashes instead.
   1.194 +    ; what a useful paramater.
   1.195 +   ))
   1.196 +
   1.197 +
   1.198 +(defn naturals []  (iterate inc 0))
   1.199 +
   1.200 +
   1.201 +(defn write-frame-2
   1.202 +  [writer frame]
   1.203 +  (let [c++-frame (cxcore$IplImage/createFrom frame)]
   1.204 +    (highgui/cvWriteFrame writer c++-frame)
   1.205 +   ; (cxcore/cvReleaseImage (.pointerByReference c++-frame)))
   1.206 +)
   1.207 +    frame)
   1.208 +
   1.209 +(defn save-seq 
   1.210 +  [writer video-seq]
   1.211 +  (map #(write-frame-2 writer %) video-seq))
   1.212 +
   1.213 +(defmacro trans-save
   1.214 +"there's a small problem with trans-save --- it IS
   1.215 +truly transitive, but it does too much work....
   1.216 +sometimes it writes files twice.
   1.217 +this is functionally correct though."
   1.218 +  [target config video-seq]
   1.219 +  `(let [writer# (video-writer ~config ~target)]
   1.220 +     (do
   1.221 +       (dorun (save-seq writer# ~video-seq))
   1.222 +       (close-writer writer#)
   1.223 +       ~video-seq)))
   1.224 +
   1.225 +
   1.226 +
   1.227 +(comment 
   1.228 +(do (use :reload-all 'clojureDemo.OpenCv) (in-ns 'clojureDemo.OpenCv))
   1.229 +)