diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,20 @@
+## [0.0.2.0] - 2017-11-06
+
+- Support OpenCV-3.3.x
+
+### Added
+
+- OpenCV.Core.ArrayOps.perspectiveTransform
+- OpenCV.ImgProc.ImgFiltering.bilateralFilter
+
+### Changed
+
+- Specify the more accurate `pkgconfig-depends: opencv >= 3.0.0` so that Cabal
+  doesn't use the wrong version..
+- Specify the more accurate `setup-depends: Cabal >= 1.23` to prevent building
+  with unsupported Cabals.
+
+
 ## [0.0.1.1] - 2017-06-23
 
 ### Changed
@@ -25,5 +42,6 @@
 - Initial version
 
 
+[0.0.2.0]: https://github.com/LumiGuide/haskell-opencv/compare/opencv-0.0.1.1...opencv-0.0.2.0
 [0.0.1.1]: https://github.com/LumiGuide/haskell-opencv/compare/opencv-0.0.1.0...opencv-0.0.1.1
 [0.0.1.0]: https://github.com/LumiGuide/haskell-opencv/compare/opencv-0.0.0.0...opencv-0.0.1.0
diff --git a/doc/generated/examples/animation.gif b/doc/generated/examples/animation.gif
deleted file mode 100644
Binary files a/doc/generated/examples/animation.gif and /dev/null differ
diff --git a/doc/generated/examples/bilateralFilterImg.png b/doc/generated/examples/bilateralFilterImg.png
new file mode 100644
Binary files /dev/null and b/doc/generated/examples/bilateralFilterImg.png differ
diff --git a/doc/generated/examples/boxBlurImg.png b/doc/generated/examples/boxBlurImg.png
Binary files a/doc/generated/examples/boxBlurImg.png and b/doc/generated/examples/boxBlurImg.png differ
diff --git a/doc/generated/examples/decolorImg.png b/doc/generated/examples/decolorImg.png
Binary files a/doc/generated/examples/decolorImg.png and b/doc/generated/examples/decolorImg.png differ
diff --git a/doc/generated/examples/fastNlMeansDenoisingColoredImg.png b/doc/generated/examples/fastNlMeansDenoisingColoredImg.png
Binary files a/doc/generated/examples/fastNlMeansDenoisingColoredImg.png and b/doc/generated/examples/fastNlMeansDenoisingColoredImg.png differ
diff --git a/doc/generated/examples/fastNlMeansDenoisingColoredMultiImg.png b/doc/generated/examples/fastNlMeansDenoisingColoredMultiImg.png
Binary files a/doc/generated/examples/fastNlMeansDenoisingColoredMultiImg.png and b/doc/generated/examples/fastNlMeansDenoisingColoredMultiImg.png differ
diff --git a/doc/generated/examples/fbMatcherImg.png b/doc/generated/examples/fbMatcherImg.png
Binary files a/doc/generated/examples/fbMatcherImg.png and b/doc/generated/examples/fbMatcherImg.png differ
diff --git a/doc/generated/examples/fromJuicyImg.png b/doc/generated/examples/fromJuicyImg.png
deleted file mode 100644
Binary files a/doc/generated/examples/fromJuicyImg.png and /dev/null differ
diff --git a/doc/generated/examples/fromJuicyPixelsImg.png b/doc/generated/examples/fromJuicyPixelsImg.png
deleted file mode 100644
Binary files a/doc/generated/examples/fromJuicyPixelsImg.png and /dev/null differ
diff --git a/doc/generated/examples/matSubRectImg.png b/doc/generated/examples/matSubRectImg.png
Binary files a/doc/generated/examples/matSubRectImg.png and b/doc/generated/examples/matSubRectImg.png differ
diff --git a/doc/generated/examples/undistortImg.png b/doc/generated/examples/undistortImg.png
Binary files a/doc/generated/examples/undistortImg.png and b/doc/generated/examples/undistortImg.png differ
diff --git a/opencv.cabal b/opencv.cabal
--- a/opencv.cabal
+++ b/opencv.cabal
@@ -1,5 +1,5 @@
 name:          opencv
-version:       0.0.1.1
+version:       0.0.2.0
 homepage:      https://github.com/LumiGuide/haskell-opencv
 bug-reports:   https://github.com/LumiGuide/haskell-opencv/issues
 license:       BSD3
@@ -48,7 +48,7 @@
     manual: True
 
 custom-setup
-    setup-depends: base, Cabal
+    setup-depends: base, Cabal >= 1.23
 
 library
     hs-source-dirs: src
