diff --git a/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.markdown b/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.markdown index 515e6b26cb..8afcd2dea8 100644 --- a/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.markdown +++ b/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.markdown @@ -11,9 +11,6 @@ In this tutorial you will learn how to: - @ref cv::erode - @ref cv::dilate -Interesting fact ------------ - @note The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler. Morphological Operations @@ -38,19 +35,14 @@ Morphological Operations - As the kernel \f$B\f$ is scanned over the image, we compute the maximal pixel value overlapped by \f$B\f$ and replace the image pixel in the anchor point position with that maximal value. As you can deduce, this maximizing operation causes bright regions within an image to "grow" (therefore the - name *dilation*). Take the above image as an example. Applying dilation we can get: + name *dilation*). +- The dilatation operation is: \f$\texttt{dst} (x,y) = \max _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f$ + +- Take the above image as an example. Applying dilation we can get: ![](images/Morphology_1_Tutorial_Theory_Dilation.png) -The background (bright) dilates around the black regions of the letter. - -To better grasp the idea and avoid possible confusion, in this other example we have inverted the original -image such as the object in white is now the letter. We have performed two dilatations with a rectangular -structuring element of size `3x3`. - -![Left image: original image inverted, right image: resulting dilatation](images/Morphology_1_Tutorial_Theory_Dilatation_2.png) - -The dilatation makes the object in white bigger. +- The bright area of the letter dilates around the black regions of the background. ### Erosion @@ -58,31 +50,39 @@ The dilatation makes the object in white bigger. area of given kernel. - As the kernel \f$B\f$ is scanned over the image, we compute the minimal pixel value overlapped by \f$B\f$ and replace the image pixel under the anchor point with that minimal value. +- The erosion operation is: \f$\texttt{dst} (x,y) = \min _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f$ - Analagously to the example for dilation, we can apply the erosion operator to the original image - (shown above). You can see in the result below that the bright areas of the image (the - background, apparently), get thinner, whereas the dark zones (the "writing") gets bigger. + (shown above). You can see in the result below that the bright areas of the image get thinner, + whereas the dark zones gets bigger. ![](images/Morphology_1_Tutorial_Theory_Erosion.png) -In similar manner, the corresponding image results by applying erosion operation on the inverted original image (two erosions -with a rectangular structuring element of size `3x3`): - -![Left image: original image inverted, right image: resulting erosion](images/Morphology_1_Tutorial_Theory_Erosion_2.png) - -The erosion makes the object in white smaller. - Code ---- +@add_toggle_cpp This tutorial's code is shown below. You can also download it [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp) @include samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp +@end_toggle + +@add_toggle_java +This tutorial's code is shown below. You can also download it +[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java) +@include samples/java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java +@end_toggle + +@add_toggle_python +This tutorial's code is shown below. You can also download it +[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/imgProc/erosion_dilatation/morphology_1.py) +@include samples/python/tutorial_code/imgProc/erosion_dilatation/morphology_1.py +@end_toggle Explanation ----------- -# Most of the material shown here is trivial (if you have any doubt, please refer to the tutorials in - previous sections). Let's check the general structure of the program: + previous sections). Let's check the general structure of the C++ program: - Load an image (can be BGR or grayscale) - Create two windows (one for dilation output, the other for erosion) diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilatation_2.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilatation_2.png deleted file mode 100644 index bdca7c6233..0000000000 Binary files a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilatation_2.png and /dev/null differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilation.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilation.png index dae930ec1e..4f0df79ed9 100644 Binary files a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilation.png and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilation.png differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion.png index 755561023f..18e9970137 100644 Binary files a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion.png and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion.png differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion_2.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion_2.png deleted file mode 100644 index 5e666eef36..0000000000 Binary files a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion_2.png and /dev/null differ diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Original_Image.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Original_Image.png index d7e8a9a429..969294c7c6 100644 Binary files a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Original_Image.png and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Original_Image.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_BlackHat.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_BlackHat.png index ce6ff35550..969bc20f2d 100644 Binary files a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_BlackHat.png and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_BlackHat.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing.png index f112bfef11..a034ac2496 100644 Binary files a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing.png and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing_2.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing_2.png deleted file mode 100644 index 57b790583f..0000000000 Binary files a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing_2.png and /dev/null differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Gradient.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Gradient.png index 5d8077f0d2..44590016a0 100644 Binary files a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Gradient.png and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Gradient.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening.png index 7b8b0850fd..b63e99ed9d 100644 Binary files a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening.png and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening_2.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening_2.png deleted file mode 100644 index 973e13a2d2..0000000000 Binary files a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening_2.png and /dev/null differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_TopHat.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_TopHat.png index ca22789b03..18f5084ca5 100644 Binary files a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_TopHat.png and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_TopHat.png differ diff --git a/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.markdown b/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.markdown index aaf57b1732..f5042907ef 100644 --- a/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.markdown +++ b/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.markdown @@ -36,15 +36,10 @@ discuss briefly 5 operations offered by OpenCV: foreground) - For instance, check out the example below. The image at the left is the original and the image at the right is the result after applying the opening transformation. We can observe that the - small spaces in the corners of the letter tend to disappear. + small dots have disappeared. ![](images/Morphology_2_Tutorial_Theory_Opening.png) -For the sake of clarity, we have performed the opening operation (`7x7` rectangular structuring element) -on the same original image but inverted such as the object in white is now the letter. - -![Left image: original image inverted, right image: resulting opening](images/Morphology_2_Tutorial_Theory_Opening_2.png) - ### Closing - It is obtained by the dilation of an image followed by an erosion. @@ -55,10 +50,6 @@ on the same original image but inverted such as the object in white is now the l ![](images/Morphology_2_Tutorial_Theory_Closing.png) -On the inverted image, we have performed the closing operation (`7x7` rectangular structuring element): - -![Left image: original image inverted, right image: resulting closing](images/Morphology_2_Tutorial_Theory_Closing_2.png) - ### Morphological Gradient - It is the difference between the dilation and the erosion of an image. @@ -88,14 +79,28 @@ On the inverted image, we have performed the closing operation (`7x7` rectangula Code ---- -This tutorial code's is shown lines below. You can also download it from +@add_toggle_cpp +This tutorial's code is shown below. You can also download it [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Morphology_2.cpp) @include cpp/tutorial_code/ImgProc/Morphology_2.cpp +@end_toggle + +@add_toggle_java +This tutorial's code is shown below. You can also download it +[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/ImgProc/opening_closing_hats/MorphologyDemo2.java) +@include java/tutorial_code/ImgProc/opening_closing_hats/MorphologyDemo2.java +@end_toggle + +@add_toggle_python +This tutorial's code is shown below. You can also download it +[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/imgProc/opening_closing_hats/morphology_2.py) +@include python/tutorial_code/imgProc/opening_closing_hats/morphology_2.py +@end_toggle Explanation ----------- --# Let's check the general structure of the program: +-# Let's check the general structure of the C++ program: - Load an image - Create a window to display results of the Morphological operations - Create three Trackbars for the user to enter parameters: @@ -139,8 +144,8 @@ Explanation Results ------- -- After compiling the code above we can execute it giving an image path as an argument. For this - tutorial we use as input the image: **baboon.png**: +- After compiling the code above we can execute it giving an image path as an argument. Results using + the image: **baboon.png**: ![](images/Morphology_2_Tutorial_Original_Image.jpg) diff --git a/samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp b/samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp index 14526ae037..4f5ab98a93 100644 --- a/samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp +++ b/samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp @@ -31,7 +31,7 @@ void Dilation( int, void* ); int main( int argc, char** argv ) { /// Load an image - CommandLineParser parser( argc, argv, "{@input | ../data/chicky_512.png | input image}" ); + CommandLineParser parser( argc, argv, "{@input | ../data/LinuxLogo.jpg | input image}" ); src = imread( parser.get( "@input" ), IMREAD_COLOR ); if( src.empty() ) { diff --git a/samples/cpp/tutorial_code/ImgProc/Morphology_2.cpp b/samples/cpp/tutorial_code/ImgProc/Morphology_2.cpp index ce71a3b118..3619753162 100644 --- a/samples/cpp/tutorial_code/ImgProc/Morphology_2.cpp +++ b/samples/cpp/tutorial_code/ImgProc/Morphology_2.cpp @@ -33,7 +33,7 @@ void Morphology_Operations( int, void* ); int main( int argc, char** argv ) { //![load] - CommandLineParser parser( argc, argv, "{@input | ../data/baboon.jpg | input image}" ); + CommandLineParser parser( argc, argv, "{@input | ../data/LinuxLogo.jpg | input image}" ); src = imread( parser.get( "@input" ), IMREAD_COLOR ); if (src.empty()) { diff --git a/samples/cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp b/samples/cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp index d96b52a0c1..34d5733f75 100644 --- a/samples/cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp +++ b/samples/cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp @@ -36,52 +36,90 @@ int main( int argc, char ** argv ) const char* filename = argc >=2 ? argv[1] : "../data/lena.jpg"; src = imread( filename, IMREAD_COLOR ); - if(src.empty()){ + 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; } + if( display_caption( "Original Image" ) != 0 ) + { + return 0; + } dst = src.clone(); - if( display_dst( DELAY_CAPTION ) != 0 ) { return 0; } - + if( display_dst( DELAY_CAPTION ) != 0 ) + { + return 0; + } /// Applying Homogeneous blur - if( display_caption( "Homogeneous Blur" ) != 0 ) { return 0; } + 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( 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; } + 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( 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; } + 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 ( src, dst, i ); + if( display_dst( DELAY_BLUR ) != 0 ) + { + return 0; + } + } //![medianblur] /// Applying Bilateral Filter - if( display_caption( "Bilateral Blur" ) != 0 ) { return 0; } + 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 ( src, dst, i, i*2, i/2 ); + if( display_dst( DELAY_BLUR ) != 0 ) + { + return 0; + } + } //![bilateralfilter] /// Done diff --git a/samples/java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java b/samples/java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java new file mode 100644 index 0000000000..386f94a553 --- /dev/null +++ b/samples/java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java @@ -0,0 +1,155 @@ +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; + +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.opencv.core.Core; +import org.opencv.core.Mat; +import org.opencv.core.Point; +import org.opencv.core.Size; +import org.opencv.imgcodecs.Imgcodecs; +import org.opencv.imgproc.Imgproc; + +public class MorphologyDemo1 { + private static final String[] ELEMENT_TYPE = { "Rectangle", "Cross", "Ellipse" }; + private static final String[] MORPH_OP = { "Erosion", "Dilatation" }; + private static int maxKernelSize = 21; + private Mat matImgSrc; + private Mat matImgDst = new Mat(); + private int elementType = Imgproc.CV_SHAPE_RECT; + private int kernelSize = 0; + private boolean doErosion = true; + private JFrame frame; + private JLabel imgLabel; + + public MorphologyDemo1(String[] args) { + String imagePath = args.length > 0 ? args[0] : "../data/LinuxLogo.jpg"; + matImgSrc = Imgcodecs.imread(imagePath); + if (matImgSrc.empty()) { + System.out.println("Empty image: " + imagePath); + System.exit(0); + } + + // Create and set up the window. + frame = new JFrame("Erosion and dilatation demo"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + // Set up the content pane. + BufferedImage img = toBufferedImage(matImgSrc); + addComponentsToPane(frame.getContentPane(), img); + // Use the content pane's default BorderLayout. No need for + // setLayout(new BorderLayout()); + // Display the window. + frame.pack(); + frame.setVisible(true); + } + + private void addComponentsToPane(Container pane, BufferedImage img) { + if (!(pane.getLayout() instanceof BorderLayout)) { + pane.add(new JLabel("Container doesn't use BorderLayout!")); + return; + } + + JPanel sliderPanel = new JPanel(); + sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.PAGE_AXIS)); + + JComboBox elementTypeBox = new JComboBox<>(ELEMENT_TYPE); + elementTypeBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + @SuppressWarnings("unchecked") + JComboBox cb = (JComboBox)e.getSource(); + if (cb.getSelectedIndex() == 0) { + elementType = Imgproc.CV_SHAPE_RECT; + } else if (cb.getSelectedIndex() == 1) { + elementType = Imgproc.CV_SHAPE_CROSS; + } else if (cb.getSelectedIndex() == 2) { + elementType = Imgproc.CV_SHAPE_ELLIPSE; + } + update(); + } + }); + sliderPanel.add(elementTypeBox); + + sliderPanel.add(new JLabel("Kernel size: 2n + 1")); + JSlider slider = new JSlider(0, maxKernelSize, 0); + slider.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + JSlider source = (JSlider) e.getSource(); + kernelSize = source.getValue(); + update(); + } + }); + sliderPanel.add(slider); + + JComboBox morphOpBox = new JComboBox<>(MORPH_OP); + morphOpBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + @SuppressWarnings("unchecked") + JComboBox cb = (JComboBox)e.getSource(); + doErosion = cb.getSelectedIndex() == 0; + update(); + } + }); + sliderPanel.add(morphOpBox); + + pane.add(sliderPanel, BorderLayout.PAGE_START); + imgLabel = new JLabel(new ImageIcon(img)); + pane.add(imgLabel, BorderLayout.CENTER); + } + + private BufferedImage toBufferedImage(Mat matrix) { + int type = BufferedImage.TYPE_BYTE_GRAY; + if (matrix.channels() > 1) { + type = BufferedImage.TYPE_3BYTE_BGR; + } + int bufferSize = matrix.channels() * matrix.cols() * matrix.rows(); + byte[] buffer = new byte[bufferSize]; + matrix.get(0, 0, buffer); // get all the pixels + BufferedImage image = new BufferedImage(matrix.cols(), matrix.rows(), type); + final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); + System.arraycopy(buffer, 0, targetPixels, 0, buffer.length); + return image; + } + + private void update() { + Mat element = Imgproc.getStructuringElement(elementType, new Size(2 * kernelSize + 1, 2 * kernelSize + 1), + new Point(kernelSize, kernelSize)); + + if (doErosion) { + Imgproc.erode(matImgSrc, matImgDst, element); + } else { + Imgproc.dilate(matImgSrc, matImgDst, element); + } + BufferedImage img = toBufferedImage(matImgDst); + imgLabel.setIcon(new ImageIcon(img)); + frame.repaint(); + } + + public static void main(String[] args) { + // Load the native OpenCV library + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + + // Schedule a job for the event dispatch thread: + // creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + new MorphologyDemo1(args); + } + }); + } +} diff --git a/samples/java/tutorial_code/ImgProc/opening_closing_hats/MorphologyDemo2.java b/samples/java/tutorial_code/ImgProc/opening_closing_hats/MorphologyDemo2.java new file mode 100644 index 0000000000..e5d80280a9 --- /dev/null +++ b/samples/java/tutorial_code/ImgProc/opening_closing_hats/MorphologyDemo2.java @@ -0,0 +1,153 @@ +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; + +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.opencv.core.Core; +import org.opencv.core.Mat; +import org.opencv.core.Point; +import org.opencv.core.Size; +import org.opencv.imgcodecs.Imgcodecs; +import org.opencv.imgproc.Imgproc; + +public class MorphologyDemo2 { + private static final String[] MORPH_OP = { "Opening", "Closing", "Gradient", "Top Hat", "Black Hat" }; + private static final int[] MORPH_OP_TYPE = { Imgproc.MORPH_OPEN, Imgproc.MORPH_CLOSE, + Imgproc.MORPH_GRADIENT, Imgproc.MORPH_TOPHAT, Imgproc.MORPH_BLACKHAT }; + private static final String[] ELEMENT_TYPE = { "Rectangle", "Cross", "Ellipse" }; + private static int maxKernelSize = 21; + private Mat matImgSrc; + private Mat matImgDst = new Mat(); + private int morphOpType = Imgproc.MORPH_OPEN; + private int elementType = Imgproc.CV_SHAPE_RECT; + private int kernelSize = 0; + private JFrame frame; + private JLabel imgLabel; + + public MorphologyDemo2(String[] args) { + String imagePath = args.length > 0 ? args[0] : "../data/LinuxLogo.jpg"; + matImgSrc = Imgcodecs.imread(imagePath); + if (matImgSrc.empty()) { + System.out.println("Empty image: " + imagePath); + System.exit(0); + } + + // Create and set up the window. + frame = new JFrame("Morphology Transformations demo"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + // Set up the content pane. + BufferedImage img = toBufferedImage(matImgSrc); + addComponentsToPane(frame.getContentPane(), img); + // Use the content pane's default BorderLayout. No need for + // setLayout(new BorderLayout()); + // Display the window. + frame.pack(); + frame.setVisible(true); + } + + private void addComponentsToPane(Container pane, BufferedImage img) { + if (!(pane.getLayout() instanceof BorderLayout)) { + pane.add(new JLabel("Container doesn't use BorderLayout!")); + return; + } + + JPanel sliderPanel = new JPanel(); + sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.PAGE_AXIS)); + + JComboBox morphOpBox = new JComboBox<>(MORPH_OP); + morphOpBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + @SuppressWarnings("unchecked") + JComboBox cb = (JComboBox)e.getSource(); + morphOpType = MORPH_OP_TYPE[cb.getSelectedIndex()]; + update(); + } + }); + sliderPanel.add(morphOpBox); + + JComboBox elementTypeBox = new JComboBox<>(ELEMENT_TYPE); + elementTypeBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + @SuppressWarnings("unchecked") + JComboBox cb = (JComboBox)e.getSource(); + if (cb.getSelectedIndex() == 0) { + elementType = Imgproc.CV_SHAPE_RECT; + } else if (cb.getSelectedIndex() == 1) { + elementType = Imgproc.CV_SHAPE_CROSS; + } else if (cb.getSelectedIndex() == 2) { + elementType = Imgproc.CV_SHAPE_ELLIPSE; + } + update(); + } + }); + sliderPanel.add(elementTypeBox); + + sliderPanel.add(new JLabel("Kernel size: 2n + 1")); + JSlider slider = new JSlider(0, maxKernelSize, 0); + slider.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + JSlider source = (JSlider) e.getSource(); + kernelSize = source.getValue(); + update(); + } + }); + sliderPanel.add(slider); + + pane.add(sliderPanel, BorderLayout.PAGE_START); + imgLabel = new JLabel(new ImageIcon(img)); + pane.add(imgLabel, BorderLayout.CENTER); + } + + private BufferedImage toBufferedImage(Mat matrix) { + int type = BufferedImage.TYPE_BYTE_GRAY; + if (matrix.channels() > 1) { + type = BufferedImage.TYPE_3BYTE_BGR; + } + int bufferSize = matrix.channels() * matrix.cols() * matrix.rows(); + byte[] buffer = new byte[bufferSize]; + matrix.get(0, 0, buffer); // get all the pixels + BufferedImage image = new BufferedImage(matrix.cols(), matrix.rows(), type); + final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); + System.arraycopy(buffer, 0, targetPixels, 0, buffer.length); + return image; + } + + private void update() { + Mat element = Imgproc.getStructuringElement(elementType, new Size(2 * kernelSize + 1, 2 * kernelSize + 1), + new Point(kernelSize, kernelSize)); + + Imgproc.morphologyEx(matImgSrc, matImgDst, morphOpType, element); + BufferedImage img = toBufferedImage(matImgDst); + imgLabel.setIcon(new ImageIcon(img)); + frame.repaint(); + } + + public static void main(String[] args) { + // Load the native OpenCV library + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); + + // Schedule a job for the event dispatch thread: + // creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + new MorphologyDemo2(args); + } + }); + } +} diff --git a/samples/python/tutorial_code/imgProc/erosion_dilatation/morphology_1.py b/samples/python/tutorial_code/imgProc/erosion_dilatation/morphology_1.py new file mode 100644 index 0000000000..cb3af732e8 --- /dev/null +++ b/samples/python/tutorial_code/imgProc/erosion_dilatation/morphology_1.py @@ -0,0 +1,63 @@ +from __future__ import print_function +import cv2 as cv +import numpy as np +import argparse + +erosion_size = 0 +max_elem = 2 +max_kernel_size = 21 +title_trackbar_element_type = 'Element:\n 0: Rect \n 1: Cross \n 2: Ellipse' +title_trackbar_kernel_size = 'Kernel size:\n 2n +1' +title_erosion_window = 'Erosion Demo' +title_dilatation_window = 'Dilation Demo' + +def erosion(val): + erosion_size = cv.getTrackbarPos(title_trackbar_kernel_size, title_erosion_window) + erosion_type = 0 + val_type = cv.getTrackbarPos(title_trackbar_element_type, title_erosion_window) + if val_type == 0: + erosion_type = cv.MORPH_RECT + elif val_type == 1: + erosion_type = cv.MORPH_CROSS + elif val_type == 2: + erosion_type = cv.MORPH_ELLIPSE + + element = cv.getStructuringElement(erosion_type, (2*erosion_size + 1, 2*erosion_size+1), (erosion_size, erosion_size)) + erosion_dst = cv.erode(src, element) + cv.imshow(title_erosion_window, erosion_dst) + +def dilatation(val): + dilatation_size = cv.getTrackbarPos(title_trackbar_kernel_size, title_dilatation_window) + dilatation_type = 0 + val_type = cv.getTrackbarPos(title_trackbar_element_type, title_dilatation_window) + if val_type == 0: + dilatation_type = cv.MORPH_RECT + elif val_type == 1: + dilatation_type = cv.MORPH_CROSS + elif val_type == 2: + dilatation_type = cv.MORPH_ELLIPSE + + element = cv.getStructuringElement(dilatation_type, (2*dilatation_size + 1, 2*dilatation_size+1), (dilatation_size, dilatation_size)) + dilatation_dst = cv.dilate(src, element) + cv.imshow(title_dilatation_window, dilatation_dst) + +parser = argparse.ArgumentParser(description='Code for Eroding and Dilating tutorial.') +parser.add_argument('--input', help='Path to input image.', default='../data/LinuxLogo.jpg') +args = parser.parse_args() + +src = cv.imread(args.input) +if src is None: + print('Could not open or find the image: ', args.input) + exit(0) + +cv.namedWindow(title_erosion_window) +cv.createTrackbar(title_trackbar_element_type, title_erosion_window , 0, max_elem, erosion) +cv.createTrackbar(title_trackbar_kernel_size, title_erosion_window , 0, max_kernel_size, erosion) + +cv.namedWindow(title_dilatation_window) +cv.createTrackbar(title_trackbar_element_type, title_dilatation_window , 0, max_elem, dilatation) +cv.createTrackbar(title_trackbar_kernel_size, title_dilatation_window , 0, max_kernel_size, dilatation) + +erosion(0) +dilatation(0) +cv.waitKey() diff --git a/samples/python/tutorial_code/imgProc/opening_closing_hats/morphology_2.py b/samples/python/tutorial_code/imgProc/opening_closing_hats/morphology_2.py new file mode 100644 index 0000000000..5dfdece1b6 --- /dev/null +++ b/samples/python/tutorial_code/imgProc/opening_closing_hats/morphology_2.py @@ -0,0 +1,48 @@ +from __future__ import print_function +import cv2 as cv +import numpy as np +import argparse + +morph_size = 0 +max_operator = 4 +max_elem = 2 +max_kernel_size = 21 +title_trackbar_operator_type = 'Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat' +title_trackbar_element_type = 'Element:\n 0: Rect - 1: Cross - 2: Ellipse' +title_trackbar_kernel_size = 'Kernel size:\n 2n + 1' +title_window = 'Morphology Transformations Demo' +morph_op_dic = {0: cv.MORPH_OPEN, 1: cv.MORPH_CLOSE, 2: cv.MORPH_GRADIENT, 3: cv.MORPH_TOPHAT, 4: cv.MORPH_BLACKHAT} + +def morphology_operations(val): + morph_operator = cv.getTrackbarPos(title_trackbar_operator_type, title_window) + morph_size = cv.getTrackbarPos(title_trackbar_kernel_size, title_window) + morph_elem = 0 + val_type = cv.getTrackbarPos(title_trackbar_element_type, title_window) + if val_type == 0: + morph_elem = cv.MORPH_RECT + elif val_type == 1: + morph_elem = cv.MORPH_CROSS + elif val_type == 2: + morph_elem = cv.MORPH_ELLIPSE + + element = cv.getStructuringElement(morph_elem, (2*morph_size + 1, 2*morph_size+1), (morph_size, morph_size)) + operation = morph_op_dic[morph_operator] + dst = cv.morphologyEx(src, operation, element) + cv.imshow(title_window, dst) + +parser = argparse.ArgumentParser(description='Code for More Morphology Transformations tutorial.') +parser.add_argument('--input', help='Path to input image.', default='../data/LinuxLogo.jpg') +args = parser.parse_args() + +src = cv.imread(args.input) +if src is None: + print('Could not open or find the image: ', args.input) + exit(0) + +cv.namedWindow(title_window) +cv.createTrackbar(title_trackbar_operator_type, title_window , 0, max_operator, morphology_operations) +cv.createTrackbar(title_trackbar_element_type, title_window , 0, max_elem, morphology_operations) +cv.createTrackbar(title_trackbar_kernel_size, title_window , 0, max_kernel_size, morphology_operations) + +morphology_operations(0) +cv.waitKey()