10000 Add bilateralFilter from ImgFiltering (#101) · LumiGuide/haskell-opencv@57fbbb2 · GitHub
[go: up one dir, main page]

Skip to content

Commit 57fbbb2

Browse files
tolyszroelvandijk
authored andcommitted
Add bilateralFilter from ImgFiltering (#101)
1 parent 9160015 commit 57fbbb2

File tree

3 files changed

+150
-0
lines changed

3 files changed

+150
-0
lines changed

opencv-examples/opencv-examples.cabal

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ executable highgui
4646

4747
default-language: Haskell2010
4848

49+
executable videoio-bilateral
50+
main-is: videoio-bilateral.hs
51+
hs-source-dirs: src
52+
ghc-options: -Wall -O2
53+
54+
build-depends:
55+
base >= 4.8 && < 4.10
56+
, opencv
57+
, opencv-examples
58+
59+
default-language: Haskell2010
60+
4961
executable videoio
5062
main-is: videoio.hs
5163
hs-source-dirs: src
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{-# language DataKinds #-}
2+
{-# language FlexibleInstances #-}
3+
{-# language FlexibleContexts #-}
4+
{-# language OverloadedStrings #-}
5+
6+
module Main where
7+
8+
import qualified OpenCV as CV
9+
import qualified OpenCV.Internal.Core.Types.Mat as CV
10+
import qualified OpenCV.VideoIO.VideoWriter as CVW
11+
import OpenCV.ImgProc.ImgFiltering
12+
import OpenCV.TypeLevel
13+
import OpenCV.Example
14+
import OpenCV.VideoIO.Types as T
15+
import System.Environment
16+
import System.Exit
17+
import Data.Word
18+
import Control.Monad
19+
import Text.Read
20+
21+
main :: IO ()
22+
main = do
23+
args <- getArgs
24+
when (length args /= 2) $ print "videoio-bilateral input d output.mov "
25+
let (_:d:output:_) = args ++ ["5", "/dev/null"]
26+
cap <- createCaptureArg
27+
28+
fps <- CV.videoCaptureGetD cap VideoCapPropFps
29+
w <- CV.videoCaptureGetI cap VideoCapPropFrameWidth
30+
h <- CV.videoCaptureGetI cap VideoCapPropFrameHeight
31+
print (fps, w, h)
32+
33+
isOpened <- CV.videoCaptureIsOpened cap
34+
35+
if not isOpened
36+
then putStrLn "Couldn't open video capture device"
37+
else CV.withWindow "video" $ \window ->
38+
CV.withWindow "input video" $ \windowlv -> do
39+
wr <- CVW.videoWriterOpen $ CVW.VideoFileSink' $ CVW.VideoFileSink output "avc1" fps (w , h)
40+
loop (readMaybe d) cap wr window windowlv 0
41+
CV.exceptErrorIO $ CVW.videoWriterRelease wr
42+
where
43+
loop d cap wr window windowlv i = do
44+
_ok <- CV.videoCaptureGrab cap
45+
print (i :: Int)
46+
mbImg <- CV.videoCaptureRetrieve cap
47+
case mbImg of
48+
Just img -> do
49+
let img' :: CV.Mat ('S ['D, 'D]) ('S 3) ('S Word8)
50+
img' = CV.exceptError (CV.coerceMat img)
51+
let dnImg = CV.exceptError $ bilateralFilter d (Just 20) (Just 500) Nothing img'
52+
CV.exceptErrorIO $ CVW.videoWriterWrite wr $ CV.unsafeCoerceMat dnImg
53+
54+
CV.imshow window dnImg
55+
CV.imshow windowlv img'
56+
key <- CV.waitKey 20
57+
-- Loop unless the escape key is pressed.
58+
unless (key == 27) $ loop d cap wr window windowlv (i + 1)
59+
Nothing -> pure ()

opencv/src/OpenCV/ImgProc/ImgFiltering.hsc

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ module OpenCV.ImgProc.ImgFiltering
3434
( MorphShape(..)
3535
, MorphOperation(..)
3636

37+
, bilateralFilter
3738
, laplacian
3839
, medianBlur
3940
, erode
@@ -132,6 +133,84 @@ marshalMorphOperation = \case
132133
-- Image Filtering
133134
--------------------------------------------------------------------------------
134135

136+
{- | Calculates the bilateralFilter of an image
137+
138+
The function applies bilateral filtering to the input image, as described in
139+
<http://www.dai.ed.ac.uk/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html Bilateral_Filtering>
140+
bilateralFilter can reduce unwanted noise very well while keeping edges fairly sharp. However, it is very slow compared to most filters.
141+
Example:
142+
143+
@
144+
bilateralFilterImg
145+
:: forall (width :: Nat)
146+
(width2 :: Nat)
147+
(height :: Nat)
148+
(channels :: Nat)
149+
(depth :: *)
150+
. ( Mat (ShapeT [height, width]) ('S channels) ('S depth) ~ Birds_512x341
151+
, width2 ~ ((*) width 2) -- TODO (RvD): HSE parse error with infix type operator
152+
)
153+
=> Mat (ShapeT [height, width2]) ('S channels) ('S depth)
154+
bilateralFilterImg = exceptError $
155+
withMatM (Proxy :: Proxy [height, width2])
156+
(Proxy :: Proxy channels)
157+
(Proxy :: Proxy depth)
158+
white $ \imgM -> do
159+
birdsFiltered <- pureExcept $ bilateralFilter (Just 9) Nothing Nothing Nothing birds_512x341
160+
matCopyToM imgM (V2 0 0) birds_512x341 Nothing
161+
matCopyToM imgM (V2 w 0) birdsFiltered Nothing
162+
where
163+
w = fromInteger $ natVal (Proxy :: Proxy width)
164+
@
165+
166+
<<doc/generated/examples/bilateralFilterImg.png bilateralFilterImg>>
167+
168+
<https://docs.opencv.org/3.0-last-rst/modules/imgproc/doc/filtering.html#bilateralfilter OpenCV Sphinx doc>
169+
-}
170+
bilateralFilter
171+
:: ( depth `In` '[Word8, Float, Double]
172+
, channels `In` '[1, 3]
173+
-- , Length shape <= 2
174+
)
175+
=> Maybe Int32
176+
-- ^ Diameter of each pixel neighborhood that is used during filtering.
177+
-- If it is non-positive, it is computed from sigmaSpace. Default value is 5.
178+
-> Maybe Double
179+
-- ^ Filter sigma in the color space. A larger value of the parameter means that farther colors within
180+
-- the pixel neighborhood (see sigmaSpace) will be mixed together, resulting in larger areas of semi-equal color.
181+
-- Default value is 50
182+
-> Maybe Double
183+
-- ^ Filter sigma in the coordinate space. A larger value of the parameter means that farther pixels will
184+
-- influence each other as long as their colors are close enough (see sigmaColor ). When d>0, it specifies
185+
-- the neighborhood size regardless of sigmaSpace. Otherwise, d is proportional to sigmaSpace.
186+
-- Default value is 50
187+
-> Maybe BorderMode
188+
-- ^ Pixel extrapolation method. Default value is BorderReflect101
189+
-> Mat shape ('S channels) ('S depth)
190+
-> CvExcept (Mat shape ('S channels) ('S depth))
191+
bilateralFilter d sigmaColor sigmaSpace borderType src = unsafeWrapException $ do
192+
dst <- newEmptyMat
193+
handleCvException (pure $ unsafeCoerceMat dst) $
194+
withPtr src $ \srcPtr ->
195+
withPtr dst $ \dstPtr ->
196+
[cvExcept|
197+
cv::bilateralFilter
198+
( *$(Mat * srcPtr )
199+
, *$(Mat * dstPtr )
200+
, $(int32_t c'd )
201+
, $(double c'sigmaColor)
202+
, $(double c'sigmaSpace)
203+
, $(int32_t c'borderType)
204+
);
205+
|]
206+
where
207+
c'd = fromMaybe 5 d
208+
c'sigmaColor = maybe 50 realToFrac sigmaColor
209+
c'sigmaSpace = maybe 50 realToFrac sigmaSpace
210+
c'borderType = fst $ marshalBorderMode $ fromMaybe BorderReflect101 borderType
211+
212+
213+
135214
{- | Calculates the Laplacian of an image
136215
137216
The function calculates the Laplacian of the source image by adding up

0 commit comments

Comments
 (0)
0