- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我编写了一个 Haskell 程序,它遍历一个文件夹并找到文件夹中每个图像的平均颜色。它使用来自 hackage 的 repa-devil 包将图像加载到 repa 数组中。我通过将所有红色、蓝色和绿色值相加然后除以像素数来找到平均值:
-- compiled with -O2
import qualified Data.Array.Repa as R
import Data.Array.Repa.IO.DevIL
import Control.Monad.Trans (liftIO)
import System.Directory (getDirectoryContents)
size :: (R.Source r e) => R.Array r R.DIM3 e -> (Int, Int)
size img = (w, h)
where (R.Z R.:. h R.:. w R.:. 3) = R.extent img
averageColour :: (R.Source r e, Num e, Integral e) => R.Array r R.DIM3 e -> (Int, Int, Int)
averageColour img = (r `div` n, g `div` n, b `div` n)
where (w, h) = size img
n = w * h
(r,g,b) = f 0 0 0 0 0
f row col r g b
| row >= w = f 0 (col + 1) r g b
| col >= h = (r, g, b)
| otherwise = f (row + 1) col (addCol 0 r) (addCol 1 g) (addCol 2 b)
where addCol x v = v + fromIntegral (img R.! (R.Z R.:. col R.:. row R.:. x))
main :: IO ()
main = do
files <- fmap (map ("images/olympics_backup/" ++) . filter (`notElem` ["..", "."])) $ getDirectoryContents "images/olympics_backup"
runIL $ do
images <- mapM readImage files
let average = zip (map (\(RGB img) -> averageColour img) images) files
liftIO . print $ average
我还使用 Python 图像库用 Python 编写了这个程序。它以相同的方式找到图像的平均值:
import Image
def get_images(folder):
images = []
for filename in os.listdir(folder):
images.append(folder + filename)
return images
def get_average(filename):
image = Image.open(filename)
pixels = image.load()
r = g = b = 0
for x in xrange(0, image.size[0]):
for y in xrange(0, image.size[1]):
colour = pixels[x, y]
r += colour[0]
g += colour[1]
b += colour[2]
area = image.size[0] * image.size[1]
r /= area
g /= area
b /= area
return [(r, g, b), filename, image]
def get_colours(images):
colours = []
for image in images:
try:
colours.append(get_average(image))
except:
continue
return colours
imgs = get_images('images/olympics_backup/')
print get_colours(imgs)
当这两个都在包含 301 张图像的文件夹上运行时,Haskell 版本的性能要高出 0.2 秒(0.87 对 0.64)。这看起来很奇怪,因为 Haskell 是一种编译语言(通常比解释型语言更快),而且我听说 repa 数组具有良好的性能(尽管这可能只是与其他 Haskell 数据类型(如列表)进行比较)。
我做的第一件事是注意到我正在使用显式递归,所以我决定用折叠替换它,这也意味着我不再需要检查我是否超出了数组的边界:
(r,g,b) = foldl' f (0,0,0) [(x, y) | x <- [0..w-1], y <- [0..h-1]]
f (r,g,b) (row,col) = (addCol 0 r, addCol 1 g, addCol 2 b)
where addCol x v = v + fromIntegral (img R.! (R.Z R.:. col R.:. row R.:. x))
这使它运行得更慢(1.2 秒),所以我决定分析代码并查看大部分时间花在哪里(以防我造成了明显的瓶颈或 repa-devil 包太慢了)。配置文件告诉我,约 58% 的时间花在 f 函数上,约 35% 的时间花在 addCol 上。
不幸的是,我想不出有什么方法可以使它运行得更快。该函数只是一个数组索引和一个加法——与 python 代码相同。有没有办法提高此代码的性能,或者 Python 图像库只是提供更高的性能?
最佳答案
虽然下面的代码有点乱,但速度还是很快的。
在 0.03 毫秒内处理 75x75 图像(16 次抽动/像素)=> 大约。 300 张图像 10-20 毫秒
512x512 (Lenna),1 毫秒(13.5 次抽动/像素)
12 毫秒内的 2560x1600(9.2 次控制/像素)
yarr
是专门为解决像您这样的任务而设计的,不幸的是有一些问题(在代码注释中指出)不允许同时使代码真正简洁和快速。
一个像素例程是 3 次内存读取 + 3 次添加
,所以我粗略地预计 3 个 tic/pixel 作为此任务的限制。
您还可以使用 parallel
轻松并行计算来自 parallel-io
包。
{-# LANGUAGE FlexibleContexts, TypeFamilies #-}
import System.Environment
import Data.Yarr
import Data.Yarr.IO.Image
import Data.Yarr.Walk
import Data.Yarr.Utils.FixedVector as V
import Data.Yarr.Shape as S
main :: IO ()
main = do
[file] <- getArgs
print =<< getAverage file
getAverage :: FilePath -> IO (Int, Int, Int)
getAverage file = do
-- Meaningful choice, for homogenious images,
-- in preference to readRGB(Vectors).
-- readRGB make the case of representation -> polymorfic access ->
-- poor performance
(RGB imageArr) <- readImage file
-- let imageArr = readRGBVectors file
let ext = extent imageArr
avs <- averageColour imageArr
return $ V.inspect avs (Fun (,,))
averageColour
:: (Vector v Int, Dim v ~ N3, Integral e,
UVecSource r slr l Dim2 v e, PreferredWorkIndex l Dim2 i)
=> UArray r l Dim2 (v e) -> IO (VecList N3 Int)
{-# INLINE averageColour #-}
averageColour image = fmap (V.map (`div` (w * h))) compSums
where -- `walk (reduce ... (V.zipWith (+))) (return V.zero) image`
-- would be more idiomatic and theoretically faster,
-- but had problems with perf too :(
compSums = walkSlicesSeparate sum (return 0) image
-- would better to `mapElems fromIntegral imageArr` before counting,
-- but faced some performance problems and I have no time to dig them
{-# INLINE sum #-}
sum = reduceL sumFold (\x y -> x + (fromIntegral y))
sumFold = S.unrolledFoldl n8 noTouch
(w, h) = extent image
编译
ghc-7.6.1 --make -Odph -rtsopts -threaded -fno-liberate-case -funbox-strict-fields -funfolding-keeness-factor1000 -fllvm -optlo-O3 -fexpose-all-unfoldings -fsimpl-tick-factor=500 -o avc average-color.hs
关于python - 使用 REPA 优化 haskell 中的平均图像颜色程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17147644/
两个相关的问题。 有没有 repa 的可变(ST monad)实现的原因?数组?相当于 Data.Vector.Mutable但有一个形状。 与此相关,应该如何在未装箱的表示中实现动态编程算法(从 相
我在 Haskell 库 Repa 中开发了一个如下定义的累积求和函数。但是,当将此功能与转置操作结合使用时,我遇到了一个问题。以下所有 3 项操作都需要不到一秒钟的时间: cumsum $ cums
在 haskell 中使用 repa,有没有一种方法可以打印矩阵,以便它们的格式很好,矩阵行位于单独的行上(大多数数值计算环境(如 R 或 matlab)的默认设置)? 我可以写一个,但它似乎已经存在
我真的很喜欢 Repa 的界面,即使它的并发能力如何。我实际上需要 repa 的数组是连续的,因为我的数组相对较小,并且它们的并行化是无用的,甚至是有害的。 但是,我确实在程序中使用了并行化,因此我将
以下代码会产生(可怕的)“嵌套并行性”错误 repa-3.4.0.1 : import Control.Monad.Identity (runIdentity, liftM) import Data.
在数值 Haskell Repa 教程中 Wiki ,有一段文字如下(用于上下文): 10.1 Fusion, and why you need it Repa depends critically
最好的制作方法是什么 type Configuration = Array DIM1 (Double, Double, Double) Read 的一个实例?所以后来我可以得出 data Simula
我想知道repa中是否有(//)的类似物? 无法并行化的数组转换需要它。例如,如果函数需要整个数组来更改数组的单个条目,然后将其应用于新数组等等(并且它应该按顺序运行)。 最佳答案 (//)可以用Da
问题 我试图了解 Repa工作,我从 Repa Examples 得到一个“模糊”示例代码。包裹。代码使用 stencil2 Quasi Quote : [stencil2| 2 4 5 4
我正在编写一个生成图像的程序,我想将其带入 Repa 数组。我目前使用的类型: data Colour = Colour Double Double Double 来表示像素,我有一个(可能效率低下但
我想实现类似于标准数组包中的有界数组但使用 repa 数组的东西。 实现这一目标的好方法是什么? 这是我尝试过的,但必须有比将所有内容包装在检查边界的自定义函数中更好的方法: import Data
假设我想使用有限差分法为看涨期权定价 然后再做以下工作: import Data.Array.Repa as Repa r, sigma, k, t, xMax, deltaX, deltaT ::
我使用 Euler symplectic method 编写了太阳系外行星的模拟。并使用 repa 和 b) 使用 yarr 实现了这一点。 yarr seems to perform about x
在我最近的 work与 Gibbs sampling ,我一直在充分利用 RVar 在我看来,它为随机数生成提供了一个近乎理想的接口(interface)。遗憾的是,由于无法在 map 中使用 mon
我正在尝试使用 Repa 实现累积和函数以计算积分图像。我当前的实现如下所示: cumsum :: (Elt a, Num a) => Array DIM2 a -> Array DIM2 a cum
我正在从磁盘加载 RGB 图像 JuicyPixels-repa 。不幸的是,图像的数组表示是 Array F DIM3 Word8其中内部维度是 RGB 像素。这与现有的repa有点不兼容。 RGB
假设我想将一个函数映射到一个数组上,但该函数的类型不仅仅是 a -> b但 a -> 整数 -> b即该函数还需要一个索引。我该怎么做? 最佳答案 简短回答,使用遍历。 更长的例子: import q
问题 我正在寻找 repa 库中可能已经存在的函数。我想要一个功能: 接受一个二维数组 指定窗口大小的两个整数 在二维数组上给定大小的每个窗口中,计算一个新值,例如此特定窗口中的小值。 例子 用 3x
Repa的所有归约函数折叠回与数组内容相同的类型。例如: foldAllP :: (Shape sh, Source r a, Elt a, Unbox a, Monad m) => (a -> a
在 GNU Octave 中此代码 - [e, ix] = min(X); 将返回最小元素及其位置。 如何在 repa 中实现任意二进制函数? 这是我想到的: min x = z $ foldl' f
我是一名优秀的程序员,十分优秀!