Mercurial > lasercutter
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 +)