comparison src/laser/rasterize.clj @ 19:3b255dcd6c50

getting closer
author Robert McIntyre <rlm@mit.edu>
date Mon, 30 Aug 2010 00:09:06 -0400
parents 962e223bab0d
children 6bed8ceb51a9
comparison
equal deleted inserted replaced
18:a769347618a1 19:3b255dcd6c50
1 (ns laser.rasterize 1 (ns laser.rasterize
2 (:use [rlm 2 (:use [rlm
3 image-utils 3 image-utils
4 map-utils] 4 map-utils]
5 [clojure.contrib 5 [clojure.contrib
6 [str-utils :only [str-join re-gsub]] 6 [str-utils :only [str-join re-gsub re-split]]
7 [seq :only [indexed]] 7 [seq :only [indexed]]
8 [math] 8 [math]])
9 [def]
10 ])
11 (:import [ij ImagePlus IJ])) 9 (:import [ij ImagePlus IJ]))
12 10
13 ;(import '(java.io File)) 11 ;(import '(java.io File))
14 ;(import '(org.apache.commons.io FileUtils)) 12 ;(import '(org.apache.commons.io FileUtils))
15 ;(import '(javax.imageio ImageIO) ) 13 ;(import '(javax.imageio ImageIO) )
16 14
17 15
18 (set! *print-length* 20) 16 (set! *print-length* 20)
19 (def feed 120) 17 (def feed 120)
20 (def dpi [500, 500]) 18 (def dpi [500, 500])
21 19 (def paramaters {:x-dpi 500 :y-dpi 500 :margin 0 :x-offset 1 :y-offset 1})
22 (def paramaters {:x-dpi 500 :y-dpi 500 :margin 0 :x-offset 0 :y-offset 0})
23 20
24 ;;; this process is divided into two tasks, 21 ;;; this process is divided into two tasks,
25 ;;; creating the raster g-code, which sweeps back and forth 22 ;;; creating the raster g-code, which sweeps back and forth
26 ;;; and creating the gmask, which turns the laser on and off. 23 ;;; and creating the gmask, which turns the laser on and off.
27 24
28 25
29 ;;; we'll be using frame-hashes, which represent picutres as 26 ;;; we'll be using frame-hashes, which represent picutres as
30 ;;; a 3D vector field over 2D space, with the vectors representing 27 ;;; a 3D vector field over 2D space, with the vectors representing
31 ;;; the rgb values at that particular point. 28 ;;; the rgb values at that particulat point.
32 29
33 (defn select-row 30 (defn select-row
34 "returns a frame hash that is just a single line at the chosen y" 31 "returns a frame hash that is just a single line at the chosen y"
35 [y window] 32 [y window]
36 (reduce 33 (filter-keys (comp (partial = y) last) window))
37 (fn [old-map number]
38 (let [pixel (get window [number y] nil)]
39 (if-not (nil? pixel)
40 (into old-map {[number y] pixel})
41 old-map)))
42 {}
43 (range (width window))))
44 34
45 (defn make-rows [pic] 35 (defn make-rows [pic]
46 (map (partial sort #(< (first %1) (first %2))) 36 (map (partial sort #(< (first %1) (first %2)))
47 (partition-by last 37 (partition-by last
48 (sort (fn [[x1 y1][x2 y2]] (> y2 y1)) 38 (sort (fn [[x1 y1][x2 y2]] (> y2 y1))
49 (map first (filter-vals (partial = black) pic)))))) 39 (map first (filter-vals (partial = black) pic))))))
50 40
41
51 ;;; generate rastering g-code 42 ;;; generate rastering g-code
52 43
53 (defn raster-preamble [] 44 (defn raster-preamble []
54 (str-join \newline ["M63 P0\nG61" (str "F" feed) "M101" "M3 S1\n"])) 45 (str-join \newline
46 ["M63 P0\nG61"
47 (str "F" feed)
48 "M101"
49 "M3 S1\n"]))
55 50
56 (defn raster-epilogue [] 51 (defn raster-epilogue []
57 (str-join \newline ["M63 P0" "M5" "M2\n"])) 52 (str-join \newline
58 53 ["M63 P0"
59 (defn raster-comment 54 "M5"
60 "wrap a statement in PARENTHENSIS to make it a comment in gcode. 55 "M2\n"]))
61 parenthesis themselves aren't allowed in comments. 56
62 Oh the humanity!!" 57 (defn raster-comment [string]
63 [string]
64 (str "(" (re-gsub #"[()]" "" string) ")")) 58 (str "(" (re-gsub #"[()]" "" string) ")"))
65 59
66 (defn rows 60
67 "creates a sequence of one dimensional vector fields which 61 ;this is a sequence of rows
68 represent the rows of a picture" 62
69 [pic] 63 ;(defn span [row]
70 (let [non-empty-rows (apply sorted-set (map (comp last first) pic))] 64 ; (let [sorted-row (sort #(< (first %1) (first %2)) row)]
71 (pmap (fn [n] (select-row n pic)) non-empty-rows))) 65 ; (vector (first sorted-row) (last sorted-row))))
72 66
67
68
69 (defn row->gcode [{:keys [x-dpi y-dpi margin x-offset y-offset]} forward? row]
73 70
74 71 (let [[x1 y1] (if forward? (last row) (first row))
75 72 [x2 y2] (if forward? (first row) (last row))]
76 73
77 (defn row->gcode [{:keys [x-dpi y-dpi margin x-offset y-offset]} row] 74 (let [x1 (* x1 (/ x-dpi))
78 (let [pixels (keys row) 75 x2 (* x2 (/ x-dpi))
79 x2 0 76 y1 (* y1 (/ y-dpi))
80 [_ y2] (first pixels) 77 y2 (* y2(/ y-dpi))]
81 [_ y1] (first pixels) 78
82 x1 533] 79 (let [x1 (+ x1 x-offset)
83 80 x2 (+ x2 x-offset)
84 ;(let [ordered-row 81 y1 (+ y1 y-offset)
85 ; (sort-map-by (fn [[x1 _] [x2 _]] (> x2 x1)) row)] 82 y2 (+ y2 y-offset)]
86 83
87 (let [;[x1 y1] (last (keys ordered-row)) 84
88 ;[x2 y2] (first (keys ordered-row))
89 [x1 y1 x2 y2] (if (odd? y1) [x2 y2 x1 y1] [x1 y1 x2 y2])]
90
91 (str (format "G0 X%.3f Y%.3f\n" 85 (str (format "G0 X%.3f Y%.3f\n"
92 (float (* x1 (/ x-dpi))) 86 (float x1 )
93 (float (* y1 (/ y-dpi)))) 87 (float y1))
94 88
95 (format "G1 X%.3f Y%.3f\n" 89 (format "G1 X%.3f Y%.3f\n"
96 (float (* x2 (/ x-dpi))) 90 (float x2)
97 (float (* y2 (/ y-dpi)))))))) 91 (float y2)))))))
98
99
100 (defn pic->gcode [paramaters pic]
101 (reduce (fn [gcode current-height]
102 (let [current-row (select-row current-height pic)]
103 (if-not (empty? current-row)
104 (let [new-code (row->gcode paramaters current-row)]
105 (println new-code)
106 (str gcode new-code))
107 gcode)))
108 ""
109 (range (height pic))))
110
111
112
113
114 (defn pic->gcode
115
116
117
118 ;(defn pic->gcode [paramaters pic]
119 92
120
121 (defn generate-gcode [pic] 93 (defn generate-gcode [pic]
122 (str (raster-preamble) 94 (str (raster-preamble)
123 (row->gcode paramaters pic) 95 (str-join ""
124 (raster-epilogue))) 96 (map
97 (fn [[index row]]
98 (row->gcode paramaters (even? index) row))
99 (indexed (make-rows pic))))
100 (raster-epilogue)))
125 101
126 102
127 103
128 104
129 105
210 (println "/home/r/kevin/out.gmask") 186 (println "/home/r/kevin/out.gmask")
211 pic) 187 pic)
212 188
213 (defn update-state [] 189 (defn update-state []
214 (def sing "/home/r/kevin/sing.png") 190 (def sing "/home/r/kevin/sing.png")
215 (def pic (frame-hash (ImagePlus. sing))) 191 (def pic (frame-hash (rotate 180 (ImagePlus. sing))))
216 (def pic (b&w pic)) 192 (def pic (b&w pic)))
217 (def pic (filter-vals (partial = black) pic))) 193
218 194 (defn compare-gen-fn [n f cmp]
219 (defn compare-gen-fn
220 ([n f cmp]
221 (let [theirs (re-split #"\n" (slurp cmp)) 195 (let [theirs (re-split #"\n" (slurp cmp))
222 ours (re-split #"\n" (f pic))] 196 ours (re-split #"\n" (f pic))]
223 (println (format "%1$-25s%2$s" "OURS" "THEIRS")) 197 (println (format "%1$-25s%2$s" "OURS" "THEIRS"))
224 (println "_______________________________________") 198 (println "_______________________________________")
225 (dorun (map (fn [[us them]] (println 199 (dorun (map (fn [[us them]] (println
226 (format "%1$-25s%2$s" us them))) 200 (format "%1$-25s%2$s" us them)))
227 (take n (partition 2 (interleave ours theirs)))))))) 201 (take n (partition 2 (interleave ours theirs)))))))
228 202
229 (defn compare-gcode 203 (defn compare-gcode [n]
230 ([] (compare-gcode 25)) 204 (compare-gen-fn n generate-gcode "/home/r/kevin/reference.ngc"))
231 ([n] (compare-gen-fn n generate-gcode "/home/r/kevin/reference.ngc"))) 205 (defn compare-gmask [n]
232 206 (compare-gen-fn n generate-gmask "/home/r/kevin/reference.gmask"))
233 (defn compare-gmask
234 ([] compare-gmask 25)
235 ([n] (compare-gen-fn n generate-gmask "/home/r/kevin/reference.gmask")))
236 207
237 208
238 209
239 210
240 211