rlm@15
|
1 (ns laser.rasterize
|
rlm@15
|
2 (:use [rlm
|
rlm@15
|
3 image-utils
|
rlm@15
|
4 map-utils]
|
rlm@15
|
5 [clojure.contrib
|
rlm@19
|
6 [str-utils :only [str-join re-gsub re-split]]
|
rlm@15
|
7 [seq :only [indexed]]
|
rlm@19
|
8 [math]])
|
rlm@15
|
9 (:import [ij ImagePlus IJ]))
|
rlm@0
|
10
|
rlm@15
|
11 ;(import '(java.io File))
|
rlm@15
|
12 ;(import '(org.apache.commons.io FileUtils))
|
rlm@15
|
13 ;(import '(javax.imageio ImageIO) )
|
rlm@0
|
14
|
rlm@0
|
15
|
rlm@15
|
16 (set! *print-length* 20)
|
rlm@1
|
17 (def feed 120)
|
rlm@1
|
18 (def dpi [500, 500])
|
rlm@21
|
19 (def paramaters {:x-dpi 500 :y-dpi 500 :margin 0.501 :x-offset 1.001 :y-offset 1})
|
rlm@8
|
20
|
rlm@15
|
21 ;;; this process is divided into two tasks,
|
rlm@15
|
22 ;;; creating the raster g-code, which sweeps back and forth
|
rlm@15
|
23 ;;; and creating the gmask, which turns the laser on and off.
|
rlm@1
|
24
|
rlm@1
|
25
|
rlm@15
|
26 ;;; we'll be using frame-hashes, which represent picutres as
|
rlm@15
|
27 ;;; a 3D vector field over 2D space, with the vectors representing
|
rlm@19
|
28 ;;; the rgb values at that particulat point.
|
rlm@2
|
29
|
rlm@15
|
30 (defn select-row
|
rlm@15
|
31 "returns a frame hash that is just a single line at the chosen y"
|
rlm@15
|
32 [y window]
|
rlm@19
|
33 (filter-keys (comp (partial = y) last) window))
|
rlm@1
|
34
|
rlm@15
|
35 (defn make-rows [pic]
|
rlm@15
|
36 (map (partial sort #(< (first %1) (first %2)))
|
rlm@15
|
37 (partition-by last
|
rlm@15
|
38 (sort (fn [[x1 y1][x2 y2]] (> y2 y1))
|
rlm@15
|
39 (map first (filter-vals (partial = black) pic))))))
|
rlm@1
|
40
|
rlm@19
|
41
|
rlm@15
|
42 ;;; generate rastering g-code
|
rlm@1
|
43
|
rlm@3
|
44 (defn raster-preamble []
|
rlm@19
|
45 (str-join \newline
|
rlm@19
|
46 ["M63 P0\nG61"
|
rlm@19
|
47 (str "F" feed)
|
rlm@19
|
48 "M101"
|
rlm@19
|
49 "M3 S1\n"]))
|
rlm@3
|
50
|
rlm@4
|
51 (defn raster-epilogue []
|
rlm@19
|
52 (str-join \newline
|
rlm@19
|
53 ["M63 P0"
|
rlm@19
|
54 "M5"
|
rlm@19
|
55 "M2\n"]))
|
rlm@3
|
56
|
rlm@19
|
57 (defn raster-comment [string]
|
rlm@4
|
58 (str "(" (re-gsub #"[()]" "" string) ")"))
|
rlm@1
|
59
|
rlm@19
|
60
|
rlm@19
|
61 ;this is a sequence of rows
|
rlm@19
|
62
|
rlm@19
|
63 ;(defn span [row]
|
rlm@19
|
64 ; (let [sorted-row (sort #(< (first %1) (first %2)) row)]
|
rlm@19
|
65 ; (vector (first sorted-row) (last sorted-row))))
|
rlm@19
|
66
|
rlm@19
|
67
|
rlm@20
|
68 (comment
|
rlm@19
|
69
|
rlm@20
|
70 (import 'org.im4java.core.ConvertCmd)
|
rlm@20
|
71 (import 'org.im4java.core.IMOperation)
|
rlm@20
|
72 (import 'org.im4java.core.Stream2BufferedImage)
|
rlm@21
|
73
|
rlm@20
|
74 (def target (.getBufferedImage (ImagePlus. sing)))
|
rlm@21
|
75 (def shiv (IMOperation.))
|
rlm@21
|
76 (.addImage shiv)
|
rlm@21
|
77 (.addImage shiv (into-array String ["png:-"]))
|
rlm@21
|
78 (def conv-shiv (ConvertCmd.))
|
rlm@21
|
79 (def s2b (Stream2BufferedImage.))
|
rlm@21
|
80 (.setOutputConsumer conv-shiv s2b)
|
rlm@21
|
81 (.run conv-shiv shiv (into-array Object [target]))
|
rlm@21
|
82 (def result (.getImage s2b ))
|
rlm@20
|
83
|
rlm@20
|
84 )
|
rlm@20
|
85
|
rlm@21
|
86 (defn mirror
|
rlm@21
|
87 "ImagePlus to ImagePlus via imageMagick through im4java!"
|
rlm@21
|
88 [#^ImagePlus img]
|
rlm@20
|
89 (let [title (.getTitle img)
|
rlm@20
|
90 target (.getBufferedImage img)
|
rlm@20
|
91 s2b (Stream2BufferedImage.)
|
rlm@20
|
92 shiv (doto (IMOperation.)
|
rlm@20
|
93 ;(.blur 2.0)
|
rlm@20
|
94 (.flip)
|
rlm@20
|
95 (.addImage)
|
rlm@20
|
96 (.addImage (into-array String ["png:-"])))
|
rlm@20
|
97 conv-shiv (doto (ConvertCmd.)
|
rlm@20
|
98 (.setOutputConsumer s2b))]
|
rlm@20
|
99
|
rlm@20
|
100 (.run conv-shiv shiv (into-array Object [target]))
|
rlm@20
|
101 (ImagePlus. title (.getImage s2b))))
|
rlm@20
|
102
|
rlm@20
|
103
|
rlm@20
|
104
|
rlm@19
|
105 (defn row->gcode [{:keys [x-dpi y-dpi margin x-offset y-offset]} forward? row]
|
rlm@16
|
106
|
rlm@19
|
107 (let [[x1 y1] (if forward? (last row) (first row))
|
rlm@19
|
108 [x2 y2] (if forward? (first row) (last row))]
|
rlm@5
|
109
|
rlm@19
|
110 (let [x1 (* x1 (/ x-dpi))
|
rlm@19
|
111 x2 (* x2 (/ x-dpi))
|
rlm@19
|
112 y1 (* y1 (/ y-dpi))
|
rlm@20
|
113 y2 (* y2 (/ y-dpi))]
|
rlm@7
|
114
|
rlm@19
|
115 (let [x1 (+ x1 x-offset)
|
rlm@19
|
116 x2 (+ x2 x-offset)
|
rlm@19
|
117 y1 (+ y1 y-offset)
|
rlm@19
|
118 y2 (+ y2 y-offset)]
|
rlm@20
|
119
|
rlm@21
|
120 (let [margin (if forward? margin (- margin))]
|
rlm@21
|
121
|
rlm@21
|
122 (let [x1 (+ x1 margin)
|
rlm@21
|
123 x2 (- x2 margin)]
|
rlm@21
|
124
|
rlm@20
|
125
|
rlm@19
|
126
|
rlm@16
|
127 (str (format "G0 X%.3f Y%.3f\n"
|
rlm@19
|
128 (float x1 )
|
rlm@19
|
129 (float y1))
|
rlm@16
|
130
|
rlm@16
|
131 (format "G1 X%.3f Y%.3f\n"
|
rlm@19
|
132 (float x2)
|
rlm@21
|
133 (float y2)))))))))
|
rlm@14
|
134
|
rlm@15
|
135 (defn generate-gcode [pic]
|
rlm@15
|
136 (str (raster-preamble)
|
rlm@19
|
137 (str-join ""
|
rlm@19
|
138 (map
|
rlm@19
|
139 (fn [[index row]]
|
rlm@19
|
140 (row->gcode paramaters (even? index) row))
|
rlm@19
|
141 (indexed (make-rows pic))))
|
rlm@19
|
142 (raster-epilogue)))
|
rlm@15
|
143
|
rlm@15
|
144
|
rlm@15
|
145
|
rlm@15
|
146
|
rlm@15
|
147
|
rlm@15
|
148
|
rlm@15
|
149
|
rlm@15
|
150
|
rlm@15
|
151
|
rlm@15
|
152
|
rlm@15
|
153
|
rlm@15
|
154
|
rlm@15
|
155
|
rlm@15
|
156
|
rlm@15
|
157
|
rlm@15
|
158
|
rlm@15
|
159
|
rlm@15
|
160
|
rlm@15
|
161
|
rlm@7
|
162 (defn gather-row [row]
|
rlm@7
|
163 (let [base [[(first (first row)) (first (first row))]]]
|
rlm@7
|
164 ; (println base)
|
rlm@7
|
165 (reduce
|
rlm@7
|
166 (fn colapse [collection new-n]
|
rlm@7
|
167
|
rlm@7
|
168 (let [collection (apply vector collection)
|
rlm@7
|
169 prevoius (last (last collection))
|
rlm@7
|
170 range-start (first (last collection))]
|
rlm@7
|
171 ; (println new-n)
|
rlm@7
|
172 ; (println prevoius)
|
rlm@7
|
173 ; (println range-start)
|
rlm@7
|
174 (if (<= new-n (+ prevoius 1))
|
rlm@11
|
175 (do ;(println "join")
|
rlm@7
|
176 ;(println (butlast collection))
|
rlm@11
|
177 (conj (apply vector (butlast collection))
|
rlm@11
|
178 (vector range-start new-n)))
|
rlm@11
|
179 (conj collection (vector new-n new-n)))))
|
rlm@7
|
180
|
rlm@7
|
181 base
|
rlm@11
|
182 (map first row))))
|
rlm@11
|
183
|
rlm@7
|
184
|
rlm@7
|
185
|
rlm@7
|
186
|
rlm@21
|
187 (defn row->gmask [{:keys [x-dpi y-dpi margin x-offset y-offset]} forward? row]
|
rlm@11
|
188 (let [start (float (* (/ x-dpi) (first (first
|
rlm@11
|
189 (if forward?
|
rlm@21
|
190 (reverse row) row)))))
|
rlm@21
|
191 start (+ start x-offset)
|
rlm@21
|
192 ]
|
rlm@11
|
193 (let [preamble (if-not forward?
|
rlm@7
|
194 (format "0 0 0 %.3f\n" start)
|
rlm@11
|
195 (format "0 0 1 %.3f\n" start))
|
rlm@7
|
196 body
|
rlm@11
|
197 (for [[x y]
|
rlm@11
|
198 (if forward?
|
rlm@11
|
199 (reverse (gather-row row))
|
rlm@11
|
200 (gather-row row))]
|
rlm@7
|
201 (let [x (float (* x (/ x-dpi)))
|
rlm@21
|
202 y (float (* y (/ x-dpi)))
|
rlm@21
|
203 x (+ x x-offset)
|
rlm@21
|
204 y (+ y y-offset)
|
rlm@21
|
205
|
rlm@21
|
206
|
rlm@21
|
207
|
rlm@21
|
208
|
rlm@21
|
209 ]
|
rlm@21
|
210
|
rlm@21
|
211
|
rlm@11
|
212 (if-not forward?
|
rlm@7
|
213 (str (format "0 0 1 %.3f\n" x)
|
rlm@7
|
214 (format "0 1 1 %.3f\n" y))
|
rlm@7
|
215
|
rlm@11
|
216 (str (format "0 0 0 %.3f\n" y)
|
rlm@11
|
217 (format "0 1 0 %.3f\n" x)))))]
|
rlm@7
|
218
|
rlm@7
|
219 (str preamble (str-join "" body)))))
|
rlm@7
|
220
|
rlm@7
|
221
|
rlm@7
|
222 (defn generate-gmask [pic]
|
rlm@7
|
223 (str "1 0 0 0\n"
|
rlm@8
|
224 (str-join "" (map (fn [[index row]]
|
rlm@21
|
225 (row->gmask paramaters (even? index) row))
|
rlm@8
|
226 (indexed (make-rows pic))))))
|
rlm@8
|
227
|
rlm@11
|
228
|
rlm@11
|
229
|
rlm@8
|
230
|
rlm@8
|
231 ;;;; testing
|
rlm@8
|
232
|
rlm@15
|
233 (defn generate-files [pic]
|
rlm@15
|
234 (println "made-image")
|
rlm@15
|
235 (spit "/home/r/kevin/out.ngc" (generate-gcode pic))
|
rlm@15
|
236 (println "/home/r/kevin/out.ngc")
|
rlm@15
|
237 (spit "/home/r/kevin/out.gmask" (generate-gmask pic))
|
rlm@15
|
238 (println "/home/r/kevin/out.gmask")
|
rlm@15
|
239 pic)
|
rlm@8
|
240
|
rlm@15
|
241 (defn update-state []
|
rlm@15
|
242 (def sing "/home/r/kevin/sing.png")
|
rlm@20
|
243 (def pic (frame-hash (mirror (ImagePlus. sing))))
|
rlm@19
|
244 (def pic (b&w pic)))
|
rlm@8
|
245
|
rlm@19
|
246 (defn compare-gen-fn [n f cmp]
|
rlm@15
|
247 (let [theirs (re-split #"\n" (slurp cmp))
|
rlm@15
|
248 ours (re-split #"\n" (f pic))]
|
rlm@15
|
249 (println (format "%1$-25s%2$s" "OURS" "THEIRS"))
|
rlm@15
|
250 (println "_______________________________________")
|
rlm@15
|
251 (dorun (map (fn [[us them]] (println
|
rlm@15
|
252 (format "%1$-25s%2$s" us them)))
|
rlm@19
|
253 (take n (partition 2 (interleave ours theirs)))))))
|
rlm@8
|
254
|
rlm@19
|
255 (defn compare-gcode [n]
|
rlm@19
|
256 (compare-gen-fn n generate-gcode "/home/r/kevin/reference.ngc"))
|
rlm@19
|
257 (defn compare-gmask [n]
|
rlm@19
|
258 (compare-gen-fn n generate-gmask "/home/r/kevin/reference.gmask"))
|
rlm@15
|
259
|
rlm@8
|
260
|
rlm@8
|
261
|
rlm@8
|
262
|
rlm@8
|
263
|