[英]Average brightness with Clojure very slow
作為Clojure的新手,我想計算(很多)jpg圖像的平均亮度。 為此,我使用ImageIO/read
從Java ImageIO/read
將圖像加載到內存中,提取其背后的字節緩沖區並應用平均值。
(defn brightness
"Computes the average brightness of an image."
[^File file]
(-> file
ImageIO/read
.getRaster
.getDataBuffer
.getData
byteaverage))
在這里,平均值
(defn byteaverage
[numbers]
(/ (float
(->> numbers
(map bytetoint)
(apply +)))
(count numbers))
)
需要考慮到字節是用Java簽名的,需要先將其轉換為足夠大的整數。
(defn bytetoint
[b]
(bit-and b 0xFF)
)
雖然這確實給出了正確的結果,但它非常慢。 20萬像素圖像需要大約10到20秒。 磁盤訪問不是問題。 從玩弄time
,罪魁禍首似乎是bytetoint
轉換。 只是將此bytetoint
映射到字節數組就會占用8 GB的內存,並且不會在REPL中終止。
為什么會這樣做呢?
PS:我知道可以使用其他編程語言,庫,多線程或更改算法。 我的觀點是上面的Clojure代碼應該更快,我想理解為什么它不是。
你基本上是在一個非常緊湊的循環中運行大量的管道,例如拳擊,轉換,使用chuncked懶惰序列等。你從現代cpus中獲得的許多好處飛出窗外; 例如預加載緩存行,分支預測等。
這種循環(計算和)在更直接的計算形式方面更好地實現,例如clojure loop
結構,其形式為:
(defn get-sum [^bytes data]
(let [m (alength data)]
(loop [idx 0 sum 0]
(if (< idx m)
(recur (inc idx) (unchecked-add sum (bit-and (aget data idx) 0xff)))
(/ sum m)))))
這是未經測試的,因此您可能需要對其進行調整,但它顯示了一些內容:
您也可以使用其他形式,它們可能表現得更好,例如具有內部可變狀態的dotimes
(比如大小為1的長向量)如果你真的需要擠出性能,但到那時,你不妨寫一下java中的一個小方法;)
除了@ shlomi的回答:
你也可以使用areduce
函數減少冗長(並且可能更快):
(defn get-sum-2 [^bytes data]
(/ (areduce data i res 0
(unchecked-add res (bit-and (aget data i) 0xff)))
(alength data)))
如果您想在Java中快速完成,那么您可以使用這些選項(最好是使用所有這些選項):
對於負字節值...不要將顏色值轉換為字節,將其直接轉換為int,如:
int rgb = somePixelColor;
int b = rgb & 0xFF;
int g = (rgb>>8) & 0xFF;
int r = (rgb>>16) & 0xFF;
int sillyBrightness = (r + g + b)/3; // because each color should have a weight for calculating brightness, there are some models of that.
除了上述好的信息之外,您可能對HipHip庫感興趣,該庫專為處理來自Clojure的原始值數組而設計: https : //github.com/plumatic/hiphip
以下是自述文件中關於計算基本數組的平均值和標准偏差的示例:
(defn std-dev [xs]
(let [mean (dbl/amean xs)
square-diff-sum (dbl/asum [x xs] (Math/pow (- x mean) 2))]
(/ square-diff-sum (dbl/alength xs))))
(defn covariance [xs ys]
(let [ys-mean (dbl/amean ys)
xs-mean (dbl/amean xs)
diff-sum (dbl/asum [x xs y ys] (* (- x xs-mean) (- y ys-mean)))]
(/ diff-sum (dec (dbl/alength xs)))))
(defn correlation [xs ys std-dev1 std-dev2]
(/ (covariance xs ys) (* std-dev1 std-dev2)))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.