javascript - ClojureScript:从 ImagaData 获取平均 RGBA 颜色

标签 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 左右的值,这是 Not Acceptable 。

我问自己这里到底出了什么问题。为了在 ClojureScript 中编写一个适当快速的平均颜色函数,我必须注意什么。

最佳答案

问题是您定义的函数是递归的。我不擅长 clojurescript,所以我不会告诉你如何在代码中解决问题,而是在概念上解决问题。

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

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

您也可以只使用硬件并将图像缩放一半,打开平滑渲染,然后再次减半,直到获得一个像素并使用该像素的值。这将为您提供像素值平均值,并且速度非常快,但仅表示值的平均值,而不是光子的平均值。

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

关于javascript - ClojureScript:从 ImagaData 获取平均 RGBA 颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34899108/

相关文章:

javascript - AngularJS : Service not Returning Variables to Controllers

javascript - 如何在 ESC/P 打印机正确解释的 javascript 数组中写入大于 7 位 (7F) 的十六进制转义序列?

javascript - 如何将变量分配给函数内的别名 Controller ?

javascript - 在嵌套数组中创建带有 javascript 错误的游戏

javascript - Canvas toDataUrl 的跨源访问失败

Javascript 方法语法 - lowerUpper 格式的正确术语

clojure - 增加原子的值

clojurescript - 您如何从 clojurescript 引用 javascript 的 this 关键字?

clojurescript - Elm 与 ClojureScript 相比如何?

javascript - 排列元素点击优先级