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