二值图像处理腐蚀与膨胀
本篇博客主要介绍使用OpenCV中的函数接口实现对一个图片的腐蚀或者膨胀,听起来有点像是对图像进行放大和缩小的意思,如果你也是这样认为,那我只能说你跟我一样肤浅!!
在OpenCV中几乎所有的操作都是针对图像的像素点进行的,包括灰化,二值化,模糊化等,膨胀和腐蚀也是一样,都是针对传入图像的像素点进行操作的!!!
膨胀:
此操作将图像(A)与任意形状的内核 (B),通常为正方形或圆形,进行卷积。内核 B 有一个可定义的 锚点, 通常定义为内核中心点。进行膨胀操作时,将内核 B 划过图像,将内核 B 覆盖区域的最大相素值提取,并代替锚点位置的相素。显然,这一最大化操作将会导致图像中的亮区开始”扩展” (因此有了术语膨胀 dilation )。
这种操作会造成图像中像素值高的区域变大,而像素值小的区域变小,等一下看你一下效果你就知道了!!!
腐蚀:
跟膨胀操作造作的效果刚好相反。腐蚀在形态学操作家族里是膨胀操作的孪生姐妹。它提取的是内核覆盖下的相素最小值。进行腐蚀操作时,将内核 B 划过图像,将内核 B 覆盖区域的最小相素值提取,并代替锚点位置的相素。以与膨胀相同的图像作为样本,我们使用腐蚀操作。从下面的结果图我们看到亮区(背景)变细,而黑色区域(字母)则变大了。
下面看一下效果图:
膨胀:
腐蚀:
我感觉GIF动画的效果还是很明显的,实际程序的运行效果跟膨胀/腐蚀的理论产生的效果一致!!!
下面看一下具体实现代码:
#include <iostream>
#include <opencv2\opencv.hpp>
#include <string>
using namespace cv;
using namespace std;
int dilateSize = 1;
int erodeSize = 1;
char * dilateBar = "dilate_KSize";
char * dilate_window = "Dilate";
char * erodeBar = "erode_KSize";
char * erode_window = "Erode";
Mat source, dilate_result, erode_result,dilate_element,erode_element;
void onDilateCallBack(int position,void* userdata) {
if (position <= 0) {
position = 1;
}
dilateSize = position;
dilate_element = getStructuringElement(MORPH_RECT, Size(dilateSize, dilateSize));
dilate(source, dilate_result, dilate_element);
imshow(dilate_window, dilate_result);
}
void onErodeCallBack(int position, void* userdata) {
if (position <= 0) {
position = 1;
}
erodeSize = position;
erode_element = getStructuringElement(MORPH_RECT, Size(erodeSize, erodeSize));
erode(dilate_result, erode_result, erode_element);
imshow(erode_window, erode_result);
}
int main() {
source = imread("tw.jpg", IMREAD_COLOR);
dilate_result = Mat(source.rows,source.cols,CV_8UC3);
cvNamedWindow(dilate_window, CV_WINDOW_AUTOSIZE);
createTrackbar(dilateBar, dilate_window, &dilateSize, 50, onDilateCallBack);
onDilateCallBack(1, dilateBar);
cvNamedWindow(erode_window, CV_WINDOW_AUTOSIZE);
createTrackbar(erodeBar, erode_window, &erodeSize, 50, onErodeCallBack);
onErodeCallBack(1, erodeBar);
waitKey(0);
return 0;
}
主要的代码就是两个函数:
膨胀:
dilate(source, dilate_result, dilate_element);
看一下函数的介绍:
** @brief Dilates an image by using a specific structuring element.
The function dilates the source image using the specified structuring element that determines the
shape of a pixel neighborhood over which the maximum is taken:
\f[\texttt{dst} (x,y) = \max _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f]
The function supports the in-place mode. Dilation can be applied several ( iterations ) times. In
case of multi-channel images, each channel is processed independently.
@param src input image; the number of channels can be arbitrary, but the depth should be one of
CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.
@param dst output image of the same size and type as src\`.
@param kernel structuring element used for dilation; if elemenat=Mat(), a 3 x 3 rectangular
structuring element is used. Kernel can be created using getStructuringElement
@param anchor position of the anchor within the element; default value (-1, -1) means that the
anchor is at the element center.
@param iterations number of times dilation is applied.
@param borderType pixel extrapolation method, see cv::BorderTypes
@param borderValue border value in case of a constant border
@sa erode, morphologyEx, getStructuringElement
*/
CV_EXPORTS_W void dilate( InputArray src, OutputArray dst, InputArray kernel,
Point anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
在这里,我们只使用了3个参数,分别代表:输入图像、输出图像、内核尺寸,有兴趣的可以自行研究其他参数的作用!!
腐蚀:
erode(dilate_result, erode_result, erode_element);
函数的介绍:
/** @brief Erodes an image by using a specific structuring element.
The function erodes the source image using the specified structuring element that determines the
shape of a pixel neighborhood over which the minimum is taken:
\f[\texttt{dst} (x,y) = \min _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f]
The function supports the in-place mode. Erosion can be applied several ( iterations ) times. In
case of multi-channel images, each channel is processed independently.
@param src input image; the number of channels can be arbitrary, but the depth should be one of
CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.
@param dst output image of the same size and type as src.
@param kernel structuring element used for erosion; if `element=Mat()`, a `3 x 3` rectangular
structuring element is used. Kernel can be created using getStructuringElement.
@param anchor position of the anchor within the element; default value (-1, -1) means that the
anchor is at the element center.
@param iterations number of times erosion is applied.
@param borderType pixel extrapolation method, see cv::BorderTypes
@param borderValue border value in case of a constant border
@sa dilate, morphologyEx, getStructuringElement
*/
CV_EXPORTS_W void erode( InputArray src, OutputArray dst, InputArray kernel,
Point anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
这里的参数代表的含义与dilate(膨胀)一样,就不介绍了!!!
在这里可能有的朋友就会想了,经过膨胀后的图片能不能用腐蚀的方法进行还原呢!答案是不能完全的还原,当使用的内核很小时,进过膨胀的图片可以适当的使用腐蚀进行还原,还原的图片跟原图相比在细节上回丢失很多信息,看一下实际的操作效果吧!!
图片原图:
内核为3,先对图片进行膨胀,再对膨胀后的图片进行腐蚀,实际运行图如下:
内核为10,先对图片进行膨胀,再对膨胀后的图片进行腐蚀,实际运行图如下:
可以看出,这种针对像素点的操作是不可逆的,即使可以还原回来,也会在丢失大量细节信息的(也不知道自己理解的对不对,如有不正确的地方,恳请大神指正)!!
有兴趣的朋友可以以关注我,遇到问题大家一起讨论一下!!
- 点赞
- 收藏
- 关注作者
评论(0)