ClojureScript:从ImagaData获取平均RGBA颜色

时间:2016-01-20 11:43:48

标签: javascript canvas clojurescript

我正在尝试在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中编写适当快速的平均颜色函数,我必须参加什么。

1 个答案:

答案 0 :(得分:1)

问题是你定义的函数是递归的。我在clojurescript中并不强大,所以我不会告诉你如何修复代码中的问题但是在概念上。

您需要将问题分解为更小的递归单位。因此,减少像素行以获得每行的结果,然后减少行结果。这将防止递归在javascript中溢出调用堆栈。

至于速度,这将取决于你想要的结果的准确度,我会使用随机样本随机选择10%的像素并使用该结果的平均值。

你也可以只使用硬件并将图像缩小一半,然后再平滑渲染然后再减半,直到你有一个像素并使用该像素的值。这将给你一个像素值的平均值,并且非常快,但只有一个值意味着,而不是一个光子平均值。

我将指出RGB通道的值是对数的,表示捕获的光子计数(用于照片)或发射(通过屏幕)的平方根。因此,像素值的平均值远低于光子计数的平均值。要获得正确的均值,您必须得到每个通道的平方的平均值,然后得到平均值的平方根,使其恢复到用于RGB值的对数标度。