OpenCV  4.2.0
Open Source Computer Vision
More Morphology Transformations

Prev Tutorial: Eroding and Dilating
Next Tutorial: Hit-or-Miss

Goal

In this tutorial you will learn how to:

  • Use the OpenCV function cv::morphologyEx to apply Morphological Transformation such as:
    • Opening
    • Closing
    • Morphological Gradient
    • Top Hat
    • Black Hat

Theory

Note
The explanation below belongs to the book Learning OpenCV by Bradski and Kaehler.

In the previous tutorial we covered two basic Morphology operations:

  • Erosion
  • Dilation.

Based on these two we can effectuate more sophisticated transformations to our images. Here we discuss briefly 5 operations offered by OpenCV:

Opening

  • It is obtained by the erosion of an image followed by a dilation.

    \[dst = open( src, element) = dilate( erode( src, element ) )\]

  • Useful for removing small objects (it is assumed that the objects are bright on a dark 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 dots have disappeared.

Closing

  • It is obtained by the dilation of an image followed by an erosion.

    \[dst = close( src, element ) = erode( dilate( src, element ) )\]

  • Useful to remove small holes (dark regions).

Morphological Gradient

  • It is the difference between the dilation and the erosion of an image.

    \[dst = morph_{grad}( src, element ) = dilate( src, element ) - erode( src, element )\]

  • It is useful for finding the outline of an object as can be seen below:

Top Hat

  • It is the difference between an input image and its opening.

    \[dst = tophat( src, element ) = src - open( src, element )\]

Black Hat

  • It is the difference between the closing and its input image

    \[dst = blackhat( src, element ) = close( src, element ) - src\]

Code

Explanation

  1. 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:
      • The first trackbar Operator returns the kind of morphology operation to use (morph_operator).
        createTrackbar("Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat", window_name, &morph_operator, max_operator, Morphology_Operations );
      • The second trackbar Element returns morph_elem, which indicates what kind of structure our kernel is:
        createTrackbar( "Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name,
        &morph_elem, max_elem,
        Morphology_Operations );
      • The final trackbar Kernel Size returns the size of the kernel to be used (morph_size)
        createTrackbar( "Kernel size:\n 2n +1", window_name,
        &morph_size, max_kernel_size,
        Morphology_Operations );
    • Every time we move any slider, the user's function Morphology_Operations will be called to effectuate a new morphology operation and it will update the output image based on the current trackbar values.
      void Morphology_Operations( int, void* )
      {
      // Since MORPH_X : 2,3,4,5 and 6
      int operation = morph_operator + 2;
      Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
      morphologyEx( src, dst, operation, element );
      imshow( window_name, dst );
      }
      We can observe that the key function to perform the morphology transformations is cv::morphologyEx . In this example we use four arguments (leaving the rest as defaults):
      • src : Source (input) image
      • dst: Output image
      • operation: The kind of morphology transformation to be performed. Note that we have 5 alternatives:

        • Opening: MORPH_OPEN : 2
        • Closing: MORPH_CLOSE: 3
        • Gradient: MORPH_GRADIENT: 4
        • Top Hat: MORPH_TOPHAT: 5
        • Black Hat: MORPH_BLACKHAT: 6

        As you can see the values range from <2-6>, that is why we add (+2) to the values entered by the Trackbar:

        int operation = morph_operator + 2;
      • element: The kernel to be used. We use the function cv::getStructuringElement to define our own structure.

Results

  • After compiling the code above we can execute it giving an image path as an argument. Results using the image: baboon.png:

  • And here are two snapshots of the display window. The first picture shows the output after using the operator Opening with a cross kernel. The second picture (right side, shows the result of using a Blackhat operator with an ellipse kernel.

cv::String
std::string String
Definition: cvstd.hpp:150
cv::IMREAD_COLOR
@ IMREAD_COLOR
If set, always convert image to the 3 channel BGR color image.
Definition: imgcodecs.hpp:67
cv::morphologyEx
void morphologyEx(InputArray src, OutputArray dst, int op, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar &borderValue=morphologyDefaultBorderValue())
Performs advanced morphological transformations.
cv::samples::findFile
cv::String findFile(const cv::String &relative_path, bool required=true, bool silentMode=false)
Try to find requested data file.
cv::waitKey
int waitKey(int delay=0)
Waits for a pressed key.
highgui.hpp
cv::namedWindow
void namedWindow(const String &winname, int flags=WINDOW_AUTOSIZE)
Creates a window.
cv::Size
Size2i Size
Definition: types.hpp:347
cv::getTrackbarPos
int getTrackbarPos(const String &trackbarname, const String &winname)
Returns the trackbar position.
cv::imread
Mat imread(const String &filename, int flags=IMREAD_COLOR)
Loads an image from a file.
cv::Mat::empty
bool empty() const
Returns true if the array has no elements.
imgcodecs.hpp
cv::dnn::print
static void print(const MatShape &shape, const String &name="")
Definition: shape_utils.hpp:188
cv::imshow
void imshow(const String &winname, InputArray mat)
Displays an image in the specified window.
cv::Point
Point2i Point
Definition: types.hpp:194
cv::Mat
n-dimensional dense array class
Definition: mat.hpp:792
cv::imshow
void imshow(const String &winname, const ogl::Texture2D &tex)
Displays OpenGL 2D texture in the specified window.
cv::CommandLineParser
Designed for command line parsing.
Definition: utility.hpp:797
cv::createTrackbar
int createTrackbar(const String &trackbarname, const String &winname, int *value, int count, TrackbarCallback onChange=0, void *userdata=0)
Creates a trackbar and attaches it to the specified window.
cv
"black box" representation of the file storage associated with a file on disk.
Definition: affine.hpp:52
cv::getStructuringElement
Mat getStructuringElement(int shape, Size ksize, Point anchor=Point(-1,-1))
Returns a structuring element of the specified size and shape for morphological operations.
imgproc.hpp
cv::WINDOW_AUTOSIZE
@ WINDOW_AUTOSIZE
the user cannot resize the window, the size is constrainted by the image displayed.
Definition: highgui.hpp:184
cv::add
void add(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray(), int dtype=-1)
Calculates the per-element sum of two arrays or an array and a scalar.