Making your own linear filters! {#tutorial_filter_2d}
===============================
+@prev_tutorial{tutorial_threshold_inRange}
+@next_tutorial{tutorial_copyMakeBorder}
+
Goal
----
In this tutorial you will learn how to:
-- Use the OpenCV function @ref cv::filter2D to create your own linear filters.
+- Use the OpenCV function **filter2D()** to create your own linear filters.
Theory
------
\f[H(x,y) = \sum_{i=0}^{M_{i} - 1} \sum_{j=0}^{M_{j}-1} I(x+i - a_{i}, y + j - a_{j})K(i,j)\f]
-Fortunately, OpenCV provides you with the function @ref cv::filter2D so you do not have to code all
+Fortunately, OpenCV provides you with the function **filter2D()** so you do not have to code all
these operations.
-Code
-----
-
--# **What does this program do?**
- - Loads an image
- - Performs a *normalized box filter*. For instance, for a kernel of size \f$size = 3\f$, the
- kernel would be:
+### What does this program do?
+- Loads an image
+- Performs a *normalized box filter*. For instance, for a kernel of size \f$size = 3\f$, the
+ kernel would be:
- \f[K = \dfrac{1}{3 \cdot 3} \begin{bmatrix}
- 1 & 1 & 1 \\
+\f[K = \dfrac{1}{3 \cdot 3} \begin{bmatrix}
+1 & 1 & 1 \\
1 & 1 & 1 \\
1 & 1 & 1
- \end{bmatrix}\f]
+\end{bmatrix}\f]
+
+The program will perform the filter operation with kernels of sizes 3, 5, 7, 9 and 11.
- The program will perform the filter operation with kernels of sizes 3, 5, 7, 9 and 11.
+- The filter output (with each kernel) will be shown during 500 milliseconds
- - The filter output (with each kernel) will be shown during 500 milliseconds
+Code
+----
--# The tutorial code's is shown lines below. You can also download it from
- [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/filter2D_demo.cpp)
- @include cpp/tutorial_code/ImgTrans/filter2D_demo.cpp
+The tutorial code's is shown in the lines below.
+
+@add_toggle_cpp
+You can also download it from
+[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgTrans/filter2D_demo.cpp)
+@include cpp/tutorial_code/ImgTrans/filter2D_demo.cpp
+@end_toggle
+
+@add_toggle_java
+You can also download it from
+[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/java/tutorial_code/ImgTrans/Filter2D/Filter2D_Demo.java)
+@include java/tutorial_code/ImgTrans/Filter2D/Filter2D_Demo.java
+@end_toggle
+
+@add_toggle_python
+You can also download it from
+[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/python/tutorial_code/ImgTrans/Filter2D/filter2D.py)
+@include python/tutorial_code/ImgTrans/Filter2D/filter2D.py
+@end_toggle
Explanation
-----------
--# Load an image
- @snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp load
--# Initialize the arguments for the linear filter
- @snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp init_arguments
--# Perform an infinite loop updating the kernel size and applying our linear filter to the input
- image. Let's analyze that more in detail:
--# First we define the kernel our filter is going to use. Here it is:
- @snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp update_kernel
- The first line is to update the *kernel_size* to odd values in the range: \f$[3,11]\f$. The second
- line actually builds the kernel by setting its value to a matrix filled with \f$1's\f$ and
- normalizing it by dividing it between the number of elements.
-
--# After setting the kernel, we can generate the filter by using the function @ref cv::filter2D :
- @snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp apply_filter
- The arguments denote:
-
- -# *src*: Source image
- -# *dst*: Destination image
- -# *ddepth*: The depth of *dst*. A negative value (such as \f$-1\f$) indicates that the depth is
+#### Load an image
+
+@add_toggle_cpp
+@snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp load
+@end_toggle
+
+@add_toggle_java
+@snippet java/tutorial_code/ImgTrans/Filter2D/Filter2D_Demo.java load
+@end_toggle
+
+@add_toggle_python
+@snippet python/tutorial_code/ImgTrans/Filter2D/filter2D.py load
+@end_toggle
+
+#### Initialize the arguments
+
+@add_toggle_cpp
+@snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp init_arguments
+@end_toggle
+
+@add_toggle_java
+@snippet java/tutorial_code/ImgTrans/Filter2D/Filter2D_Demo.java init_arguments
+@end_toggle
+
+@add_toggle_python
+@snippet python/tutorial_code/ImgTrans/Filter2D/filter2D.py init_arguments
+@end_toggle
+
+##### Loop
+
+Perform an infinite loop updating the kernel size and applying our linear filter to the input
+image. Let's analyze that more in detail:
+
+- First we define the kernel our filter is going to use. Here it is:
+
+@add_toggle_cpp
+@snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp update_kernel
+@end_toggle
+
+@add_toggle_java
+@snippet java/tutorial_code/ImgTrans/Filter2D/Filter2D_Demo.java update_kernel
+@end_toggle
+
+@add_toggle_python
+@snippet python/tutorial_code/ImgTrans/Filter2D/filter2D.py update_kernel
+@end_toggle
+
+The first line is to update the *kernel_size* to odd values in the range: \f$[3,11]\f$.
+The second line actually builds the kernel by setting its value to a matrix filled with
+\f$1's\f$ and normalizing it by dividing it between the number of elements.
+
+- After setting the kernel, we can generate the filter by using the function **filter2D()** :
+
+@add_toggle_cpp
+@snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp apply_filter
+@end_toggle
+
+@add_toggle_java
+@snippet java/tutorial_code/ImgTrans/Filter2D/Filter2D_Demo.java apply_filter
+@end_toggle
+
+@add_toggle_python
+@snippet python/tutorial_code/ImgTrans/Filter2D/filter2D.py apply_filter
+@end_toggle
+
+- The arguments denote:
+ - *src*: Source image
+ - *dst*: Destination image
+ - *ddepth*: The depth of *dst*. A negative value (such as \f$-1\f$) indicates that the depth is
the same as the source.
- -# *kernel*: The kernel to be scanned through the image
- -# *anchor*: The position of the anchor relative to its kernel. The location *Point(-1, -1)*
- indicates the center by default.
- -# *delta*: A value to be added to each pixel during the correlation. By default it is \f$0\f$
- -# *BORDER_DEFAULT*: We let this value by default (more details in the following tutorial)
+ - *kernel*: The kernel to be scanned through the image
+ - *anchor*: The position of the anchor relative to its kernel. The location *Point(-1, -1)*
+ indicates the center by default.
+ - *delta*: A value to be added to each pixel during the correlation. By default it is \f$0\f$
+ - *BORDER_DEFAULT*: We let this value by default (more details in the following tutorial)
--# Our program will effectuate a *while* loop, each 500 ms the kernel size of our filter will be
+- Our program will effectuate a *while* loop, each 500 ms the kernel size of our filter will be
updated in the range indicated.
Results
result should be a window that shows an image blurred by a normalized filter. Each 0.5 seconds
the kernel size should change, as can be seen in the series of snapshots below:
- ![](images/filter_2d_tutorial_result.jpg)
+![](images/filter_2d_tutorial_result.jpg)
*/
int main ( int argc, char** argv )
{
- /// Declare variables
- Mat src, dst;
+ // Declare variables
+ Mat src, dst;
- Mat kernel;
- Point anchor;
- double delta;
- int ddepth;
- int kernel_size;
- const char* window_name = "filter2D Demo";
+ Mat kernel;
+ Point anchor;
+ double delta;
+ int ddepth;
+ int kernel_size;
+ const char* window_name = "filter2D Demo";
- //![load]
- String imageName("../data/lena.jpg"); // by default
- if (argc > 1)
- {
- imageName = argv[1];
- }
- src = imread( imageName, IMREAD_COLOR ); // Load an image
+ //![load]
+ const char* imageName = argc >=2 ? argv[1] : "../data/lena.jpg";
- if( src.empty() )
- { return -1; }
- //![load]
+ // Loads an image
+ src = imread( imageName, IMREAD_COLOR ); // Load an image
- //![init_arguments]
- /// Initialize arguments for the filter
- anchor = Point( -1, -1 );
- delta = 0;
- ddepth = -1;
- //![init_arguments]
+ if( src.empty() )
+ {
+ printf(" Error opening image\n");
+ printf(" Program Arguments: [image_name -- default ../data/lena.jpg] \n");
+ return -1;
+ }
+ //![load]
- /// Loop - Will filter the image with different kernel sizes each 0.5 seconds
- int ind = 0;
- for(;;)
- {
- char c = (char)waitKey(500);
- /// Press 'ESC' to exit the program
- if( c == 27 )
- { break; }
+ //![init_arguments]
+ // Initialize arguments for the filter
+ anchor = Point( -1, -1 );
+ delta = 0;
+ ddepth = -1;
+ //![init_arguments]
- //![update_kernel]
- /// Update kernel size for a normalized box filter
- kernel_size = 3 + 2*( ind%5 );
- kernel = Mat::ones( kernel_size, kernel_size, CV_32F )/ (float)(kernel_size*kernel_size);
- //![update_kernel]
+ // Loop - Will filter the image with different kernel sizes each 0.5 seconds
+ int ind = 0;
+ for(;;)
+ {
+ //![update_kernel]
+ // Update kernel size for a normalized box filter
+ kernel_size = 3 + 2*( ind%5 );
+ kernel = Mat::ones( kernel_size, kernel_size, CV_32F )/ (float)(kernel_size*kernel_size);
+ //![update_kernel]
- //![apply_filter]
- filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT );
- //![apply_filter]
- imshow( window_name, dst );
- ind++;
- }
+ //![apply_filter]
+ // Apply filter
+ filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT );
+ //![apply_filter]
+ imshow( window_name, dst );
- return 0;
+ char c = (char)waitKey(500);
+ // Press 'ESC' to exit the program
+ if( c == 27 )
+ { break; }
+
+ ind++;
+ }
+
+ return 0;
}
--- /dev/null
+/**
+ * @file Filter2D_demo.java
+ * @brief Sample code that shows how to implement your own linear filters by using filter2D function
+ */
+
+import org.opencv.core.*;
+import org.opencv.core.Point;
+import org.opencv.highgui.HighGui;
+import org.opencv.imgcodecs.Imgcodecs;
+import org.opencv.imgproc.Imgproc;
+
+class Filter2D_DemoRun {
+
+ public void run(String[] args) {
+ // Declare variables
+ Mat src, dst = new Mat();
+
+ Mat kernel = new Mat();
+ Point anchor;
+ double delta;
+ int ddepth;
+ int kernel_size;
+ String window_name = "filter2D Demo";
+
+ //! [load]
+ String imageName = ((args.length > 0) ? args[0] : "../data/lena.jpg");
+
+ // Load an image
+ src = Imgcodecs.imread(imageName, Imgcodecs.IMREAD_COLOR);
+
+ // Check if image is loaded fine
+ if( src.empty() ) {
+ System.out.println("Error opening image!");
+ System.out.println("Program Arguments: [image_name -- default ../data/lena.jpg] \n");
+ System.exit(-1);
+ }
+ //! [load]
+
+ //! [init_arguments]
+ // Initialize arguments for the filter
+ anchor = new Point( -1, -1);
+ delta = 0.0;
+ ddepth = -1;
+ //! [init_arguments]
+
+ // Loop - Will filter the image with different kernel sizes each 0.5 seconds
+ int ind = 0;
+ while( true )
+ {
+ //! [update_kernel]
+ // Update kernel size for a normalized box filter
+ kernel_size = 3 + 2*( ind%5 );
+ Mat ones = Mat.ones( kernel_size, kernel_size, CvType.CV_32F );
+ Core.multiply(ones, new Scalar(1/(double)(kernel_size*kernel_size)), kernel);
+ //! [update_kernel]
+
+ //! [apply_filter]
+ // Apply filter
+ Imgproc.filter2D(src, dst, ddepth , kernel, anchor, delta, Core.BORDER_DEFAULT );
+ //! [apply_filter]
+ HighGui.imshow( window_name, dst );
+
+ int c = HighGui.waitKey(500);
+ // Press 'ESC' to exit the program
+ if( c == 27 )
+ { break; }
+
+ ind++;
+ }
+
+ System.exit(0);
+ }
+}
+
+public class Filter2D_Demo {
+ public static void main(String[] args) {
+ // Load the native library.
+ System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
+ new Filter2D_DemoRun().run(args);
+ }
+}