@@ -209,7 +209,7 @@
         TypeOperators
 
     default-language:   Haskell2010
-    pkgconfig-depends:  opencv
+    pkgconfig-depends:  opencv >= 3.0.0
     extra-libraries:    stdc++
 
 test-suite doc-images-opencv
diff --git a/src/OpenCV/Core/ArrayOps.cpp b/src/OpenCV/Core/ArrayOps.cpp
--- a/src/OpenCV/Core/ArrayOps.cpp
+++ b/src/OpenCV/Core/ArrayOps.cpp
@@ -483,3 +483,18 @@
 }
 
 }
+
+extern "C" {
+void inline_c_OpenCV_Core_ArrayOps_26_228e7ff428ad599703e14a00252d380743ce0af1(Point2d * srcPtr_inline_c_0, int32_t cnumPts_27_inline_c_1, Point2d * dstPtr_27_inline_c_2, int32_t cnumPts_27_inline_c_3, Mat * tmPtr_inline_c_4) {
+
+            cv::_InputArray srcPts  = cv::_InputArray( srcPtr_inline_c_0,  cnumPts_27_inline_c_1);
+            cv::_OutputArray dstPts = cv::_OutputArray(dstPtr_27_inline_c_2, cnumPts_27_inline_c_3);
+            cv::perspectiveTransform
+                ( srcPts
+                , dstPts
+                , *tmPtr_inline_c_4
+                );
+            
+}
+
+}
diff --git a/src/OpenCV/Core/ArrayOps.hs b/src/OpenCV/Core/ArrayOps.hs
--- a/src/OpenCV/Core/ArrayOps.hs
+++ b/src/OpenCV/Core/ArrayOps.hs
@@ -46,13 +46,15 @@
     , matTranspose
     , hconcat
     , vconcat
+    , perspectiveTransform
     ) where
 
 import "base" Data.Proxy ( Proxy(..) )
 import "base" Data.Word
+import "base" Foreign.C.Types ( CDouble )
 import "base" Foreign.Marshal.Alloc ( alloca )
 import "base" Foreign.Marshal.Array ( allocaArray, peekArray )
-import "base" Foreign.Ptr ( Ptr )
+import "base" Foreign.Ptr ( Ptr, castPtr )
 import "base" Foreign.Storable ( Storable(..), peek )
 import "base" GHC.TypeLits
 import "base" Data.Int ( Int32 )
@@ -998,3 +1000,36 @@
   where
     c'numMats :: C.CSize
     c'numMats = fromIntegral $ V.length mats
