Show image and generate palette via k-means
This commit is contained in:
parent
e5e97e14e0
commit
3ab1571add
4 changed files with 3229 additions and 10 deletions
5
deps.edn
5
deps.edn
|
|
@ -1,3 +1,6 @@
|
|||
{:deps {clojure2d {:mvn/version "1.4.0-SNAPSHOT"}
|
||||
enlive {:mvn/version "1.1.6"}
|
||||
clj-http {:mvn/version "3.10.1"}}}
|
||||
clj-http {:mvn/version "3.10.1"}
|
||||
generateme/fastmath {:mvn/version "2.0.3"}}
|
||||
:aliases {:docs {:extra-deps {marginalia {:mvn/version "0.9.1"}}
|
||||
:main-opts ["-m" "heyarne.vanilla-sky.marginalia"]}}}
|
||||
|
|
|
|||
3105
docs/uberdoc.html
Normal file
3105
docs/uberdoc.html
Normal file
File diff suppressed because one or more lines are too long
40
src/heyarne/vanilla_sky/marginalia.clj
Normal file
40
src/heyarne/vanilla_sky/marginalia.clj
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
(ns heyarne.vanilla-sky.marginalia
|
||||
(:gen-class)
|
||||
(:require [marginalia.parser :as p]
|
||||
[marginalia.core :refer [run-marginalia find-processable-file-paths]]
|
||||
[marginalia.html :refer [*resources*]]
|
||||
[clojure.string :as str]))
|
||||
|
||||
;; taken from https://gist.github.com/genmeblog/14a03bf7ee67f3435376e482e3981759
|
||||
(defn- code-block
|
||||
"Create code block from given string `s`"
|
||||
[s]
|
||||
(str "\n```clojure\n" s "\n```\n\n"))
|
||||
|
||||
(defn save-md
|
||||
"Save markdown built from clojure source"
|
||||
[filename]
|
||||
(let [target (str (second (re-find #"(.*)\.(\w+)$" filename)) ".md")]
|
||||
(spit target "")
|
||||
(doseq [{:keys [docstring raw form type] :as all} (p/parse-file filename)]
|
||||
(spit target
|
||||
(condp = type
|
||||
:code (str docstring (code-block raw))
|
||||
:comment (if (str/starts-with? raw "=>")
|
||||
(str "Result:" (code-block raw))
|
||||
(str raw "\n\n")))
|
||||
:append true))))
|
||||
|
||||
;; taken from https://github.com/gdeer81/marginalia/blob/master/src/marginalia/main.clj
|
||||
(defn generate-html [sources]
|
||||
(binding [*resources* ""]
|
||||
(run-marginalia sources)
|
||||
(shutdown-agents)))
|
||||
|
||||
(defn -main [& sources]
|
||||
(generate-html
|
||||
(if (seq sources)
|
||||
sources
|
||||
(find-processable-file-paths "./src" #(re-find #"\.clj[sc]?$" %))))
|
||||
|
||||
#_(save-md (first args)))
|
||||
|
|
@ -10,17 +10,20 @@
|
|||
|
||||
(require '[clj-http.client :as http])
|
||||
(require '[net.cgrand.enlive-html :as html])
|
||||
(require 'hashp.core)
|
||||
|
||||
(defn fetch-url [url]
|
||||
(future (html/html-snippet (:body (http/get url)))))
|
||||
|
||||
;; here are some hand-picked webcams:
|
||||
;; colorado springs: https://www.insecam.org/en/view/481423/
|
||||
;; salzburg: https://www.insecam.org/en/view/540433/
|
||||
;; not madrid: https://www.insecam.org/en/view/856408/
|
||||
;; colorado springs, usa: https://www.insecam.org/en/view/481423/
|
||||
;; salzburg, austria: https://www.insecam.org/en/view/540433/
|
||||
;; not madrid, spain: https://www.insecam.org/en/view/856408/
|
||||
;; florence, italy: https://www.insecam.org/en/view/866450/
|
||||
;; portoferaio, italy: https://www.insecam.org/en/view/870342/
|
||||
|
||||
(def some-detail-page
|
||||
@(fetch-url "https://www.insecam.org/en/view/856408/"))
|
||||
@(fetch-url "https://www.insecam.org/en/view/870342/"))
|
||||
|
||||
(def some-camera-image
|
||||
(->
|
||||
|
|
@ -77,6 +80,7 @@
|
|||
|
||||
;; if you need a refresher what multipart messages look like:
|
||||
;; https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
|
||||
;; We need this for mjpeg streams: https://en.wikipedia.org/wiki/Motion_JPEG#M-JPEG_over_HTTP
|
||||
|
||||
(defn parse-multipart-alternative [body]
|
||||
(let [parsed (partition-with-seq (map int [\return \newline \return \newline]) body)]
|
||||
|
|
@ -127,10 +131,77 @@
|
|||
(with-open [in (java.io.ByteArrayInputStream. bs)]
|
||||
(javax.imageio.ImageIO/read in)))
|
||||
|
||||
(def img (byte-array->image (:body first-multipart-chunk)))
|
||||
(def canvas (c2d/canvas (c2d/width img) (c2d/height img)))
|
||||
(def img (byte-array->image webcam-picture))
|
||||
(def aspect-ratio (/ (c2d/width img) (c2d/height img)))
|
||||
|
||||
(c2d/with-canvas [c canvas]
|
||||
(c2d/image c img))
|
||||
(def width (min 640 (c2d/width img)))
|
||||
(def height (int (/ width aspect-ratio)))
|
||||
|
||||
(c2d/show-window canvas "Hello World")
|
||||
(def canvas (c2d/canvas width height))
|
||||
|
||||
(defn place-image [canvas img]
|
||||
(c2d/with-canvas [c canvas]
|
||||
(->> (c2d/resize img width height)
|
||||
(c2d/image c))))
|
||||
|
||||
(place-image canvas img)
|
||||
|
||||
(c2d/show-window canvas "Webcam Image")
|
||||
|
||||
;; now that we have the image, let's generate the palette.
|
||||
;; how about we start with some pixel sorting?
|
||||
|
||||
(require '[clojure2d.pixels :as pix])
|
||||
(require '[clojure2d.color :as col])
|
||||
(require '[clojure2d.extra.utils :as util])
|
||||
|
||||
(def playground (c2d/canvas (c2d/width canvas) (c2d/height canvas)))
|
||||
(place-image playground img)
|
||||
|
||||
#_(let [pixels (pix/to-pixels canvas)]
|
||||
(pix/set-canvas-pixels! canvas (pix/filter-channels pix/dilate pixels)))
|
||||
|
||||
(pix/set-canvas-pixels!
|
||||
playground
|
||||
(let [filter (fn [p x y] (pix/get-color p x (+ y 75)))]
|
||||
(binding [pix/*pixels-edge* :wrap]
|
||||
(pix/filter-colors-xy filter (pix/to-pixels playground)))))
|
||||
|
||||
(defn hsv-colors [pixels]
|
||||
(->>
|
||||
(map #(-> (pix/get-color pixels %)
|
||||
(col/to-HSV*)) (range (count pixels)))
|
||||
(sort-by (juxt #(nth % 0) #(nth % 2) #(nth % 1)))))
|
||||
|
||||
(let [src (pix/to-pixels playground)
|
||||
dst (pix/clone-pixels src)
|
||||
sorted (->>
|
||||
(hsv-colors src)
|
||||
(sort-by (juxt #(nth % 1) #(nth % 0) #(nth % 2) ))
|
||||
(map col/from-HSV*))]
|
||||
(doseq [[idx col] (map-indexed vector sorted)]
|
||||
(pix/set-color! dst idx col))
|
||||
(pix/set-canvas-pixels! playground dst))
|
||||
|
||||
(c2d/show-window playground "Pixel Manipulation")
|
||||
|
||||
;; ok so that's how pixel access works in generl, quote straight forward.
|
||||
;; how about we try some k-means clustering on the colors?
|
||||
|
||||
(require '[fastmath.core :as m])
|
||||
(require '[fastmath.clustering :as cluster])
|
||||
|
||||
;; white and black are oftentimes used for informational overlays. they aren't
|
||||
;; really part of the scenery, except for some very dark or maybe very
|
||||
;; hazy conditions.
|
||||
|
||||
(def colors (->> (hsv-colors (pix/to-pixels playground))
|
||||
(remove #{(col/color :white) (col/color :black)})))
|
||||
|
||||
(def palette
|
||||
(->> (cluster/k-means colors 16)
|
||||
(:representatives)
|
||||
(map (comp col/from-HSV* col/color))
|
||||
(sort-by (comp (juxt first last) col/to-HSB*))))
|
||||
|
||||
(util/show-palette palette)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue