【问题标题】:How can I optimize this haskell function我怎样才能优化这个haskell函数
【发布时间】:2014-01-14 04:15:16
【问题描述】:

我需要在调色板ps 中找到与给定颜色p 最接近的颜色。如何在不更改类型的情况下尽快使函数nearestColor Pixel8PixelRGB8。到目前为止,我已经尝试过内联。

import qualified Data.Vector as V

type Pixel8 = Word8    

data PixelRGB8 = PixelRGB8 {-# UNPACK #-} !Pixel8 -- Red
                           {-# UNPACK #-} !Pixel8 -- Green
                           {-# UNPACK #-} !Pixel8 -- Blue
           deriving (Eq, Ord, Show)

nearestColor :: PixelRGB8 -> Vector PixelRGB8 -> PixelRGB8
nearestColor p ps = snd $ V.minimumBy comp ds
  where
    ds = V.map (\px -> (dist2Px px p, px)) ps
    comp a b = fst a `compare` fst b

dist2Px :: PixelRGB8 -> PixelRGB8 -> Int
dist2Px (PixelRGB8 r1 g1 b1) (PixelRGB8 r2 g2 b2) = dr*dr + dg*dg + db*db
  where
    (dr, dg, db) =
      ( fromIntegral r1 - fromIntegral r2
      , fromIntegral g1 - fromIntegral g2
      , fromIntegral b1 - fromIntegral b2 )

【问题讨论】:

  • 我们能看到dist2Px的代码吗?
  • 到目前为止您尝试过什么?你可以尝试分析它,你可以内联那些本地函数dscomp,你可以编译到核心并搜索瓶颈,然后编译到汇编并确保你有紧密的循环。
  • 我怀疑构建一个只有距离的向量,并使用minIndex 在原始向量中查找结果可能会更快:ps ! V.minIndex (V.map (\px -> dist2Px px p) ps)
  • @Tamil - 不会加快速度,但它更干净,谢谢。
  • 您究竟想优化什么:单个函数调用的时间,还是针对不同颜色但相同调色板的大量调用的平均时间?

标签: haskell optimization


【解决方案1】:

如果您想使用单个调色板并要求不同的颜色,我会先翻转您的签名:

type Palette = V.Vector PixelRGB8
nearestColor :: Palette -> PixelRGB8 -> PixelRGB8

这有利于部分应用,并允许记忆调色板配置。

接下来,您要这样做:将调色板重新存储在适合快速查找的数据结构中。由于您基本上对 ℝ3 中的欧几里德距离感兴趣(顺便说一句,对于颜色比较来说并不是很理想),这是一个非常常见的问题。一个经典的结构是 k-d 树,has long been used for such a nearest-neighbour search。有足够的a Haskell library 可用,对你来说是一个相当方便的界面:

import qualified Data.Trees.KdTree a s KD

instance KD.Point PixelRGB where
  dimension _ = 3
  coord 0 (PixelRGB r _ _) = fromIntegral r
  coord 1 (PixelRGB _ g _) = fromIntegral g
  coord 2 (PixelRGB _ _ b) = fromIntegral b
  dist2 = fromIntegral . dist2Px

然后我们可以将调色板转换成这样的树:

type FastPalette = KD.KdTree PixelRGB8
accelPalette :: Palette -> FastPalette
accelPalette = KD.fromList . V.toList

最后只需使用库提供的下一个邻居搜索:

nearestColor palette = fromJust . KD.nearestNeighbor fpal
 where fpal = accelPalette palette

【讨论】:

  • 我投了赞成票,因为这是一个很好的答案。不幸的是,我仅限于在 Haskell 平台中使用包。顺便说一句,有一些类型 coord1 ... = fromIntegral g 等
  • 嗯,你当然也可以自己重新实现k-d树,没那么难。
猜你喜欢
  • 1970-01-01
  • 2021-04-30
  • 2012-02-02
  • 1970-01-01
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-27
相关资源
最近更新 更多