Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add histogram-diff command #33

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions src/cljck/color.clj
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
(ns cljck.color
(:import [java.awt.image BufferedImage Raster]))
(:require [cljck.io.sync :refer [robot]])
(:import [java.awt Rectangle]
[java.awt.image BufferedImage Raster]))

(defn image->pixels
"Converts a BufferedImage into a flat sequence of pixels. A pixel is really
Expand Down Expand Up @@ -36,9 +38,7 @@
The result would increment the buckets as follows:
[[0 0 0 0 0 0 0 1] [0 0 0 1 0 0 0 0] [1 0 0 0 0 0 0 0]]"
[[reds greens blues] [red green blue]]
[(update-buckets reds red)
(update-buckets greens green)
(update-buckets blues blue)])
(map update-buckets [reds greens blues] [red green blue]))

(defn normalize-bucket
"Takes a bucket count, divides it by the total number of pixels and multiplies
Expand All @@ -52,6 +52,27 @@
(Math/round)
int))

(defn hex->histogram
"Converts a string into a color histogram. The string is expected to conform
to the following format:

[rrrrrrrrrrrrrrrrggggggggggggggggbbbbbbbbbbbbbbbb]

where each section r, g, and b is divided into

[[hh] [hh] [hh] [hh] [hh] [hh] [hh] [hh]]

each h being a hexadecimal value. The output is a vector with 3 elements
(one for each color), each element is itself a vector with 8 elements
(dividing the color into 8 'buckets' from low to high RGB values). Each bucket
will have a value in the inclusive range [0 255]."
[hex-string]
(sequence
(comp (map (partial partition 2))
(map (partial map (partial apply str)))
(map (partial map #(Long/parseLong % 16))))
(partition 16 hex-string)))

(defn histogram
"Constructs a histogram of a given BufferedImage, which is a measure of where
in the color spectrum the pixels comprising the image fall. This is an image
Expand All @@ -75,4 +96,4 @@
(let [diff-red (reduce + (map diff red-a red-b))
diff-green (reduce + (map diff green-a green-b))
diff-blue (reduce + (map diff blue-a blue-b))]
(/ (+ diff-red diff-green diff-blue) 255 3))))
(/ (+ diff-red diff-green diff-blue) 255 3 2))))
14 changes: 14 additions & 0 deletions src/cljck/io.clj
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
(ns cljck.io
(:gen-class)
(:require
[cljck.color :refer [hex->histogram histogram histogram-diff]]
[cljck.io
[images :refer [fetch-screen]]
[keyboard :refer [press]]
[mouse :refer [click move-to mouse-pointer scroll-down scroll-up]]]
[clojure.core.async :refer [<! <!! chan go go-loop timeout]]
Expand All @@ -26,6 +28,18 @@
[_]
(click :left))

(defmethod process-event :histogram
[[_ hex-code]]
(hex->histogram hex-code))

(defmethod process-event :histogram-at
[[_ x y width height]]
(histogram (fetch-screen x y width height)))

(defmethod process-event :histogram-diff
[[_ hist1 hist2 max-diff]]
(<= (histogram-diff (process-event hist1) (process-event hist2)) max-diff))

(defmethod process-event :if
[[_ condition then else]]
(if (process-event condition)
Expand Down
17 changes: 17 additions & 0 deletions src/cljck/io/images.clj
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
(ns cljck.io.images
(:require [cljck.io.sync :refer [robot]])
(:import
[java.awt Rectangle Toolkit]
[java.awt.image BufferedImage]
[java.io File]
[javax.imageio ImageIO]))

(defn screen-resolution
"Returns the current width and height of the screen."
[]
((juxt (memfn getWidth) (memfn getHeight))
(.. Toolkit getDefaultToolkit getScreenSize)))

(defn buffered-image
"Takes a path to an image file, which is assumed available on the class path,
and constructs and returns a BufferedImage from it."
[path]
(ImageIO/read (File. ^String path)))

(defn fetch-screen
"Returns a BufferedImage of the pixels currently on the screen. Optionally
takes a rectangle to limit the fetching to."
([]
(apply fetch-screen 0 0 (screen-resolution)))
([x y width height]
(.createScreenCapture robot (Rectangle. x y width height))))