diff --git a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.markdown b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.markdown index 753b368c0d..e915d04b94 100644 --- a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.markdown +++ b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.markdown @@ -1,16 +1,18 @@ Smoothing Images {#tutorial_gausian_median_blur_bilateral_filter} ================ +@next_tutorial{tutorial_erosion_dilatation} + Goal ---- In this tutorial you will learn how to apply diverse linear filters to smooth images using OpenCV functions such as: -- @ref cv::blur -- @ref cv::GaussianBlur -- @ref cv::medianBlur -- @ref cv::bilateralFilter +- **blur()** +- **GaussianBlur()** +- **medianBlur()** +- **bilateralFilter()** Theory ------ @@ -92,38 +94,65 @@ Code - Loads an image - Applies 4 different kinds of filters (explained in Theory) and show the filtered images sequentially + +@add_toggle_cpp - **Downloadable code**: Click - [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Smoothing.cpp) + [here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp) + - **Code at glance:** - @include samples/cpp/tutorial_code/ImgProc/Smoothing.cpp + @include samples/cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp +@end_toggle + +@add_toggle_java +- **Downloadable code**: Click + [here](https://raw.githubusercontent.com/opencv/opencv/master/samples/java/tutorial_code/ImgProc/Smoothing/Smoothing.java) + +- **Code at glance:** + @include samples/java/tutorial_code/ImgProc/Smoothing/Smoothing.java +@end_toggle + +@add_toggle_python +- **Downloadable code**: Click + [here](https://raw.githubusercontent.com/opencv/opencv/master/samples/python/tutorial_code/imgProc/Smoothing/smoothing.py) + +- **Code at glance:** + @include samples/python/tutorial_code/imgProc/Smoothing/smoothing.py +@end_toggle Explanation ----------- --# Let's check the OpenCV functions that involve only the smoothing procedure, since the rest is - already known by now. --# **Normalized Block Filter:** +Let's check the OpenCV functions that involve only the smoothing procedure, since the rest is +already known by now. - OpenCV offers the function @ref cv::blur to perform smoothing with this filter. - @snippet cpp/tutorial_code/ImgProc/Smoothing.cpp blur +#### Normalized Block Filter: +- OpenCV offers the function **blur()** to perform smoothing with this filter. We specify 4 arguments (more details, check the Reference): - - *src*: Source image - *dst*: Destination image - - *Size( w,h )*: Defines the size of the kernel to be used ( of width *w* pixels and height + - *Size( w, h )*: Defines the size of the kernel to be used ( of width *w* pixels and height *h* pixels) - *Point(-1, -1)*: Indicates where the anchor point (the pixel evaluated) is located with respect to the neighborhood. If there is a negative value, then the center of the kernel is considered the anchor point. --# **Gaussian Filter:** +@add_toggle_cpp +@snippet cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp blur +@end_toggle - It is performed by the function @ref cv::GaussianBlur : - @snippet cpp/tutorial_code/ImgProc/Smoothing.cpp gaussianblur +@add_toggle_java +@snippet samples/java/tutorial_code/ImgProc/Smoothing/Smoothing.java blur +@end_toggle +@add_toggle_python +@snippet samples/python/tutorial_code/imgProc/Smoothing/smoothing.py blur +@end_toggle + +#### Gaussian Filter: + +- It is performed by the function **GaussianBlur()** : Here we use 4 arguments (more details, check the OpenCV reference): - - *src*: Source image - *dst*: Destination image - *Size(w, h)*: The size of the kernel to be used (the neighbors to be considered). \f$w\f$ and @@ -134,35 +163,65 @@ Explanation - \f$\sigma_{y}\f$: The standard deviation in y. Writing \f$0\f$ implies that \f$\sigma_{y}\f$ is calculated using kernel size. --# **Median Filter:** +@add_toggle_cpp +@snippet cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp gaussianblur +@end_toggle - This filter is provided by the @ref cv::medianBlur function: - @snippet cpp/tutorial_code/ImgProc/Smoothing.cpp medianblur +@add_toggle_java +@snippet samples/java/tutorial_code/ImgProc/Smoothing/Smoothing.java gaussianblur +@end_toggle +@add_toggle_python +@snippet samples/python/tutorial_code/imgProc/Smoothing/smoothing.py gaussianblur +@end_toggle + +#### Median Filter: + +- This filter is provided by the **medianBlur()** function: We use three arguments: - - *src*: Source image - *dst*: Destination image, must be the same type as *src* - *i*: Size of the kernel (only one because we use a square window). Must be odd. --# **Bilateral Filter** +@add_toggle_cpp +@snippet cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp medianblur +@end_toggle - Provided by OpenCV function @ref cv::bilateralFilter - @snippet cpp/tutorial_code/ImgProc/Smoothing.cpp bilateralfilter +@add_toggle_java +@snippet samples/java/tutorial_code/ImgProc/Smoothing/Smoothing.java medianblur +@end_toggle +@add_toggle_python +@snippet samples/python/tutorial_code/imgProc/Smoothing/smoothing.py medianblur +@end_toggle + +#### Bilateral Filter + +- Provided by OpenCV function **bilateralFilter()** We use 5 arguments: - - *src*: Source image - *dst*: Destination image - *d*: The diameter of each pixel neighborhood. - \f$\sigma_{Color}\f$: Standard deviation in the color space. - \f$\sigma_{Space}\f$: Standard deviation in the coordinate space (in pixel terms) +@add_toggle_cpp +@snippet cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp bilateralfilter +@end_toggle + +@add_toggle_java +@snippet samples/java/tutorial_code/ImgProc/Smoothing/Smoothing.java bilateralfilter +@end_toggle + +@add_toggle_python +@snippet samples/python/tutorial_code/imgProc/Smoothing/smoothing.py bilateralfilter +@end_toggle + Results ------- -- The code opens an image (in this case *lena.jpg*) and display it under the effects of the 4 - filters explained. +- The code opens an image (in this case [lena.jpg](https://raw.githubusercontent.com/opencv/opencv/master/samples/data/lena.jpg)) + and display it under the effects of the 4 filters explained. - Here is a snapshot of the image smoothed using *medianBlur*: ![](images/Smoothing_Tutorial_Result_Median_Filter.jpg) diff --git a/doc/tutorials/imgproc/table_of_content_imgproc.markdown b/doc/tutorials/imgproc/table_of_content_imgproc.markdown index 42dd4ce3bf..335ba291bb 100644 --- a/doc/tutorials/imgproc/table_of_content_imgproc.markdown +++ b/doc/tutorials/imgproc/table_of_content_imgproc.markdown @@ -5,6 +5,8 @@ In this section you will learn about the image processing (manipulation) functio - @subpage tutorial_gausian_median_blur_bilateral_filter + *Languages:* C++, Java, Python + *Compatibility:* \> OpenCV 2.0 *Author:* Ana Huamán diff --git a/samples/cpp/tutorial_code/ImgProc/Smoothing.cpp b/samples/cpp/tutorial_code/ImgProc/Smoothing.cpp deleted file mode 100644 index 58aa474c38..0000000000 --- a/samples/cpp/tutorial_code/ImgProc/Smoothing.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/** - * file Smoothing.cpp - * brief Sample code for simple filters - * author OpenCV team - */ - -#include "opencv2/imgproc.hpp" -#include "opencv2/imgcodecs.hpp" -#include "opencv2/highgui.hpp" - -using namespace std; -using namespace cv; - -/// Global Variables -int DELAY_CAPTION = 1500; -int DELAY_BLUR = 100; -int MAX_KERNEL_LENGTH = 31; - -Mat src; Mat dst; -char window_name[] = "Smoothing Demo"; - -/// Function headers -int display_caption( const char* caption ); -int display_dst( int delay ); - - -/** - * function main - */ -int main( void ) -{ - namedWindow( window_name, WINDOW_AUTOSIZE ); - - /// Load the source image - src = imread( "../data/lena.jpg", IMREAD_COLOR ); - - if( display_caption( "Original Image" ) != 0 ) { return 0; } - - dst = src.clone(); - if( display_dst( DELAY_CAPTION ) != 0 ) { return 0; } - - - /// Applying Homogeneous blur - if( display_caption( "Homogeneous Blur" ) != 0 ) { return 0; } - - //![blur] - for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) - { blur( src, dst, Size( i, i ), Point(-1,-1) ); - if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } - //![blur] - - /// Applying Gaussian blur - if( display_caption( "Gaussian Blur" ) != 0 ) { return 0; } - - //![gaussianblur] - for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) - { GaussianBlur( src, dst, Size( i, i ), 0, 0 ); - if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } - //![gaussianblur] - - /// Applying Median blur - if( display_caption( "Median Blur" ) != 0 ) { return 0; } - - //![medianblur] - for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) - { medianBlur ( src, dst, i ); - if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } - //![medianblur] - - /// Applying Bilateral Filter - if( display_caption( "Bilateral Blur" ) != 0 ) { return 0; } - - //![bilateralfilter] - for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) - { bilateralFilter ( src, dst, i, i*2, i/2 ); - if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } - //![bilateralfilter] - - /// Wait until user press a key - display_caption( "End: Press a key!" ); - - waitKey(0); - - return 0; -} - -/** - * @function display_caption - */ -int display_caption( const char* caption ) -{ - dst = Mat::zeros( src.size(), src.type() ); - putText( dst, caption, - Point( src.cols/4, src.rows/2), - FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) ); - - imshow( window_name, dst ); - int c = waitKey( DELAY_CAPTION ); - if( c >= 0 ) { return -1; } - return 0; -} - -/** - * @function display_dst - */ -int display_dst( int delay ) -{ - imshow( window_name, dst ); - int c = waitKey ( delay ); - if( c >= 0 ) { return -1; } - return 0; -} diff --git a/samples/cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp b/samples/cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp new file mode 100644 index 0000000000..d96b52a0c1 --- /dev/null +++ b/samples/cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp @@ -0,0 +1,115 @@ +/** + * file Smoothing.cpp + * brief Sample code for simple filters + * author OpenCV team + */ + +#include +#include "opencv2/imgproc.hpp" +#include "opencv2/imgcodecs.hpp" +#include "opencv2/highgui.hpp" + +using namespace std; +using namespace cv; + +/// Global Variables +int DELAY_CAPTION = 1500; +int DELAY_BLUR = 100; +int MAX_KERNEL_LENGTH = 31; + +Mat src; Mat dst; +char window_name[] = "Smoothing Demo"; + +/// Function headers +int display_caption( const char* caption ); +int display_dst( int delay ); + + +/** + * function main + */ +int main( int argc, char ** argv ) +{ + namedWindow( window_name, WINDOW_AUTOSIZE ); + + /// Load the source image + const char* filename = argc >=2 ? argv[1] : "../data/lena.jpg"; + + src = imread( filename, IMREAD_COLOR ); + if(src.empty()){ + printf(" Error opening image\n"); + printf(" Usage: ./Smoothing [image_name -- default ../data/lena.jpg] \n"); + return -1; + } + + if( display_caption( "Original Image" ) != 0 ) { return 0; } + + dst = src.clone(); + if( display_dst( DELAY_CAPTION ) != 0 ) { return 0; } + + + /// Applying Homogeneous blur + if( display_caption( "Homogeneous Blur" ) != 0 ) { return 0; } + + //![blur] + for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) + { blur( src, dst, Size( i, i ), Point(-1,-1) ); + if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } + //![blur] + + /// Applying Gaussian blur + if( display_caption( "Gaussian Blur" ) != 0 ) { return 0; } + + //![gaussianblur] + for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) + { GaussianBlur( src, dst, Size( i, i ), 0, 0 ); + if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } + //![gaussianblur] + + /// Applying Median blur + if( display_caption( "Median Blur" ) != 0 ) { return 0; } + + //![medianblur] + for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) + { medianBlur ( src, dst, i ); + if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } + //![medianblur] + + /// Applying Bilateral Filter + if( display_caption( "Bilateral Blur" ) != 0 ) { return 0; } + + //![bilateralfilter] + for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 ) + { bilateralFilter ( src, dst, i, i*2, i/2 ); + if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } } + //![bilateralfilter] + + /// Done + display_caption( "Done!" ); + + return 0; +} + +/** + * @function display_caption + */ +int display_caption( const char* caption ) +{ + dst = Mat::zeros( src.size(), src.type() ); + putText( dst, caption, + Point( src.cols/4, src.rows/2), + FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) ); + + return display_dst(DELAY_CAPTION); +} + +/** + * @function display_dst + */ +int display_dst( int delay ) +{ + imshow( window_name, dst ); + int c = waitKey ( delay ); + if( c >= 0 ) { return -1; } + return 0; +} diff --git a/samples/java/tutorial_code/ImgProc/Smoothing/Smoothing.java b/samples/java/tutorial_code/ImgProc/Smoothing/Smoothing.java new file mode 100644 index 0000000000..b4d96307c9 --- /dev/null +++ b/samples/java/tutorial_code/ImgProc/Smoothing/Smoothing.java @@ -0,0 +1,101 @@ +import org.opencv.core.*; +import org.opencv.highgui.HighGui; +import org.opencv.imgcodecs.Imgcodecs; +import org.opencv.imgproc.Imgproc; + +class SmoothingRun { + + /// Global Variables + int DELAY_CAPTION = 1500; + int DELAY_BLUR = 100; + int MAX_KERNEL_LENGTH = 31; + + Mat src = new Mat(), dst = new Mat(); + String windowName = "Filter Demo 1"; + + public void run(String[] args) { + + String filename = ((args.length > 0) ? args[0] : "../data/lena.jpg"); + + src = Imgcodecs.imread(filename, Imgcodecs.IMREAD_COLOR); + if( src.empty() ) { + System.out.println("Error opening image"); + System.out.println("Usage: ./Smoothing [image_name -- default ../data/lena.jpg] \n"); + System.exit(-1); + } + + if( displayCaption( "Original Image" ) != 0 ) { System.exit(0); } + + dst = src.clone(); + if( displayDst( DELAY_CAPTION ) != 0 ) { System.exit(0); } + + /// Applying Homogeneous blur + if( displayCaption( "Homogeneous Blur" ) != 0 ) { System.exit(0); } + + //! [blur] + for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) { + Imgproc.blur(src, dst, new Size(i, i), new Point(-1, -1)); + displayDst(DELAY_BLUR); + } + //! [blur] + + /// Applying Gaussian blur + if( displayCaption( "Gaussian Blur" ) != 0 ) { System.exit(0); } + + //! [gaussianblur] + for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) { + Imgproc.GaussianBlur(src, dst, new Size(i, i), 0, 0); + displayDst(DELAY_BLUR); + } + //! [gaussianblur] + + /// Applying Median blur + if( displayCaption( "Median Blur" ) != 0 ) { System.exit(0); } + + //! [medianblur] + for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) { + Imgproc.medianBlur(src, dst, i); + displayDst(DELAY_BLUR); + } + //! [medianblur] + + /// Applying Bilateral Filter + if( displayCaption( "Bilateral Blur" ) != 0 ) { System.exit(0); } + + //![bilateralfilter] + for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2) { + Imgproc.bilateralFilter(src, dst, i, i * 2, i / 2); + displayDst(DELAY_BLUR); + } + //![bilateralfilter] + + /// Done + displayCaption( "Done!" ); + + System.exit(0); + } + + int displayCaption(String caption) { + dst = Mat.zeros(src.size(), src.type()); + Imgproc.putText(dst, caption, + new Point(src.cols() / 4, src.rows() / 2), + Core.FONT_HERSHEY_COMPLEX, 1, new Scalar(255, 255, 255)); + + return displayDst(DELAY_CAPTION); + } + + int displayDst(int delay) { + HighGui.imshow( windowName, dst ); + int c = HighGui.waitKey( delay ); + if (c >= 0) { return -1; } + return 0; + } +} + +public class Smoothing { + public static void main(String[] args) { + // Load the native library. + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + new SmoothingRun().run(args); + } +} diff --git a/samples/python/tutorial_code/imgProc/Smoothing/smoothing.py b/samples/python/tutorial_code/imgProc/Smoothing/smoothing.py new file mode 100644 index 0000000000..c20ca8716d --- /dev/null +++ b/samples/python/tutorial_code/imgProc/Smoothing/smoothing.py @@ -0,0 +1,107 @@ +import sys +import cv2 +import numpy as np + +# Global Variables + +DELAY_CAPTION = 1500 +DELAY_BLUR = 100 +MAX_KERNEL_LENGTH = 31 + +src = None +dst = None +window_name = 'Smoothing Demo' + + +def main(argv): + cv2.namedWindow(window_name, cv2.WINDOW_AUTOSIZE) + + # Load the source image + imageName = argv[0] if len(argv) > 0 else "../data/lena.jpg" + + global src + src = cv2.imread(imageName, 1) + if src is None: + print ('Error opening image') + print ('Usage: smoothing.py [image_name -- default ../data/lena.jpg] \n') + return -1 + + if display_caption('Original Image') != 0: + return 0 + + global dst + dst = np.copy(src) + if display_dst(DELAY_CAPTION) != 0: + return 0 + + # Applying Homogeneous blur + if display_caption('Homogeneous Blur') != 0: + return 0 + + ## [blur] + for i in range(1, MAX_KERNEL_LENGTH, 2): + dst = cv2.blur(src, (i, i)) + if display_dst(DELAY_BLUR) != 0: + return 0 + ## [blur] + + # Applying Gaussian blur + if display_caption('Gaussian Blur') != 0: + return 0 + + ## [gaussianblur] + for i in range(1, MAX_KERNEL_LENGTH, 2): + dst = cv2.GaussianBlur(src, (i, i), 0) + if display_dst(DELAY_BLUR) != 0: + return 0 + ## [gaussianblur] + + # Applying Median blur + if display_caption('Median Blur') != 0: + return 0 + + ## [medianblur] + for i in range(1, MAX_KERNEL_LENGTH, 2): + dst = cv2.medianBlur(src, i) + if display_dst(DELAY_BLUR) != 0: + return 0 + ## [medianblur] + + # Applying Bilateral Filter + if display_caption('Bilateral Blur') != 0: + return 0 + + ## [bilateralfilter] + # Remember, bilateral is a bit slow, so as value go higher, it takes long time + for i in range(1, MAX_KERNEL_LENGTH, 2): + dst = cv2.bilateralFilter(src, i, i * 2, i / 2) + if display_dst(DELAY_BLUR) != 0: + return 0 + ## [bilateralfilter] + + # Done + display_caption('Done!') + + return 0 + + +def display_caption(caption): + global dst + dst = np.zeros(src.shape, src.dtype) + rows, cols, ch = src.shape + cv2.putText(dst, caption, + (int(cols / 4), int(rows / 2)), + cv2.FONT_HERSHEY_COMPLEX, 1, (255, 255, 255)) + + return display_dst(DELAY_CAPTION) + + +def display_dst(delay): + cv2.imshow(window_name, dst) + c = cv2.waitKey(delay) + if c >= 0 : return -1 + return 0 + + +if __name__ == "__main__": + main(sys.argv[1:])