我正在尝试在ClojureScript中编写一个函数,它返回给定ImageData对象的平均RGBA值。
在JavaScript中,使用“for”或“while”循环实现此问题的速度非常快。在几毫秒内,它们返回例如平均值。 4000 x 4000大小的ImageData对象。
在ClojureScript中,我的解决方案并不是那么快,有时浏览器会放弃产生“堆栈跟踪错误”。
然而,到目前为止我写的最快的是这一个:
(extend-type js/Uint8ClampedArray
ISeqable
(-seq [array] (array-seq array 0)))
(defn average-color [img-data]
(let [data (.-data img-data)
nr (/ (count data) 4)]
(->> (reduce (fn [m v] (-> (update-in m [:color (rem (:pos m) 4)] (partial + v))
(update-in [:pos] inc)))
{:color [0 0 0 0] :pos 0}
data)
(:color)
(map #(/ % nr)))))
嗯,不幸的是它只能达到500x500左右的值,这是不可接受的。
我问自己这里究竟是什么问题。为了在ClojureScript中编写适当快速的平均颜色函数,我必须参加什么。
答案 0 :(得分:1)
问题是你定义的函数是递归的。我在clojurescript中并不强大,所以我不会告诉你如何修复代码中的问题但是在概念上。
您需要将问题分解为更小的递归单位。因此,减少像素行以获得每行的结果,然后减少行结果。这将防止递归在javascript中溢出调用堆栈。
至于速度,这将取决于你想要的结果的准确度,我会使用随机样本随机选择10%的像素并使用该结果的平均值。
你也可以只使用硬件并将图像缩小一半,然后再平滑渲染然后再减半,直到你有一个像素并使用该像素的值。这将给你一个像素值的平均值,并且非常快,但只有一个值意味着,而不是一个光子平均值。
我将指出RGB通道的值是对数的,表示捕获的光子计数(用于照片)或发射(通过屏幕)的平方根。因此,像素值的平均值远低于光子计数的平均值。要获得正确的均值,您必须得到每个通道的平方的平均值,然后得到平均值的平方根,使其恢复到用于RGB值的对数标度。