Mercurial > lasercutter
view src/laser/rasterize.clj @ 8:0f48db8d2a05
going to upgrade to clojure 1.2
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 03:21:22 -0400 |
parents | 5e167f275a93 |
children | f952052e37b7 |
line wrap: on
line source
1 (ns laser.rasterize)3 (import '(java.io File))4 (import '(org.apache.commons.io FileUtils))5 (import '(javax.imageio ImageIO) )6 (import '(javax.swing JFrame))7 (import '(java.awt Color BorderLayout))8 (import '(ij ImagePlus IJ))9 (import '(java.lang Math))10 (import '(java.awt Graphics2D Panel))11 (import '(ij Macro))13 (import '(java.io BufferedReader InputStreamReader))14 (import '(java.awt.image BufferedImage))16 (use 'clojure.contrib.str-utils)17 (use 'clojure.contrib.seq-utils)18 (use 'clojure.contrib.combinatorics)19 (use 'clojure.contrib.duck-streams)21 (use 'clojure.contrib.repl-utils)23 (set! *print-length* 20)28 (def feed 120)29 (def dpi [500, 500])34 (defn preserve-meta [f]35 (fn [& x] (with-meta36 (apply f x)37 (meta (last x)))))39 (defmulti frame-hash-multi class)42 (defmethod frame-hash-multi ImagePlus43 [image+]44 (with-meta45 (let [buf (.. image+ getBufferedImage)46 color (.getColorModel buf)]47 (apply hash-map48 (interleave49 (doall (for [x (range (.getWidth image+)) y (range (.getHeight image+))]50 (vector x y)))51 (doall (for [x (range (.getWidth image+)) y (range (.getHeight image+))]52 (let [data (.getRGB buf x y)]53 (hash-map :r (bit-shift-right (bit-and 0xff0000 data) 16)54 :g (bit-shift-right (bit-and 0x00ff00 data) 8)55 :b (bit-and 0x0000ff data))))))))56 {:width (.getWidth image+) :height (.getHeight image+)}))59 (defmethod frame-hash-multi String60 [image-name]61 (let [image+ (ImagePlus. image-name)]62 (frame-hash-multi image+)))65 (defn frame-hash66 "yields a convienent representation for the pixles in an image.67 Because of the size of the structvre generated, this must only be used68 in a transient way so that java can do it's garbage collection."69 [something]70 (frame-hash-multi something))72 ;(def frame-hash (preserve-meta frame-hash))77 (def white {:r 255, :g 255, :b 255})78 (def black {:r 0, :g 0, :b 0})80 (def expt #(Math/pow %1 %2))82 (defn rgb-euclidian83 [{r1 :r g1 :g b1 :b} {r2 :r g2 :g b2 :b} ]84 (expt (+ (expt (- r1 r2) 2)85 (expt (- g1 g2) 2)86 (expt (- b1 b2) 2)) 0.5))88 (defn b&w89 "turn everything strictly black or white"90 [window]91 (with-meta92 (zipmap93 (keys window)94 (map (fn [rgb]95 (if (> (rgb-euclidian rgb white) (rgb-euclidian rgb black))96 black white))97 (vals window))) (meta window)))101 (defn raster-preamble []102 (str-join \newline103 ["M63 P0\nG61"104 (str \F feed)105 "M101"106 "M3 S1\n"]))108 (defn raster-epilogue []109 (str-join \newline110 ["M63 P0"111 "M5"112 "M2\n"]))115 (defn raster-comment [string]116 (str "(" (re-gsub #"[()]" "" string) ")"))118 (defn filter-keys [fun m]119 (select-keys m (filter fun (keys m))))121 (def filter-keys (preserve-meta filter-keys))123 (defn filter-vals [fun m]124 (into {} (filter (comp fun val) m)))126 (def filter-vals (preserve-meta filter-vals))128 (defn frame-hash->bufferedImage129 [frame-hash]130 (let [data (meta frame-hash)131 image (BufferedImage. (:width data) (:height data) BufferedImage/TYPE_INT_BGR)]133 (doall (for [element frame-hash]134 (let [coord (key element)135 rgb (val element)136 packed-RGB137 (+ (bit-shift-left (:r rgb) 16)138 (bit-shift-left (:g rgb) 8)139 (:b rgb))]140 (.setRGB image (first coord) (last coord) packed-RGB))))141 image))143 (defmulti display "Creates a JFrame and displays a buffered image" class)145 (defn- makePanel [image] (proxy [Panel] [] (paint [g] (.drawImage g image 0 0 nil))))147 (defn select-row [x window]148 (filter-keys (comp (partial = x) first) window))152 (defmethod display153 BufferedImage [image]154 (let [panel (makePanel image)155 frame (JFrame. "Oh Yeah!")]156 (.add frame panel)157 (.pack frame)158 (.setVisible frame true )159 (.setSize frame(.getWidth image) (.getHeight image))))161 (defmethod display162 ImagePlus [image]163 (display (.getBufferedImage image)))165 (defmethod display166 clojure.lang.PersistentHashMap [frame-hash]167 (display (frame-hash->bufferedImage frame-hash)))169 (defmethod display170 clojure.lang.PersistentArrayMap [frame-hash]171 (display (frame-hash->bufferedImage frame-hash)))177 ;this is a sequence of rows179 ;(defn span [row]180 ; (let [sorted-row (sort #(< (first %1) (first %2)) row)]181 ; (vector (first sorted-row) (last sorted-row))))184 (defn row->gcode [[x-dpi y-dpi] row]185 (let [[x1 y1] (first row)186 [x2 y2] (last row)]187 (str (format "G0 X%.3f Y%.3f\n"188 (float (* x1 (/ x-dpi)))189 (float (* y1 (/ y-dpi))))191 (format "G1 X%.3f Y%.3f\n"192 (float (* x2 (/ x-dpi)))193 (float (* y2 (/ y-dpi)))))))195 (defn gather-row [row]196 (let [base [[(first (first row)) (first (first row))]]]197 ; (println base)198 (reduce199 (fn colapse [collection new-n]201 (let [collection (apply vector collection)202 prevoius (last (last collection))203 range-start (first (last collection))]204 ; (println new-n)205 ; (println prevoius)206 ; (println range-start)207 (if (<= new-n (+ prevoius 1))208 (do ;(println "join")209 ;(println (butlast collection))210 (conj (apply vector (butlast collection)) (vector range-start new-n)))211 (conj collection (vector new-n new-n)))))213 base214 (map first row))))218 (defn row->gmask [[x-dpi y-dpi] forward? row]220 (let [start (float (* (/ x-dpi) (first (first row))))]222 (let [preamble (if forward?223 (str224 (format "0 0 0 %.3f\n" start)225 (format "0 0 1 %.3f\n" start)))226 body227 (for [[x y] (gather-row row)]228 (let [x (float (* x (/ x-dpi)))229 y (float (* y (/ x-dpi)))]230 (if forward?231 (str (format "0 0 1 %.3f\n" x)232 (format "0 1 1 %.3f\n" y))234 (str (format "0 0 0 %.3f\n" x)235 (format "0 1 0 %.3f\n" y)))))]237 (str preamble (str-join "" body)))))241 (defn make-rows [pic]243 (map (partial sort #(< (first %1) (first %2)))244 (partition-by last245 (sort (fn [[x1 y1][x2 y2]] (> y2 y1))246 (map first (filter-vals (partial = black) pic))))))250 (defn generate-gmask [pic]252 (str "1 0 0 0\n"253 (str-join "" (map (fn [[index row]]254 (row->gmask dpi (odd? index) row))255 (indexed (make-rows pic))))))257 ;; 1 0 0 0258 ;; 0 0 1 2.881259 ;; 0 0 0 2.881260 ;; 0 1 0 2.863261 ;; 0 0 0 2.769262 ;; 0 1 0 2.751263 ;; 0 0 0 2.729264 ;; 0 1 0 2.617265 ;; 0 0 0 2.593266 ;; 0 1 0 2.561267 ;; 0 0 0 2.463268 ;; 0 1 0 2.445269 ;; 0 0 0 2.385270 ;; 0 1 0 2.317271 ;; 0 0 0 2.253272 ;; 0 1 0 2.233273 ;; 0 0 0 2.177277 (defn generate-gcode [pic]278 (str (raster-preamble)281 (str-join "" (map (partial row->gcode dpi) (make-rows pic)))282 (raster-epilogue)))286 (defn rotate [degrees #^ImagePlus image]287 (.rotate (.getChannelProcessor image) degrees)288 image)290 (defn map-keys [f m]291 (into {} (map (fn [[key val]] [(f key) val]) m)))295 (defn invert-frame-hash [pic]296 (map-keys (fn [[x y]] [x (- (:height (meta pic)) y 1)]) pic ))299 (defn generate-files [pic]300 (let [image (invert-frame-hash (b&w (frame-hash (rotate 180 (ImagePlus. pic)))))]301 (spit "/home/r/kevin/out.ngc" (generate-gcode image))302 (spit "/home/r/kevin/out.gmask" (generate-gmask image))303 image))307 ;;;; testing309 (defn init []310 (let [stuff312 (bound-fn []314 (do315 (println "hi everyone")316 (def img "/home/r/kevin/sing.png")317 (def pic (frame-hash (let [image (ImagePlus. img)]318 (.rotate (.getChannelProcessor image) 180)319 image)))322 (def test-image323 (invert-frame-hash (b&w (frame-hash (rotate 180 (ImagePlus. img))))))325 (defn test-gmask []326 (println (str-join "" (take 170 (generate-gmask test-image)))))328 (println "ALL variables initialized!")330 ))]331 (.start332 (Thread. stuff))))336 (defn thread-test []338 (let [temp *out*]339 (.start340 (Thread.341 (fn []342 (with-bindings {#'clojure.core/*out* temp}343 (Thread/sleep 5000)344 (println "hi")))))))