packages feed

fei-modelzoo-1.0.0: src/MXNet/NN/ModelZoo/Utils/Box.hs

module MXNet.NN.ModelZoo.Utils.Box where

import RIO
import Data.Array.Repa (Array, U, DIM1, Z(..), (:.)(..))
import qualified Data.Array.Repa as Repa

import MXNet.NN.Utils.Repa


type RBox = Array U DIM1 Float

bboxArea :: RBox -> Float
bboxArea box = (box ^#! 2 - box ^#! 0 + 1) * (box ^#! 3 - box ^#! 1 + 1)

bboxIntersect :: RBox -> RBox -> Maybe RBox
bboxIntersect box1 box2 | not valid = Nothing
                        | otherwise = Just $ Repa.fromListUnboxed (Z:.4) [x1, y1, x2, y2]
  where
    valid = x2 - x1 > 0 && y2 - y1 > 0
    x1 = max (box1 ^#! 0) (box2 ^#! 0)
    x2 = min (box1 ^#! 2) (box2 ^#! 2)
    y1 = max (box1 ^#! 1) (box2 ^#! 1)
    y2 = min (box1 ^#! 3) (box2 ^#! 3)

bboxIOU :: RBox -> RBox -> Float
bboxIOU box1 box2 = case bboxIntersect box1 box2 of
                      Nothing -> 0
                      Just boxI -> let areaI = bboxArea boxI
                                       areaU = bboxArea box1 + bboxArea box2 - areaI
                                   in areaI / areaU

whctr :: RBox -> RBox
whctr box1 = Repa.fromListUnboxed (Z:.4) [w, h, x, y]
  where
    [x0, y0, x1, y1] = Repa.toList box1
    w = x1 - x0 + 1
    h = y1 - y0 + 1
    x = x0 + 0.5 * (w - 1)
    y = y0 + 0.5 * (h - 1)

bboxTransform :: RBox -> RBox -> RBox -> RBox
bboxTransform stds box1 box2 =
    let [w1, h1, cx1, cy1] = Repa.toList $ whctr box1
        [w2, h2, cx2, cy2] = Repa.toList $ whctr box2
        dx = (cx2 - cx1) / (w1 + 1e-14)
        dy = (cy2 - cy1) / (h1 + 1e-14)
        dw = log (w2 / w1)
        dh = log (h2 / h1)
    in Repa.computeS $ Repa.fromListUnboxed (Z:.4) [dx, dy, dw, dh] Repa./^ stds

ctrwh :: RBox -> RBox
ctrwh box1 = Repa.fromListUnboxed (Z:.4) [x0, y0, x1, y1]
  where
    [w, h, cx, cy] = Repa.toList box1
    x0 = cx - 0.5 * (w - 1)
    y0 = cy - 0.5 * (h - 1)
    x1 = w + x0 - 1
    y1 = h + y0 - 1

bboxTransInv :: RBox -> RBox -> RBox -> RBox
bboxTransInv stds box delta =
    let [dx, dy, dw, dh] = Repa.toList $ delta Repa.*^ stds
        [w1, h1, cx1, cy1] = Repa.toList $ whctr box
        w2 = exp dw * w1
        h2 = exp dh * w2
        cx2 = dx * w1 + cx1
        cy2 = dy * h1 + cy1
    in ctrwh $ Repa.fromListUnboxed (Z:.4) [w2, h2, cx2, cy2]


bboxClip :: Float -> Float -> RBox -> RBox
bboxClip height width box = Repa.fromListUnboxed (Z:.4) [x0', y0', x1', y1']
  where
    [x0, y0, x1, y1] = Repa.toList box
    w' = width - 1
    h' = height - 1
    x0' = max 0 (min x0 w')
    y0' = max 0 (min y0 h')
    x1' = max 0 (min x1 w')
    y1' = max 0 (min y1 h')