Mercurial > lasercutter
view src/clojureDemo/OpenCv.clj @ 15:8ad629298649
major refactoring
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sun, 29 Aug 2010 19:02:26 -0400 |
parents | 6d9bdaf919f7 |
children |
line wrap: on
line source
1 (ns clojureDemo.OpenCv)3 (import '(java.awt Rectangle Robot Toolkit) )4 (import '(java.awt.image BufferedImage) )5 (import '(java.awt Graphics2D Panel))6 (import '(java.io File) )7 (import '(javax.imageio ImageIO) )8 (import '(javax.swing JFrame))9 (import '(org.apache.commons.io FileUtils))10 (import clojure.lang.LazySeq)11 (import '(name.audet.samuel.javacv.jna highgui cv cxcore12 cxcore$IplImage highgui$CvCapture$PointerByReference13 highgui$CvVideoWriter$PointerByReference cxcore$IplImage$PointerByReference))14 (import '(name.audet.samuel.javacv CanvasFrame JavaCvErrorCallback))16 (.redirectError (JavaCvErrorCallback.))18 (use 'clojure.contrib.repl-utils)19 ;(use 'clojureDemo.Defines)20 ;(use '[clojureDemo.Xuggle :only (cache)])22 ;this is still a work in progress, I'll come back to it later when I understand23 ;jna more thoroughly. the important abstraction here is24 ;video-seq, which gives a lazy sequence of Intel Image Processing library images.26 (defn naturals [] (iterate inc 0))28 (defn- makePanel [image] (proxy [Panel] [] (paint [g] (.drawImage g image 0 0 nil))))31 (defmulti display "Creates a JFrame and displays a buffered image" class)33 (defmethod display34 BufferedImage [image]35 (let [panel (makePanel image)36 frame (JFrame. "Oh Yeah!")]37 (.add frame panel)38 (.pack frame)39 (.setVisible frame true )40 (.setSize frame(.getWidth image) (.getHeight image))))42 (defmethod display43 cxcore$IplImage [image]44 ( display (.getBufferedImage image)))46 (defmethod display47 String [image]48 (display (highgui/cvLoadImage image highgui/CV_LOAD_IMAGE_COLOR)))50 (defmethod display51 LazySeq [s]52 (display (first s)))56 (def ext "jpg")57 ;see below for the rationale for this choice of extention.59 (def cache-location "/home/r/Desktop/vision-cache/")61 (defn close-capture62 [capture]63 (highgui/cvReleaseCapture (highgui$CvCapture$PointerByReference. capture)))65 (defn close-writer66 [writer] (highgui/cvReleaseVideoWriter (highgui$CvVideoWriter$PointerByReference. writer)))68 (defn- cache-path69 [video]70 (File. cache-location (.getName video)))72 (defn- already-cached73 "this is the simplest and most retarded way to do it"74 [video]75 (.exists (cache-path video)))77 (defn write-frame78 [capture target-dir n]79 (let [image (highgui/cvQueryFrame capture)]80 (if (nil? image) false81 (highgui/cvSaveImage (str (File. target-dir (str n "." ext))) image))))83 (defn- write-frame-bad84 [capture target-dir n]85 (println (str "saving frame: " n))86 (let [image (highgui/cvQueryFrame capture)]87 (if (nil? image) false88 ( ImageIO/write (.getBufferedImage image) ext (File. target-dir (str n "." ext))))))90 (defn- write-frames91 [video target-dir]92 (let [capture (highgui/cvCreateFileCapture (.getPath video))]93 (dorun94 (for [n (naturals) :while (write-frame capture target-dir n) ] nil ))95 (highgui/cvReleaseCapture (highgui$CvCapture$PointerByReference. capture))))97 (defn- cache-frames98 [cache-location video]99 (time100 (do101 (println "\"caching entire video structure... this will take a while... go get a snack or something :)\"")102 (FileUtils/deleteDirectory (cache-path video))103 (FileUtils/forceMkdir (cache-path video))104 (write-frames video (cache-path video)))))106 ;(defn cache107 ; [video]108 ; (if (already-cached video) nil (cache-frames cache-location video)))110 (defn video-len111 [video]112 (alength (.list (cache-path video))))113 (def video-len (memoize video-len))115 (defn video-data116 "since the opencv version is so absolutely unreliable..."117 [video]118 (let119 [capture (highgui/cvCreateFileCapture (.getPath video))120 info {:length (video-len video)121 :width (highgui/cvGetCaptureProperty capture highgui/CV_CAP_PROP_FRAME_WIDTH)122 :height (highgui/cvGetCaptureProperty capture highgui/CV_CAP_PROP_FRAME_HEIGHT)123 :fps (highgui/cvGetCaptureProperty capture highgui/CV_CAP_PROP_FPS)124 :codec (highgui/cvGetCaptureProperty capture highgui/CV_CAP_PROP_FOURCC)}]125 (close-capture capture)126 info))127 (def video-data (memoize video-data))129 (defn video-frame-path130 [video n]131 (File. (cache-path video) (str n "." ext)))134 (defn- video-frame-ipl135 [video n]136 ; (cache video)137 (let138 [c++-managed (highgui/cvLoadImage (str (File. (cache-path video) (str n "." ext))) highgui/CV_LOAD_IMAGE_COLOR)139 jvm-managed (.clone c++-managed)]140 ;this bit with the cloning is so I can deal with Garbage Collection once and for all.141 ;the cpp-managed image must be manually Garbage Collected, but it's clone is managed by142 ;the JVM's Garbage Collector. By getting rid of the c++ part right here and now, no143 ;other function has to worry about manual garbage collection ever again.144 ;Unfortunately, this doesn't seem to work for certain types of files. It's not file-size145 ;which is the issue, but something involving the image header.146 (cxcore/cvReleaseImage (.pointerByReference c++-managed))147 jvm-managed148 ))151 (defn- video-frame-buffered152 "takes one frame from a video in constant time"153 [video n]154 ; (cache video)155 (ImageIO/read (File. (cache-path video) (str n "." ext))))157 (defn video-frame [video n] (video-frame-buffered video n))159 (defn- dumb-write160 [video n writer]161 (let162 [c++-managed (highgui/cvLoadImage (str (File. (cache-path video) (str n ext))) highgui/CV_LOAD_IMAGE_COLOR)]163 (highgui/cvWriteFrame writer c++-managed)164 (cxcore/cvReleaseImage (cxcore$IplImage$PointerByReference. c++-managed))))166 (defn video-seq167 "makes a lazy sequence of IPL images"168 ;additionally, I want to pass metadata around with the sequence.169 [video] ;(cache video)170 (map #(video-frame video %) (range (video-len video))))171 (defn video-writer172 "uses data about the video to make a writer"173 [data fileTarget]174 (highgui/cvCreateVideoWriter175 (str fileTarget)177 ;(highgui/CV_FOURCC \P,\I,\M,\1) ;= MPEG-1 codec (112913.386195 msecs) (104 MB)178 ;(highgui/CV_FOURCC \M,\J,\P,\G) ;= motion-jpeg codec (crashed)179 ;(highgui/CV_FOURCC \M,\P,\4,\2) ;= MPEG-4.2 codec (107184.186774 msecs) (82 MB)180 ;(highgui/CV_FOURCC \D,\I,\V,\3) ;= MPEG-4.3 codec (118308.933328 msecs) (83 MB)181 (highgui/CV_FOURCC \D,\I,\V,\X) ;= MPEG-4 codec (99037.738131 msecs) (85 MB)182 ;(highgui/CV_FOURCC \U,\2,\6,\3) ;= H263 codec (101141.993551 msecs) (89 MB)183 ;(highgui/CV_FOURCC \I,\2,\6,\3) ;= H263I codec (crashed)184 ;(highgui/CV_FOURCC \F,\L,\V,\1) ;= FLV1 codec (104307.567802 msecs) (93 MB)185 ;(:codec data) ;= whatever the movie originally had. (98278.694169 msecs) (1.9 GB)187 (:fps data) (cxcore/cvSize (:width data) (:height data))188 1; 1 here means that we're writing in color.189 ; you cannot change it to 0 to write in190 ; black and white. Everything just crashes instead.191 ; what a useful paramater.192 ))195 (defn naturals [] (iterate inc 0))198 (defn write-frame-2199 [writer frame]200 (let [c++-frame (cxcore$IplImage/createFrom frame)]201 (highgui/cvWriteFrame writer c++-frame)202 ; (cxcore/cvReleaseImage (.pointerByReference c++-frame)))203 )204 frame)206 (defn save-seq207 [writer video-seq]208 (map #(write-frame-2 writer %) video-seq))210 (defmacro trans-save211 "there's a small problem with trans-save --- it IS212 truly transitive, but it does too much work....213 sometimes it writes files twice.214 this is functionally correct though."215 [target config video-seq]216 `(let [writer# (video-writer ~config ~target)]217 (do218 (dorun (save-seq writer# ~video-seq))219 (close-writer writer#)220 ~video-seq)))224 (comment225 (do (use :reload-all 'clojureDemo.OpenCv) (in-ns 'clojureDemo.OpenCv))226 )