+
+
+{-| Performs the perspective matrix transformation of vectors.
+
+    TODO: Modify this function for accept 3D points
+    TODO: Generalize return type to
+          V.Vector (point2 CDouble)
+
+<http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#perspectivetransform OpenCV Sphinx doc>
+-}
+perspectiveTransform
+    :: (IsPoint2 point2 CDouble)
+    => V.Vector (point2 CDouble)
+    -> Mat ('S '[ 'S 3, 'S 3 ]) ('S 1) ('S Double)
+    -> V.Vector Point2d
+perspectiveTransform srcPoints transformationMat = unsafePerformIO $
+    withArrayPtr (V.map toPoint srcPoints) $ \srcPtr ->
+    withPtr transformationMat $ \tmPtr ->
+    allocaArray numPts $ \(dstPtr :: Ptr (V2 CDouble)) -> do
+        let dstPtr' = castPtr dstPtr
+        [C.block| void {
+            cv::_InputArray srcPts  = cv::_InputArray( $(Point2d * srcPtr),  $(int32_t c'numPts));
+            cv::_OutputArray dstPts = cv::_OutputArray($(Point2d * dstPtr'), $(int32_t c'numPts));
+            cv::perspectiveTransform
+                ( srcPts
+                , dstPts
+                , *$(Mat * tmPtr)
+                );
+            }|]
+        peekArray numPts dstPtr >>= return . V.fromList . map toPoint
+  where
+    numPts   = fromIntegral $ V.length srcPoints
+    c'numPts = fromIntegral $ V.length srcPoints
diff --git a/src/OpenCV/ImgProc/ImgFiltering.cpp b/src/OpenCV/ImgProc/ImgFiltering.cpp
--- a/src/OpenCV/ImgProc/ImgFiltering.cpp
+++ b/src/OpenCV/ImgProc/ImgFiltering.cpp
@@ -6,10 +6,35 @@
 using namespace cv;
 
 extern "C" {
-Exception * inline_c_OpenCV_ImgProc_ImgFiltering_0_e376504d66a67a81166f6a7de96ff685ab99ae52(Mat * srcPtr_inline_c_0, Mat * dstPtr_inline_c_1, int32_t cddepth_27_inline_c_2, int32_t cksize_27_inline_c_3, double cscale_27_inline_c_4, double cdelta_27_inline_c_5, int32_t cborderType_27_inline_c_6) {
+Exception * inline_c_OpenCV_ImgProc_ImgFiltering_0_7d3d053e68542f65ab73e44b4db97dfe42c74c51(Mat * srcPtr_inline_c_0, Mat * dstPtr_inline_c_1, int32_t cd_27_inline_c_2, double csigmaColor_27_inline_c_3, double csigmaSpace_27_inline_c_4, int32_t cborderType_27_inline_c_5) {
 
   try
   {   
+        cv::bilateralFilter
+        ( *srcPtr_inline_c_0
+        , *dstPtr_inline_c_1
+        ,  cd_27_inline_c_2
+        ,  csigmaColor_27_inline_c_3
+        ,  csigmaSpace_27_inline_c_4
+        ,  cborderType_27_inline_c_5
+        );
+      
+    return NULL;
+  }
+  catch (const cv::Exception & e)
+  {
+    return new cv::Exception(e);
+  }
+
+}
+
+}
+
+extern "C" {
+Exception * inline_c_OpenCV_ImgProc_ImgFiltering_1_e376504d66a67a81166f6a7de96ff685ab99ae52(Mat * srcPtr_inline_c_0, Mat * dstPtr_inline_c_1, int32_t cddepth_27_inline_c_2, int32_t cksize_27_inline_c_3, double cscale_27_inline_c_4, double cdelta_27_inline_c_5, int32_t cborderType_27_inline_c_6) {
+
+  try
+  {   
         cv::Laplacian
         ( *srcPtr_inline_c_0
         , *dstPtr_inline_c_1
@@ -32,7 +57,7 @@
 }
 
 extern "C" {
-Exception * inline_c_OpenCV_ImgProc_ImgFiltering_1_345ace375d204c2a7dff8b68ca0269df67bc7938(Mat * matInPtr_inline_c_0, Mat * matOutPtr_inline_c_1, int32_t ksize_inline_c_2) {
+Exception * inline_c_OpenCV_ImgProc_ImgFiltering_2_345ace375d204c2a7dff8b68ca0269df67bc7938(Mat * matInPtr_inline_c_0, Mat * matOutPtr_inline_c_1, int32_t ksize_inline_c_2) {
 
   try
   {    cv::medianBlur(*matInPtr_inline_c_0, *matOutPtr_inline_c_1, ksize_inline_c_2); 
@@ -48,7 +73,7 @@
 }
 
 extern "C" {
-Exception * inline_c_OpenCV_ImgProc_ImgFiltering_2_d33ce1e3332ac2ac4dd5246990112c449c582d4c(Mat * matInPtr_inline_c_0, Mat * matOutPtr_inline_c_1, Size2i * ksizePtr_inline_c_2) {
+Exception * inline_c_OpenCV_ImgProc_ImgFiltering_3_d33ce1e3332ac2ac4dd5246990112c449c582d4c(Mat * matInPtr_inline_c_0, Mat * matOutPtr_inline_c_1, Size2i * ksizePtr_inline_c_2) {
 
   try
   {   
@@ -70,7 +95,7 @@
 }
 
 extern "C" {
-Exception * inline_c_OpenCV_ImgProc_ImgFiltering_3_907ecf95556ac76c10894cb3ae59a4e2b7e7ca9b(Mat * matInPtr_inline_c_0, Mat * matOutPtr_inline_c_1, Size2i * ksizePtr_inline_c_2, double csigmaX_27_inline_c_3, double csigmaY_27_inline_c_4) {
+Exception * inline_c_OpenCV_ImgProc_ImgFiltering_4_907ecf95556ac76c10894cb3ae59a4e2b7e7ca9b(Mat * matInPtr_inline_c_0, Mat * matOutPtr_inline_c_1, Size2i * ksizePtr_inline_c_2, double csigmaX_27_inline_c_3, double csigmaY_27_inline_c_4) {
 
   try
   {   
@@ -94,7 +119,7 @@
 }
 
 extern "C" {
-Exception * inline_c_OpenCV_ImgProc_ImgFiltering_4_82421a3cb5054e4b649407f8926c057bfed86a45(Mat * srcPtr_inline_c_0, Mat * dstPtr_inline_c_1, Mat * kernelPtr_inline_c_2, Point2i * anchorPtr_inline_c_3, int32_t citerations_27_inline_c_4, int32_t cborderType_27_inline_c_5, Scalar * borderValuePtr_inline_c_6) {
+Exception * inline_c_OpenCV_ImgProc_ImgFiltering_5_82421a3cb5054e4b649407f8926c057bfed86a45(Mat * srcPtr_inline_c_0, Mat * dstPtr_inline_c_1, Mat * kernelPtr_inline_c_2, Point2i * anchorPtr_inline_c_3, int32_t citerations_27_inline_c_4, int32_t cborderType_27_inline_c_5, Scalar * borderValuePtr_inline_c_6) {
 
   try
   {   
@@ -120,7 +145,7 @@
 }
 
 extern "C" {
-Exception * inline_c_OpenCV_ImgProc_ImgFiltering_5_686cd566b987aa9d5ec27846da2b925a79b1c365(Mat * srcPtr_inline_c_0, Mat * dstPtr_inline_c_1, Mat * kernelPtr_inline_c_2, Point2i * anchorPtr_inline_c_3, double cdelta_27_inline_c_4, int32_t cborderType_27_inline_c_5) {
+Exception * inline_c_OpenCV_ImgProc_ImgFiltering_6_686cd566b987aa9d5ec27846da2b925a79b1c365(Mat * srcPtr_inline_c_0, Mat * dstPtr_inline_c_1, Mat * kernelPtr_inline_c_2, Point2i * anchorPtr_inline_c_3, double cdelta_27_inline_c_4, int32_t cborderType_27_inline_c_5) {
 
   try
   {   
@@ -146,7 +171,7 @@
 }
 
 extern "C" {
-Exception * inline_c_OpenCV_ImgProc_ImgFiltering_6_93c9df76baf0966fe0e3e5136e89b57d1aea3586(Mat * srcPtr_inline_c_0, Mat * dstPtr_inline_c_1, Mat * kernelPtr_inline_c_2, Point2i * anchorPtr_inline_c_3, int32_t citerations_27_inline_c_4, int32_t cborderType_27_inline_c_5, Scalar * borderValuePtr_inline_c_6) {
+Exception * inline_c_OpenCV_ImgProc_ImgFiltering_7_93c9df76baf0966fe0e3e5136e89b57d1aea3586(Mat * srcPtr_inline_c_0, Mat * dstPtr_inline_c_1, Mat * kernelPtr_inline_c_2, Point2i * anchorPtr_inline_c_3, int32_t citerations_27_inline_c_4, int32_t cborderType_27_inline_c_5, Scalar * borderValuePtr_inline_c_6) {
 
   try
   {   
@@ -172,7 +197,7 @@
 }
 
 extern "C" {
-Exception * inline_c_OpenCV_ImgProc_ImgFiltering_7_fe64cf1ef54e417d07f7d0a61e6c49313898058d(Mat * srcPtr_inline_c_0, Mat * dstPtr_inline_c_1, int32_t cop_27_inline_c_2, Mat * kernelPtr_inline_c_3, Point2i * anchorPtr_inline_c_4, int32_t citerations_27_inline_c_5, int32_t cborderType_27_inline_c_6, Scalar * borderValuePtr_inline_c_7) {
+Exception * inline_c_OpenCV_ImgProc_ImgFiltering_8_fe64cf1ef54e417d07f7d0a61e6c49313898058d(Mat * srcPtr_inline_c_0, Mat * dstPtr_inline_c_1, int32_t cop_27_inline_c_2, Mat * kernelPtr_inline_c_3, Point2i * anchorPtr_inline_c_4, int32_t citerations_27_inline_c_5, int32_t cborderType_27_inline_c_6, Scalar * borderValuePtr_inline_c_7) {
 
   try
   {   
@@ -199,7 +224,7 @@
 }
 
 extern "C" {
-Exception * inline_c_OpenCV_ImgProc_ImgFiltering_8_7ea2729a8a8a953773da566c07815d3fa635d8e9(Mat * elementPtr_inline_c_0, int32_t cmorphShape_27_inline_c_1, Size2i * ksizePtr_inline_c_2, Point2i * anchorPtr_inline_c_3) {
+Exception * inline_c_OpenCV_ImgProc_ImgFiltering_9_7ea2729a8a8a953773da566c07815d3fa635d8e9(Mat * elementPtr_inline_c_0, int32_t cmorphShape_27_inline_c_1, Size2i * ksizePtr_inline_c_2, Point2i * anchorPtr_inline_c_3) {
 
   try
   {   
diff --git a/src/OpenCV/ImgProc/ImgFiltering.hsc b/src/OpenCV/ImgProc/ImgFiltering.hsc
--- a/src/OpenCV/ImgProc/ImgFiltering.hsc
+++ b/src/OpenCV/ImgProc/ImgFiltering.hsc
@@ -34,6 +34,7 @@
     ( MorphShape(..)
     , MorphOperation(..)
 
+    , bilateralFilter
     , laplacian
     , medianBlur
     , erode
@@ -131,6 +132,84 @@
 --------------------------------------------------------------------------------
 -- Image Filtering
 --------------------------------------------------------------------------------
+
+{- | Calculates the bilateralFilter of an image
+
+The function applies bilateral filtering to the input image, as described in
+<http://www.dai.ed.ac.uk/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html Bilateral_Filtering>
+bilateralFilter can reduce unwanted noise very well while keeping edges fairly sharp. However, it is very slow compared to most filters.
+Example:
+
+@
+bilateralFilterImg
+    :: forall (width    :: Nat)
+              (width2   :: Nat)
+              (height   :: Nat)
+              (channels :: Nat)
+              (depth    :: *)
+     . ( Mat (ShapeT [height, width]) ('S channels) ('S depth) ~ Birds_512x341
+       , width2 ~ ((*) width 2) -- TODO (RvD): HSE parse error with infix type operator
+       )
+    => Mat (ShapeT [height, width2]) ('S channels) ('S depth)
+bilateralFilterImg = exceptError $
+    withMatM (Proxy :: Proxy [height, width2])
+             (Proxy :: Proxy channels)
+             (Proxy :: Proxy depth)
+             white $ \imgM -> do
+      birdsFiltered <- pureExcept $ bilateralFilter (Just 9) Nothing Nothing Nothing birds_512x341
+      matCopyToM imgM (V2 0 0) birds_512x341 Nothing
+      matCopyToM imgM (V2 w 0) birdsFiltered Nothing
+  where
+    w = fromInteger $ natVal (Proxy :: Proxy width)
+@
+
+<<doc/generated/examples/bilateralFilterImg.png bilateralFilterImg>>
+
+<https://docs.opencv.org/3.0-last-rst/modules/imgproc/doc/filtering.html#bilateralfilter OpenCV Sphinx doc>
+-}
+bilateralFilter
+    :: ( depth    `In` '[Word8, Float, Double]
+       , channels `In` '[1, 3]
+       -- , Length shape <= 2
+       )
+    => Maybe Int32
+       -- ^ Diameter of each pixel neighborhood that is used during filtering.
+       -- If it is non-positive, it is computed from sigmaSpace. Default value is 5.
+    -> Maybe Double
+       -- ^ Filter sigma in the color space. A larger value of the parameter means that farther colors within
+       -- the pixel neighborhood (see sigmaSpace) will be mixed together, resulting in larger areas of semi-equal color.
+       -- Default value is 50
+    -> Maybe Double
+       -- ^ Filter sigma in the coordinate space. A larger value of the parameter means that farther pixels will
+       -- influence each other as long as their colors are close enough (see sigmaColor ). When d>0, it specifies
+       -- the neighborhood size regardless of sigmaSpace. Otherwise, d is proportional to sigmaSpace.
+       -- Default value is 50
+    -> Maybe BorderMode
+       -- ^ Pixel extrapolation method. Default value is BorderReflect101
+    -> Mat shape ('S channels) ('S depth)
+    -> CvExcept (Mat shape ('S channels) ('S depth))
+bilateralFilter d sigmaColor sigmaSpace borderType src = unsafeWrapException $ do
+    dst <- newEmptyMat
+    handleCvException (pure $ unsafeCoerceMat dst) $
+      withPtr src $ \srcPtr ->
+      withPtr dst $ \dstPtr ->
+      [cvExcept|
+        cv::bilateralFilter
+        ( *$(Mat *   srcPtr      )
+        , *$(Mat *   dstPtr      )
+        ,  $(int32_t c'd         )
+        ,  $(double  c'sigmaColor)
+        ,  $(double  c'sigmaSpace)
+        ,  $(int32_t c'borderType)
+        );
+      |]
+  where
+    c'd = fromMaybe 5 d
+    c'sigmaColor = maybe 50 realToFrac sigmaColor
+    c'sigmaSpace = maybe 50 realToFrac sigmaSpace
+    c'borderType = fst $ marshalBorderMode $ fromMaybe BorderReflect101 borderType
+
+
 
 {- | Calculates the Laplacian of an image
 
