[OpenCV Getting Started Tutorial 10] Morphological Image Processing (I): Dilation and Erosion[Copy link]
This post was last edited by Rambo on 2017-12-27 14:28
In this article, we explored the most basic morphological operations in image processing - dilation and erosion. Qianmo kindly reminded at the beginning of the article that the effect of using people's photos for erosion and dilation will be more horrifying and destroy your worldview. It is not recommended to try... OK, let's get started. Let's put a screenshot first: 1. Explanation of theories and concepts - from phenomenon to essence 1.1 Overview of Morphology The term morphology usually refers to a branch of biology that studies the form and structure of plants and animals. When we refer to morphology in image processing, we often mean mathematical morphology. Let’s take a look at the concept of mathematical morphology. Mathematical morphology is an image analysis discipline based on lattice theory and topology, and is the basic theory of mathematical morphological image processing. Its basic operations include: binary erosion and expansion, binary opening and closing operations, skeleton extraction, limit erosion, hit-hit-miss transformation, morphological gradient, Top-hat transformation, particle analysis, watershed transformation, gray value erosion and expansion, gray value opening and closing operations, gray value morphological gradient, etc. Simply put, morphological operations are a series of image processing operations based on shapes. OpenCV provides fast and convenient functions for morphological transformation of images. There are two most basic morphological operations, namely dilation and erosion. Dilation and erosion can achieve a variety of functions, mainly as follows:
Eliminate noise
Isolate independent image elements and connect adjacent elements in the image.
Find obvious maximum or minimum areas in the image
Find the gradient of the image
Here we give the original image of the "light ink" brush calligraphy that will be used below to compare the expansion and erosion operations:
Before explaining erosion and dilation, we must first note that erosion and dilation refer to the white part (highlight part), not the black part. Dilation is the expansion of the highlight part in the image, "domain expansion", and the effect image has a larger highlight area than the original image. Erosion is the erosion of the highlight part in the original image, "domain erosion", and the effect image has a smaller highlight area than the original image. 1.2 Dilation In fact, dilation is the operation of finding the local maximum. Mathematically speaking, dilation or erosion operation is to convolve the image (or a part of the image, which we call A) with the kernel (which we call B). The kernel can be of any shape and size. It has a single defined reference point, which we call an anchor point. In most cases, the kernel is a small square or disk with a reference point and a solid center. In fact, we can think of the kernel as a template or mask. Dilation is the operation of finding the local maximum value. The kernel B is convolved with the graph, that is, the maximum value of the pixel points in the area covered by the kernel B is calculated, and this maximum value is assigned to the pixel specified by the reference point. This will gradually increase the highlight area in the image. As shown in the figure below, this is the original intention of the dilation operation. Mathematical expression of expansion:
Expansion effect diagram (brush calligraphy):
Photo expansion effect diagram: 1.3 Erosion Let's take a look at erosion. As you all know, dilation and erosion are good friends and opposite operations, so erosion is the operation of finding the local minimum. We usually understand and learn about corrosion and expansion together. As you can see below, the function prototypes of the two are basically the same. Schematic diagram: Mathematical expression of corrosion:
Corrosion effect diagram (brush calligraphy):
Photo corrosion effect diagram: Light ink means this dog is super cute: D 2. In-depth - OpenCV source code analysis and tracing Go directly to the source code. Starting from line 1353 in the ...\opencv\sources\modules\imgproc\src\ morph.cpp path is the source code of the erode (erosion) function, and line 1361 is the source code of the dilate (expansion) function. [cpp]view plaincopy
//------------------------ ---------------[erode() function Chinese annotated version source code]------------------------- --- // Note: The following code is from the official source code of the computer open source vision library OpenCV // OpenCV source code version: 2.4.8 // Source code path: ...\opencv\sources\modules\imgproc\src\ morph.cpp // Source file The starting line number of the following code: 1353 lines // Chinese comments by Qianmo //------------------------------ -------------------------------------------------- ------------------------ void cv::erode( InputArray src, OutputArraydst, InputArray kernel, Point anchor, int iterations, int borderType, constScalar& borderValue ) { //Call the morphOp function and set the identifier to MORPH_ERODE morphOp( MORPH_ERODE, src, dst, kernel, anchor, iterations, borderType, borderValue ); } [/backcolor] [backcolor=rgb(231, 229, 220)][font=Consolas, "][size=12px][color=silver][backcolor=rgb(248, 248, 248)][font=Verdana, Geneva, Arial, Helvetica, sans-serif][size=9px][b][cpp] [/b] [color=rgb(12, 137, 207)][backcolor=inherit][size=9px][url=http://blog.csdn.net/poem_qianmo/article/details/23710721#]view plain[/url][/size][/backcolor][ /color] [color=rgb(12, 137, 207)][backcolor=inherit][size=9px][url=http://blog.csdn.net/poem_qianmo/article/details/23710721#]copy[/url][/size][/backcolor][/ color] [/size][/font][/backcolor][/color] [list=1] [*][code]//--------------------- --------------[Dilate() function Chinese annotated version source code]------------------------- --- // Description: The following code is from the official source code of the computer open source vision library OpenCV // OpenCV source code version: 2.4.8 // Source code path: ...\opencv\sources\modules\imgproc\src\ morph. cpp // The starting line number of the following code in the source file: 1361 lines // Chinese comments by Qianmo //------------------------- -------------------------------------------------- ----------------------------- void cv::dilate( InputArray src,OutputArray dst, InputArray kernel, Point anchor, int iterations, int borderType, constScalar& borderValue ) { //Call the morphOp function and set the identifier to MORPH_DILATE morphOp( MORPH_DILATE, src, dst, kernel, anchor, iterations, borderType,borderValue ); }
复制代码
It can be found that the two functions erode and dilate call morphOp internally, but when they call morphOp, the first The two parameter identifiers are different, one is MORPH_ERODE (erosion) and the other is MORPH_DILATE (dilation). The source code of the morphOp function is in ...\opencv\sources\modules Interested friends can study line 1286 in \imgproc\src\morph.cpp, so I won’t waste time and space analyzing it here. 14px] [ color=rgb(204, 0,0)]3. Simple introduction - API function quick start3.1 Morphological expansion - dilate function The erode function uses the local maximum operator in the pixel neighborhood to dilate an image, input from src and output from dst. Supports in-place operations. Function prototype: [cpp]view plaincopy
C++: void dilate( InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() );
复制代码
Detailed explanation of parameters:
The first parameter, src of InputArray type, is the input image, i.e. the source image, which can be filled with an object of Mat class. The number of image channels can be arbitrary, but the image depth should be one of CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.
The second parameter, dst of OutputArray type, is the target image, which needs to have the same size and type as the source image.
The third parameter, kernel of InputArray type, is the kernel of the dilation operation. If it is NULL, it means using a kernel with the reference point at the center of 3x3.
We usually use the getStructuringElement function with this parameter. The getStructuringElement function returns a structure element (kernel matrix) of a specified shape and size.
The first parameter of the getStructuringElement function represents the shape of the kernel. We can choose one of the following three shapes:
Rectangle: MORPH_RECT
Cross: MORPH_CROSS
Ellipse: MORPH_ELLIPSE The second and third parameters of the getStructuringElement function are the size of the kernel and the position of the anchor point respectively.
Before calling the erode and dilate functions, we usually define a variable of type Mat to obtain the return value of the getStructuringElement function. For the position of the anchor point, there is a default value of Point(-1,-1), which means that the anchor point is located at the center. And it should be noted that the shape of the cross element depends solely on the position of the anchor point. In other cases, the anchor point only affects the offset of the morphological operation result.
The example code related to the call of the getStructuringElement function is as follows: [cpp]view plaincopy
int g_nStructElementSize = 3; //Size of the structure element (kernel matrix)
After calling this, we can fill in the third parameter with the Mat type variable that saves the return value of getStructuringElement when calling the erode or dilate function next time. Corresponding to the example above, it is to fill in the element variable.
The fourth parameter, anchor of type Point, is the location of the anchor. It has a default value of (-1, -1), which means the anchor is at the center.
The fifth parameter, iterations of type int, is the number of times the erode() function is iterated. The default value is 1.
The sixth parameter, borderType of type int, is used to infer a certain border mode for pixels outside the image. Note that it has a default value of BORDER_DEFAULT.
The seventh parameter, borderValue of const Scalar& type, has a default value of morphologyDefaultBorderValue() when the border is a constant. Generally, we don't need to care about it. When you need to use it, you can refer to the createMorphologyFilter() function in the official documentation for a more detailed explanation.
Using the erode function, generally we only need to fill in the first three parameters, and the following four parameters have default values. And it is often used in conjunction with getStructuringElement. Calling example: [cpp]view plaincopy
//Load the original image
Mat image = imread("1.jpg");
//Get custom kernel
Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
//----------------------------------[Header file includes part]--------------------------------------- // Description: Contains header files that the program depends on//---------------------------------------------------------------------------------------------- #include
#include
#include
#include
//-----------------------------------[Namespace declaration part]--------------------------------------- // Description: Contains the namespaces used by the program//----------------------------------------------------------------------------------------------- using namespace std; using namespace cv; //-----------------------------------[main() function]-------------------------------------------- // Description: The entry function of the console application, our program starts here//----------------------------------------------------------------------------------------------- int main() { //Load the original image Mat image = imread("1.jpg"); //Create a window namedWindow("【Original image】Expansion operation"); namedWindow("【Effect image】Expansion operation"); //Display the original image imshow("【Original image】Expansion operation", image);
//Get the custom kernel Mat element = getStructuringElement(MORPH_RECT, Size(15, 15)); Mat out;
Run screenshot: 3.2 Morphological Erosion - Erode Function The erode function, which uses the local minimum operator within the pixel neighborhood to erode an image, is input from src and output by dst. Supports in-place operations. Look at the function prototype: [cpp]view plaincopy
C++: void erode( InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT,const Scalar& borderValue=morphologyDefaultBorderValue() );
复制代码
Parameter explanation:
The first parameter, src of InputArray type, input image, that is, source image, can be filled with Mat class object. The number of image channels can be arbitrary, but the image depth should be one of CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.
The second parameter, dst of OutputArray type, that is, target image, needs to have the same size and type as the source image.
The third parameter, kernel of InputArray type, kernel of erosion operation. If it is NULL, it means using the kernel with the reference point at the center 3x3. We usually use the function getStructuringElement in conjunction with this parameter. The getStructuringElement function returns a structural element (kernel matrix) of a specified shape and size. (For details, see the third parameter of the dilate function in the above article)
The fourth parameter, anchor of type Point, is the position of the anchor. It has a default value of (-1, -1), indicating that the anchor is located at the center of the unit (element). We generally don't need to care about it.
The fifth parameter, iterations of type int, is the number of times the erode() function is iterated. The default value is 1.
The sixth parameter, borderType of type int, is used to infer a certain border pattern of the pixels outside the image. Note that it has a default value of BORDER_DEFAULT.
The seventh parameter, borderValue of type const Scalar&, is the border value when the border is a constant. It has a default value of morphologyDefaultBorderValue(). Generally, we don't need to care about it. When you need to use it, you can see the createMorphologyFilter() function in the official documentation for a more detailed explanation. Similarly, when using the erode function, we usually only need to fill in the first three parameters, and the following four parameters have default values. And it is often used in conjunction with getStructuringElement. Calling example: [cpp]view plaincopy
//Load the original image
Mat image = imread("1.jpg");
//Get custom kernel
Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
Mat out;
//Perform erosion operation
erode(image,out, element);
The complete program code built with the above core code: [cpp]view plaincopy
//-----------------------------------[Header file includes part]--------------------------------------- // Description: Contains header files that the program depends on//---------------------------------------------------------------------------------------------- #include<opencv2 core="" core.hpp="">
#include<opencv2 highgui="" highgui.hpp="">
#include<opencv2 imgproc="" imgproc.hpp="">
#include<iostream>
//-----------------------------------[Namespace declaration part]--------------------------------------- // Description: Contains the namespaces used by the program//----------------------------------------------------------------------------------------------- using namespace std; using namespace cv; //-----------------------------------[main() function]-------------------------------------------- // Description: The entry function of the console application, our program starts here//----------------------------------------------------------------------------------------------- int main() { //Load the original image Matimage = imread("1.jpg"); //Create a window namedWindow("【Original image】Erosion operation"); namedWindow("【Effect image】Erosion operation"); //Display the original image imshow("【Original image】Erosion operation", image); //Get custom kernel Mat element = getStructuringElement(MORPH_RECT, Size(15, 15)); Mat out; //Perform corrosion operation erode(image,out, element); //Display the effect image imshow("【Effect image】Erosion operation", out); waitKey(0); return 0; }
复制代码
Running results: 4. Comprehensive Examples - Familiarity in Actual Combat As always, each article will be equipped with a detailed annotated blog post supporting example program, which presents the knowledge points introduced in this article to everyone in the form of code. The effect window in this sample program has two scroll bars. As the name implies, the first scroll bar "Erosion/Dilation" is used to switch between corrosion/dilation; the second scroll bar "Kernel Size" is used to adjust the kernel size during morphological operations to obtain images with different effects. It is quite playable. Without further ado, here is the code: [cpp]view plaincopy
[code] //-----------------------------------[Program Description]---------------------------------------------- // Program name:: "[OpenCV Getting Started Tutorial 10] Morphological Image Processing (I): Dilation and Erosion" Blog supporting source code // IDE version used for development: Visual Studio 2010 // OpenCV version used for development: 2.4.8 // April 14, 2014 Created by 浅墨// 浅墨's Weibo: @浅墨_毛星云//------------------------------------------------------------------------------------------------ //-----------------------------------[Header file includes part]--------------------------------------- // Description: Includes header files that the program depends on//---------------------------------------------------------------------------------------------- #include
#include
#include
#include
//-----------------------------------[Namespace declaration part]--------------------------------------- // Description: Contains the namespace used by the program//----------------------------------------------------------------------------------------------- using namespace std; using namespace cv; //-----------------------------------[Global variable declaration part]-------------------------------------- // Description: Global variable declaration//----------------------------------------------------------------------------------------------- Mat g_srcImage, g_dstImage;//Original image and effect image int g_nTrackbarNumer = 0;//0 means erode, 1 means dilate int g_nStructElementSize = 3; //Size of structure element (kernel matrix)//-----------------------------------[Global function declaration part]-------------------------------------- // Description: Global function declaration//----------------------------------------------------------------------------------------------- void Process();//Dilation and erosion processing function void on_TrackbarNumChange(int, void *);//Callback function void on_ElementSizeChange(int, void *);//Callback function//-----------------------------------【main() function】-------------------------------------------- // Description: The entry function of the console application, our program starts here//------------------------------------------------------------------------------- int main() { //Change the console font colorsystem("color5E"); //Load the original imageg_srcImage= imread("1.jpg"); if(!g_srcImage.data ) { printf("Oh, no, error in reading srcImage~! \n"); return false; } //Display the original image namedWindow("【Original image】"); imshow("【Original image】", g_srcImage); //Perform the initial erosion operation and display the effect image namedWindow("【Effect image】"); //Get the custom kernel Mat element = getStructuringElement(MORPH_RECT, Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1),Point( g_nStructElementSize, g_nStructElementSize )); erode(g_srcImage,g_dstImage, element); imshow("【Effect image】", g_dstImage); //Create trackbar createTrackbar("Erosion/Expansion", "【Effect image】", &g_nTrackbarNumer, 1, on_TrackbarNumChange); createTrackbar("Core size", "【Effect image】",&g_nStructElementSize, 21, on_ElementSizeChange); //Output some help information cout<' [img="0,100]http://img.blog.csdn.net/20140414230512781?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9lbV9xaWFubW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast[/img]