Mercurial > lasercutter
diff src/clojureDemo/VisionCore.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/VisionCore.clj Fri Aug 20 00:32:44 2010 -0400 1.3 @@ -0,0 +1,229 @@ 1.4 +(ns clojureDemo.VisionCore) 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 +(import '(name.audet.samuel.javacv CanvasFrame)) 1.16 +(import '(name.audet.samuel.javacv.jna cxcore$IplImage)) 1.17 +(import '(name.audet.samuel.javacv.jna highgui$CvCapture$PointerByReference)) 1.18 +(import '(name.audet.samuel.javacv.jna highgui$CvVideoWriter$PointerByReference)) 1.19 +(import '(name.audet.samuel.javacv.jna cxcore$IplImage$PointerByReference)) 1.20 +(import '(name.audet.samuel.javacv.jna cxcore$IplImage)) 1.21 +(import '(name.audet.samuel.javacv JavaCvErrorCallback)) 1.22 +(.redirectError (JavaCvErrorCallback.)) 1.23 + 1.24 +(use 'clojure.contrib.repl-utils) 1.25 + 1.26 +(def -inf Double/NEGATIVE_INFINITY) 1.27 +(def inf Double/POSITIVE_INFINITY) 1.28 + 1.29 + 1.30 + 1.31 +(def lian (File. "/home/r/Desktop/source-videos/lian1.mpeg")) 1.32 +(def look (File. "/home/r/Desktop/source-videos/dramatic_look.flv")) 1.33 + 1.34 +(def target (File. "/home/r/Desktop/output-vision/")) 1.35 + 1.36 + 1.37 +;this is still a work in progress, I'll come back to it later when I understand 1.38 +;jna more thoroughly. the important abstraction here is 1.39 +;video-seq, which gives a lazy sequence of Intel Image Processing library images. 1.40 + 1.41 +(defn naturals [] (iterate inc 0)) 1.42 + 1.43 +(def ext "jpg") 1.44 +;see below for the rationale for this choice of extention. 1.45 + 1.46 +(def cache-location "/home/r/Desktop/vision-cache/") 1.47 + 1.48 +(defn close-capture 1.49 + [capture] 1.50 + (highgui/cvReleaseCapture (highgui$CvCapture$PointerByReference. capture))) 1.51 + 1.52 +(defn close-writer 1.53 + [writer] (highgui/cvReleaseVideoWriter (highgui$CvVideoWriter$PointerByReference. writer))) 1.54 + 1.55 +(defn- cache-path 1.56 + [video] 1.57 + (File. cache-location (.getName video))) 1.58 + 1.59 +(defn- already-cached 1.60 + "this is the simplest and most retarded way to do it" 1.61 + [video] 1.62 + (.exists (cache-path video))) 1.63 + 1.64 +(defn- write-frame 1.65 + [capture target-dir n] 1.66 + (let [image (highgui/cvQueryFrame capture)] 1.67 + (if (nil? image) false 1.68 + (highgui/cvSaveImage (str (File. target-dir (str n "." ext))) image)))) 1.69 + 1.70 +(defn- write-frame-bad 1.71 + [capture target-dir n] 1.72 + (println (str "saving frame: " n)) 1.73 + (let [image (highgui/cvQueryFrame capture)] 1.74 + (if (nil? image) false 1.75 + ( ImageIO/write (.getBufferedImage image) ext (File. target-dir (str n "." ext)))))) 1.76 + 1.77 +(defn- write-frames 1.78 + [video target-dir] 1.79 + (let [capture (highgui/cvCreateFileCapture (.getPath video))] 1.80 + (dorun 1.81 + (for [n (naturals) :while (write-frame capture target-dir n) ] nil )) 1.82 + (highgui/cvReleaseCapture (highgui$CvCapture$PointerByReference. capture)))) 1.83 + 1.84 +(defn- cache-frames 1.85 + [cache-location video] 1.86 + (time 1.87 + (do 1.88 + (println "\"caching entire video structure... this will take a while... go get a snack or something :)\"") 1.89 + (FileUtils/deleteDirectory (cache-path video)) 1.90 + (FileUtils/forceMkdir (cache-path video)) 1.91 + (write-frames video (cache-path video))))) 1.92 + 1.93 +(defn cache 1.94 + [video] 1.95 + (if (already-cached video) nil (cache-frames cache-location video))) 1.96 + 1.97 +(defn video-len 1.98 + [video] (cache video) 1.99 + (alength (.list (cache-path video)))) 1.100 +(def video-len (memoize video-len)) 1.101 + 1.102 +(defn video-data 1.103 + "since the opencv version is so absolutely unreliable..." 1.104 + [video] 1.105 + (let 1.106 + [capture (highgui/cvCreateFileCapture (.getPath video)) 1.107 + info {:length (video-len video) 1.108 + :width (highgui/cvGetCaptureProperty capture highgui/CV_CAP_PROP_FRAME_WIDTH) 1.109 + :height (highgui/cvGetCaptureProperty capture highgui/CV_CAP_PROP_FRAME_HEIGHT) 1.110 + :fps (highgui/cvGetCaptureProperty capture highgui/CV_CAP_PROP_FPS) 1.111 + :codec (highgui/cvGetCaptureProperty capture highgui/CV_CAP_PROP_FOURCC)}] 1.112 + (close-capture capture) 1.113 + info)) 1.114 +(def video-data (memoize video-data)) 1.115 + 1.116 +(defn- video-frame 1.117 + [video n] 1.118 + (cache video) 1.119 + (let 1.120 + [c++-managed (highgui/cvLoadImage (str (File. (cache-path video) (str n "." ext))) highgui/CV_LOAD_IMAGE_COLOR) 1.121 + jvm-managed (.clone c++-managed)] 1.122 + ;this bit with the cloning is so I can deal with Garbage Collection once and for all. 1.123 + ;the cpp-managed image must be manually Garbage Collected, but it's clone is managed by 1.124 + ;the JVM's Garbage Collector. By getting rid of the c++ part right here and now, no 1.125 + ;other function has to worry about manual garbage collection ever again. 1.126 + ;Unfortunately, this doesn't seem to work for certain types of files. It's not file-size 1.127 + ;which is the issue, but something involving the image header. 1.128 + (cxcore/cvReleaseImage (.pointerByReference c++-managed)) 1.129 + jvm-managed 1.130 +)) 1.131 + 1.132 + 1.133 +(defn- video-frame-buffered 1.134 + "takes one frame from a video in constant time" 1.135 + [video n] 1.136 + (cache video) 1.137 + (ImageIO/read (File. (cache-path video) (str n "." ext)))) 1.138 + 1.139 + 1.140 +(defn- dumb-write 1.141 + [video n writer] 1.142 + (let 1.143 + [c++-managed (highgui/cvLoadImage (str (File. (cache-path video) (str n ext))) highgui/CV_LOAD_IMAGE_COLOR)] 1.144 + (highgui/cvWriteFrame writer c++-managed) 1.145 + (cxcore/cvReleaseImage (cxcore$IplImage$PointerByReference. c++-managed)))) 1.146 + 1.147 +(defn video-seq 1.148 + "makes a lazy sequence of IPL images" 1.149 + ;additionally, I want to pass metadata around with the sequence. 1.150 + [video] (cache video) 1.151 + (map #(video-frame video %) (range (video-len video)))) 1.152 + 1.153 + 1.154 + 1.155 + 1.156 + 1.157 + 1.158 +(comment 1.159 + 1.160 +; I initially decided to use .sr because it loads the fastest out of all the 1.161 +; formats opencv supports, under a simple benchmark of reading/writing 1.162 +; a blank file of each type 100 times. 1.163 + 1.164 + ;I just kept changing the file extention at the REPL to generate these times. 1.165 + (def file "test.tiff") 1.166 + (do 1.167 + (time (dotimes [_ 100] (highgui/cvSaveImage (str cache-location file) ipl))) 1.168 + (time (dotimes [_ 100] (highgui/cvLoadImage (str cache-location file))))) 1.169 + 1.170 + ; Write Read 1.171 + (jpg 4404.000955 msecs 3397.8564 msecs) 1.172 + (jpeg 4376.138853 msecs 3482.990118 msecs) 1.173 + (jpeg 4253.721501 msecs 3414.004122 msecs) 1.174 + (bmp 3488.281695 msecs 786.883035 msecs) 1.175 + (dib 3589.010247 msecs 685.681985 msecs) 1.176 + (jpe 4288.541679 msecs 3359.819425 msecs) 1.177 + (png 10127.648557 msecs 3786.184994 msecs) 1.178 + (pbm 3880.794141 msecs 917.737667 msecs) 1.179 + (pgm 3879.710445 msecs 894.78237 msecs) 1.180 + (ppm 3938.319148 msecs 1014.412766 msecs) 1.181 + (sr 3510.893891 msecs 676.502596 msecs) 1.182 + (dib 3434.654784 msecs 737.495844 msecs) 1.183 + (bmp 3354.956726 msecs 783.353025 msecs) 1.184 + (ras 3351.400751 msecs 722.548007 msecs) 1.185 + (tiff 3657.893326 msecs 1361.576798 msecs) 1.186 + (tif 3594.753736 msecs 1254.568533 msecs) 1.187 + 1.188 +;Ah, but now it's time for some more tests. 1.189 +;I started using 1.190 +(def ext ".sr") 1.191 +;, and an empty cache, and ran 1.192 +(cache lian) 1.193 +"caching entire video structure... this will take a while... go get a snack or something :)" 1.194 +"Elapsed time: 56486.816728 msecs" 1.195 +(time (dorun (video-seq lian))) 1.196 +"Elapsed time: 120515.66221 msecs" 1.197 +(time (dorun (video-seq lian))) 1.198 +"Elapsed time: 122867.82989 msecs" ;good agreement with times 1.199 + 1.200 +;*erased vision cache with* 1.201 +;*rm -rf ~/Desktop/vision-cache * 1.202 +(def ext ".bmp") 1.203 +(cache lian) 1.204 +"Elapsed time: 59613.624691 msecs" 1.205 +(time (dorun (video-seq lian))) 1.206 +"Elapsed time: 123850.390784 msecs" 1.207 + 1.208 +;same process except with 1.209 +(def ext ".jpg") 1.210 +(cache lian) 1.211 +"Elapsed time: 139964.031921 msecs" 1.212 +(time (dorun (video-seq lian))) 1.213 +"Elapsed time: 127740.50204 msecs" 1.214 + 1.215 +;I find this quite shocking --- the jpg's do take longer to cache, 1.216 +;but the processing time is almost the same! 1.217 + 1.218 +;since lian is 434 MB as a bunch of jpg files, and 3.7 GB as .sr files, 1.219 +;I'll go with the jpgs. 1.220 + 1.221 + 1.222 +;; writing files 1.223 + 1.224 +"JPG" 1.225 +(time (write-video sarah (File. "/home/r/Desktop/clojure2.avi"))) 1.226 +"Elapsed time: 371541.024455 msecs" 1.227 + 1.228 +"BMP" 1.229 +(time (write-video sarah (File. "/home/r/Desktop/clojure3.avi"))) 1.230 +"Elapsed time: 382568.502361 msecs" 1.231 + 1.232 +)