我正在尝试在 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 左右的值,这是 Not Acceptable 。
我问自己这里到底出了什么问题。为了在 ClojureScript 中编写一个适当快速的平均颜色函数,我必须注意什么。
最佳答案
问题是您定义的函数是递归的。我不擅长 clojurescript,所以我不会告诉你如何在代码中解决问题,而是在概念上解决问题。
您需要将问题分解为更小的递归单元。因此,减少像素行以获得每行的结果,然后减少行结果。这将防止递归溢出 javascript 中的调用堆栈。
至于速度,这取决于您希望结果的准确程度,我会使用随机样本,随机选择 10% 的像素并使用该结果的平均值。
您也可以只使用硬件并将图像缩放一半,打开平滑渲染,然后再次减半,直到获得一个像素并使用该像素的值。这将为您提供像素值平均值,并且速度非常快,但仅表示值的平均值,而不是光子的平均值。
我要指出的是,RGB channel 的值是对数的,代表捕获(对于照片)或发射(通过屏幕)的光子计数的平方根。因此,像素值的平均值远低于光子计数的平均值。要获得正确的平均值,您必须获取每个 channel 的平方平均值,然后获取平均值的平方根,以将其返回到用于 RGB 值的对数刻度。
关于javascript - ClojureScript:从 ImagaData 获取平均 RGBA 颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34899108/