Mercurial > lasercutter
comparison 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 |
comparison
equal
deleted
inserted
replaced
0:163bf9b2fd13 | 1:6d9bdaf919f7 |
---|---|
1 (ns clojureDemo.VisionCore) | |
2 | |
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 cxcore)) | |
12 (import '(name.audet.samuel.javacv CanvasFrame)) | |
13 (import '(name.audet.samuel.javacv.jna cxcore$IplImage)) | |
14 (import '(name.audet.samuel.javacv.jna highgui$CvCapture$PointerByReference)) | |
15 (import '(name.audet.samuel.javacv.jna highgui$CvVideoWriter$PointerByReference)) | |
16 (import '(name.audet.samuel.javacv.jna cxcore$IplImage$PointerByReference)) | |
17 (import '(name.audet.samuel.javacv.jna cxcore$IplImage)) | |
18 (import '(name.audet.samuel.javacv JavaCvErrorCallback)) | |
19 (.redirectError (JavaCvErrorCallback.)) | |
20 | |
21 (use 'clojure.contrib.repl-utils) | |
22 | |
23 (def -inf Double/NEGATIVE_INFINITY) | |
24 (def inf Double/POSITIVE_INFINITY) | |
25 | |
26 | |
27 | |
28 (def lian (File. "/home/r/Desktop/source-videos/lian1.mpeg")) | |
29 (def look (File. "/home/r/Desktop/source-videos/dramatic_look.flv")) | |
30 | |
31 (def target (File. "/home/r/Desktop/output-vision/")) | |
32 | |
33 | |
34 ;this is still a work in progress, I'll come back to it later when I understand | |
35 ;jna more thoroughly. the important abstraction here is | |
36 ;video-seq, which gives a lazy sequence of Intel Image Processing library images. | |
37 | |
38 (defn naturals [] (iterate inc 0)) | |
39 | |
40 (def ext "jpg") | |
41 ;see below for the rationale for this choice of extention. | |
42 | |
43 (def cache-location "/home/r/Desktop/vision-cache/") | |
44 | |
45 (defn close-capture | |
46 [capture] | |
47 (highgui/cvReleaseCapture (highgui$CvCapture$PointerByReference. capture))) | |
48 | |
49 (defn close-writer | |
50 [writer] (highgui/cvReleaseVideoWriter (highgui$CvVideoWriter$PointerByReference. writer))) | |
51 | |
52 (defn- cache-path | |
53 [video] | |
54 (File. cache-location (.getName video))) | |
55 | |
56 (defn- already-cached | |
57 "this is the simplest and most retarded way to do it" | |
58 [video] | |
59 (.exists (cache-path video))) | |
60 | |
61 (defn- write-frame | |
62 [capture target-dir n] | |
63 (let [image (highgui/cvQueryFrame capture)] | |
64 (if (nil? image) false | |
65 (highgui/cvSaveImage (str (File. target-dir (str n "." ext))) image)))) | |
66 | |
67 (defn- write-frame-bad | |
68 [capture target-dir n] | |
69 (println (str "saving frame: " n)) | |
70 (let [image (highgui/cvQueryFrame capture)] | |
71 (if (nil? image) false | |
72 ( ImageIO/write (.getBufferedImage image) ext (File. target-dir (str n "." ext)))))) | |
73 | |
74 (defn- write-frames | |
75 [video target-dir] | |
76 (let [capture (highgui/cvCreateFileCapture (.getPath video))] | |
77 (dorun | |
78 (for [n (naturals) :while (write-frame capture target-dir n) ] nil )) | |
79 (highgui/cvReleaseCapture (highgui$CvCapture$PointerByReference. capture)))) | |
80 | |
81 (defn- cache-frames | |
82 [cache-location video] | |
83 (time | |
84 (do | |
85 (println "\"caching entire video structure... this will take a while... go get a snack or something :)\"") | |
86 (FileUtils/deleteDirectory (cache-path video)) | |
87 (FileUtils/forceMkdir (cache-path video)) | |
88 (write-frames video (cache-path video))))) | |
89 | |
90 (defn cache | |
91 [video] | |
92 (if (already-cached video) nil (cache-frames cache-location video))) | |
93 | |
94 (defn video-len | |
95 [video] (cache video) | |
96 (alength (.list (cache-path video)))) | |
97 (def video-len (memoize video-len)) | |
98 | |
99 (defn video-data | |
100 "since the opencv version is so absolutely unreliable..." | |
101 [video] | |
102 (let | |
103 [capture (highgui/cvCreateFileCapture (.getPath video)) | |
104 info {:length (video-len video) | |
105 :width (highgui/cvGetCaptureProperty capture highgui/CV_CAP_PROP_FRAME_WIDTH) | |
106 :height (highgui/cvGetCaptureProperty capture highgui/CV_CAP_PROP_FRAME_HEIGHT) | |
107 :fps (highgui/cvGetCaptureProperty capture highgui/CV_CAP_PROP_FPS) | |
108 :codec (highgui/cvGetCaptureProperty capture highgui/CV_CAP_PROP_FOURCC)}] | |
109 (close-capture capture) | |
110 info)) | |
111 (def video-data (memoize video-data)) | |
112 | |
113 (defn- video-frame | |
114 [video n] | |
115 (cache video) | |
116 (let | |
117 [c++-managed (highgui/cvLoadImage (str (File. (cache-path video) (str n "." ext))) highgui/CV_LOAD_IMAGE_COLOR) | |
118 jvm-managed (.clone c++-managed)] | |
119 ;this bit with the cloning is so I can deal with Garbage Collection once and for all. | |
120 ;the cpp-managed image must be manually Garbage Collected, but it's clone is managed by | |
121 ;the JVM's Garbage Collector. By getting rid of the c++ part right here and now, no | |
122 ;other function has to worry about manual garbage collection ever again. | |
123 ;Unfortunately, this doesn't seem to work for certain types of files. It's not file-size | |
124 ;which is the issue, but something involving the image header. | |
125 (cxcore/cvReleaseImage (.pointerByReference c++-managed)) | |
126 jvm-managed | |
127 )) | |
128 | |
129 | |
130 (defn- video-frame-buffered | |
131 "takes one frame from a video in constant time" | |
132 [video n] | |
133 (cache video) | |
134 (ImageIO/read (File. (cache-path video) (str n "." ext)))) | |
135 | |
136 | |
137 (defn- dumb-write | |
138 [video n writer] | |
139 (let | |
140 [c++-managed (highgui/cvLoadImage (str (File. (cache-path video) (str n ext))) highgui/CV_LOAD_IMAGE_COLOR)] | |
141 (highgui/cvWriteFrame writer c++-managed) | |
142 (cxcore/cvReleaseImage (cxcore$IplImage$PointerByReference. c++-managed)))) | |
143 | |
144 (defn video-seq | |
145 "makes a lazy sequence of IPL images" | |
146 ;additionally, I want to pass metadata around with the sequence. | |
147 [video] (cache video) | |
148 (map #(video-frame video %) (range (video-len video)))) | |
149 | |
150 | |
151 | |
152 | |
153 | |
154 | |
155 (comment | |
156 | |
157 ; I initially decided to use .sr because it loads the fastest out of all the | |
158 ; formats opencv supports, under a simple benchmark of reading/writing | |
159 ; a blank file of each type 100 times. | |
160 | |
161 ;I just kept changing the file extention at the REPL to generate these times. | |
162 (def file "test.tiff") | |
163 (do | |
164 (time (dotimes [_ 100] (highgui/cvSaveImage (str cache-location file) ipl))) | |
165 (time (dotimes [_ 100] (highgui/cvLoadImage (str cache-location file))))) | |
166 | |
167 ; Write Read | |
168 (jpg 4404.000955 msecs 3397.8564 msecs) | |
169 (jpeg 4376.138853 msecs 3482.990118 msecs) | |
170 (jpeg 4253.721501 msecs 3414.004122 msecs) | |
171 (bmp 3488.281695 msecs 786.883035 msecs) | |
172 (dib 3589.010247 msecs 685.681985 msecs) | |
173 (jpe 4288.541679 msecs 3359.819425 msecs) | |
174 (png 10127.648557 msecs 3786.184994 msecs) | |
175 (pbm 3880.794141 msecs 917.737667 msecs) | |
176 (pgm 3879.710445 msecs 894.78237 msecs) | |
177 (ppm 3938.319148 msecs 1014.412766 msecs) | |
178 (sr 3510.893891 msecs 676.502596 msecs) | |
179 (dib 3434.654784 msecs 737.495844 msecs) | |
180 (bmp 3354.956726 msecs 783.353025 msecs) | |
181 (ras 3351.400751 msecs 722.548007 msecs) | |
182 (tiff 3657.893326 msecs 1361.576798 msecs) | |
183 (tif 3594.753736 msecs 1254.568533 msecs) | |
184 | |
185 ;Ah, but now it's time for some more tests. | |
186 ;I started using | |
187 (def ext ".sr") | |
188 ;, and an empty cache, and ran | |
189 (cache lian) | |
190 "caching entire video structure... this will take a while... go get a snack or something :)" | |
191 "Elapsed time: 56486.816728 msecs" | |
192 (time (dorun (video-seq lian))) | |
193 "Elapsed time: 120515.66221 msecs" | |
194 (time (dorun (video-seq lian))) | |
195 "Elapsed time: 122867.82989 msecs" ;good agreement with times | |
196 | |
197 ;*erased vision cache with* | |
198 ;*rm -rf ~/Desktop/vision-cache * | |
199 (def ext ".bmp") | |
200 (cache lian) | |
201 "Elapsed time: 59613.624691 msecs" | |
202 (time (dorun (video-seq lian))) | |
203 "Elapsed time: 123850.390784 msecs" | |
204 | |
205 ;same process except with | |
206 (def ext ".jpg") | |
207 (cache lian) | |
208 "Elapsed time: 139964.031921 msecs" | |
209 (time (dorun (video-seq lian))) | |
210 "Elapsed time: 127740.50204 msecs" | |
211 | |
212 ;I find this quite shocking --- the jpg's do take longer to cache, | |
213 ;but the processing time is almost the same! | |
214 | |
215 ;since lian is 434 MB as a bunch of jpg files, and 3.7 GB as .sr files, | |
216 ;I'll go with the jpgs. | |
217 | |
218 | |
219 ;; writing files | |
220 | |
221 "JPG" | |
222 (time (write-video sarah (File. "/home/r/Desktop/clojure2.avi"))) | |
223 "Elapsed time: 371541.024455 msecs" | |
224 | |
225 "BMP" | |
226 (time (write-video sarah (File. "/home/r/Desktop/clojure3.avi"))) | |
227 "Elapsed time: 382568.502361 msecs" | |
228 | |
229 ) |