1. 膨胀与腐蚀的原理
膨胀与腐蚀是数学形态学在图像处理中最基础的操作。对于图像的每个像素,取其一定的邻域,计算最大值/最小值作为新图像对应像素位置的像素值。其中,取最大值就是膨胀,取最小值就是腐蚀。
2. 膨胀的实现
1) OpenCV实现
在OpenCV中实现了图像膨胀的函数dilate(),可以直接调用:
<code>Mat img = imread(imagename, IMREAD_GRAYSCALE);
if (img.empty())
{
fprintf(stderr, "Can not load image %s\\n", imagename);
return -1;
}
//OpenCV方法
Mat dilated_cv;
dilate(img, dilated_cv, Mat());/<code>
dilate()函数第一个参数表示输入影像,第二个参数表示输出影像,第三个表示一个默认的核,在3X3的范围内寻找最大值。
2) C++实现
在一般的图像处理时,图像读写是由专门的组件进行读取的。这这里仍然使用OpenCV进行读取,以免增加复杂性。而在CV::Mat类中,提供了at()函数访问某一行某一列的像素值,可以通过at()函数去访问每一个像素的领域。
与之前OpenCV实现的一样,对于每一个像素,遍历以其像素位置为中心的3X3邻域,取最大值作为新图像对应位置的像素值。其具体实现如下:
<code>//从文件中读取成灰度图像
const char* imagename = "lena.jpg";
Mat img = imread(imagename, IMREAD_GRAYSCALE);
if (img.empty())
{
fprintf(stderr, "Can not load image %s\\n", imagename);
return -1;
}
//自定义方法
Mat dilated_my;
dilated_my.create(img.rows, img.cols, CV_8UC1);
for (int i = 0; i < img.rows; ++i)
{
for (int j = 0; j < img.cols; ++j)
{
//uchar minV = 255;
uchar maxV = 0;
//遍历周围最大像素值
for (int yi = i-1; yi <= i+1; yi++)
{
for (int xi = j-1; xi <= j+1; xi++)
{
if (xi<0||xi>= img.cols|| yi<0 || yi >= img.rows)
{
continue;
}
//minV = (std::min<uchar>)(minV, img.at<uchar>(yi, xi));
maxV = (std::max<uchar>)(maxV, img.at<uchar>(yi, xi));
}
}
dilated_my.at<uchar>(i, j) = maxV;
}
} /<uchar>/<uchar>/<uchar>/<uchar>/<uchar>/<code>
3) 验证
为了验证自己的算法是否正确,可以通过把两者膨胀的结果通过compare()函数进行比较。compare()函数会逐个比较两者的像素值,如果相同就会返回255(白色),如果不相同就会返回0(黑色)。整个过程的具体实现如下:
<code>#include <iostream>
#include <algorithm>
#include <opencv2>
using namespace cv;
using namespace std;
int main()
{
//从文件中读取成灰度图像
const char* imagename = "lena.jpg";
Mat img = imread(imagename, IMREAD_GRAYSCALE);
if (img.empty())
{
fprintf(stderr, "Can not load image %s\\n", imagename);
return -1;
}
//OpenCV方法
Mat dilated_cv;
dilate(img, dilated_cv, Mat());
//自定义方法
Mat dilated_my;
dilated_my.create(img.rows, img.cols, CV_8UC1);
for (int i = 0; i < img.rows; ++i)
{
for (int j = 0; j < img.cols; ++j)
{
//uchar minV = 255;
uchar maxV = 0;
//遍历周围最大像素值
for (int yi = i-1; yi <= i+1; yi++)
{
for (int xi = j-1; xi <= j+1; xi++)
{
if (xi<0||xi>= img.cols|| yi<0 || yi >= img.rows)
{
continue;
}
//minV = (std::min<uchar>)(minV, img.at<uchar>(yi, xi));
maxV = (std::max<uchar>)(maxV, img.at<uchar>(yi, xi));
}
}
dilated_my.at<uchar>(i, j) = maxV;
}
}
//比较两者的结果
Mat c;
compare(dilated_cv, dilated_my, c, CMP_EQ);
//显示
imshow("原始", img);
imshow("膨胀_cv", dilated_cv);
imshow("膨胀_my", dilated_my);
imshow("比较结果", c);
waitKey();
return 0;
}/<uchar>/<uchar>/<uchar>/<uchar>/<uchar>/<opencv2>/<algorithm>/<iostream>/<code>
其运行结果如下所示。可以发现最后的比较结果是一张白色的图像,说明自己实现的算法是正确的。
閱讀更多 DL小寶 的文章