Introduction
In the last tutorial, we saw several morphological operations such as Opening and Closing. In this tutorial I will show you yet another morphological operation – Hit-or-Miss. I will present it in a separate tutorial because it is more complex than the rest of the morphological operations and will require extra explanations. We will still use the same OpenCV function that we did before, but this time there will be a difference in the structuring element. I will provide you an explanation and a source code. Hopefully, this tutorial will be useful to you.
Hit-or-Miss morphology operation
The Hit-or-Miss operation is a general binary morphological operation that can be used to look for particular patterns of pixels in a binary image. Again, it uses a combination of operations like erode for the calculation. The Hit-or-Miss operation uses two structuring elements, which we will combine into one. Firstly, the operation erodes the image with the first structuring element (or in our case, with the combined element). Then it erodes the complemented image with the second structuring element (again, the combined one). Lastly, it ANDs the results from the first two steps. More information is available here and here.
Explanation of the operation
Here is a brief explanation on how the Hit-or-Miss operation works. Let us assume we have a binary image or set of data, which looks like this:
Now we want to find the following pattern in this image:
The gray value here means that we do not care about the color (both black and white are acceptable). Therefore, we want to find three white pixels and one black pixel on top of them. We will divide the image data into 3×3 matrices and check all of them against the pattern. Once we find such a pattern, the middle pixel will become white. If the matrix we are currently looking at is not as the pattern, the middle pixel will become black. The result on the above image data is as follow:
As you can see, the second row matches the pattern. For example, when we take a matrix that consists of the first three rows and columns, the middle pixel will be black; the bottom three pixels will be white; the rest pixels do not matter. It matches the pattern so we make the middle pixel (pixel[2,2]) white. This goes on for all other matrices.
Another pattern example
Let us consider the same image data but this time with another patter. The pattern will look like this:
Using this pattern, we will find all vertical white lines. The result will look like this:
You can see from the first example that using horizontal line pattern we can find all horizontal lines in the image. In addition, by using a vertical line, we can find all the vertical line pixels.
The structuring element
Above you saw that we have three different colors in the structuring element. We need to describe them in OpenCV. Therefore, we do it in the following way: For the gray pixels (those we do not care what their color will be) we use zero (0). For the white pixels we use one (1) and for the black pixels – minus one (-1). The first structuring element’s matrix will look like this:
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Respectively, the second structuring element will look like this:
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
The source code for the Hit-or-Miss operation
Hit-Or-Miss on a binary image
Let’s first see how to apply hit-or-miss on a binary image. Below is the source code and some explanation.
// Applies the Hit-or-Miss on a image void applyHitOrMissImage() { // Path to the input image std::string l_pathToInputImage{ "../Resources/loveSymbol.jpg" }; // Create an object to hold the image data of the first image Mat l_image; // Read the image date from a file in grayscale because 8UC1 format is required l_image = imread(l_pathToInputImage, IMREAD_GRAYSCALE); // Check if we have read the first image data correctly if (!l_image.data) { std::cout << "No image data \n"; return; } // Create the output image matrix Mat l_outputImage = l_image.clone(); // Creating the structuring element for the morphological operation Mat kernel = (Mat_<int>(3, 3) << 0, 0, 0, 0, -1, 0, 1, 1, 1 ); // Applying the Gradient Morphological operation morphologyEx( l_image, l_outputImage, MORPH_HITMISS, kernel ); // Display the input image namedWindow("Input", WINDOW_NORMAL); cv::imshow("Input", l_image); // Display the result image namedWindow("Result", WINDOW_NORMAL); cv::imshow("Result", l_outputImage); }
As usual, we load one image and check if it is loaded correctly. Then we clone the image because we want to apply operation on another image, while preserving the original image. I strongly encourage you to try on your side not to use a new image for applying the operations but rather use the same image as an input and output. This will give you different results.
Next step is to create one matrix for the structuring element. I am creating one 3×3 matrix and as I mentioned above I define the colors – 0 for not-care. -1 for black and 1 for white. Then using the morphologyEx() function and this time setting the operation to MORPH_HITMISS I am applying the operation. In the previous tutorial, I already showed how to use this function. Lastly, I am displaying the result.

As you can probably see just some of the borders (the top borders) are visible. This is due to the fact that we were only looking for one white bottom row of pixels with top black pixels on it. Only the top borders satisfy this requirement.
Hit-Or-Miss on a data set
The next example shows how to apply the Hit-Or-Miss on a matrix data set. It is the same as the previous one, only difference is that we do not load an image but instead we have one hard-coded matrix. Here is the source code.
// Applies the Hit-or-Miss on a set of data void applyHitOrMissMatrix() { Mat l_image = (Mat_<uchar>(8, 10) << 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255); // Create the output image matrix Mat l_outputImage = l_image.clone(); // Creating the structuring element for the morphological operation Mat kernel = (Mat_<int>(3, 3) << 0, 0, 0, 0, -1, 0, 1, 1, 1); // Applying the Gradient Morphological operation morphologyEx(l_image, l_outputImage, MORPH_HITMISS, kernel); // Display the input image namedWindow("Input", WINDOW_NORMAL); cv::imshow("Input", l_image); // Display the result image namedWindow("Result", WINDOW_NORMAL); cv::imshow("Result", l_outputImage); }
Here is the result, which I get. You can play with the input matrix and the structuring element and change it to observe some different results. The result I get is similar to what I have described above.

Conclusion
In the tutorial we have got familiar with yet another morphology operation – Hit-or-Miss. We saw how to apply it on an image or just on a set of pixel values in one matrix. This operation is very useful for searching a given pattern in a set of pixels. Sure, you will meet this transformation.
The code is again available on GitHub and as an archive below.
Next time we will see how to generate image pyramids.

Passionate developer, loving husband and caring father. As an introvert programming is my life. I work as a senior software engineer in a big international company. My hobbies include playing computer games (mostly World of Warcraft), watching TV series and hiking.