膨胀与腐蚀是数学形态学在图像处理中最基础的操做。在笔者以前的文章《图像的卷积(滤波)运算(一)——图像梯度》、《图像的卷积(滤波)运算(二)——高斯滤波》具体介绍了图像卷积\滤波的具体的概念与操做,图像的膨胀与腐蚀其实也是一种相似的卷积操做。其卷积操做很是简单,对于图像的每一个像素,取其必定的邻域,计算最大值/最小值做为新图像对应像素位置的像素值。其中,取最大值就是膨胀,取最小值就是腐蚀。ios
在OpenCV中实现了图像膨胀的函数dilate(),能够直接调用:算法
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());
dilate()函数第一个参数表示输入影像,第二个参数表示输出影像,第三个表示一个默认的核,在3X3的范围内寻找最大值。函数
在通常的图像处理时,图像读写是由专门的组件进行读取的。这这里仍然使用OpenCV进行读取,觉得增长复杂性。而在CV::Mat类中,提供了at()函数访问某一行某一列的像素值,能够经过at()函数去访问每个像素的领域。spa
与以前OpenCV实现的同样,对于每个像素,遍历以其像素位置为中心的3X3邻域,取最大值做为新图像对应位置的像素值。
其具体实现以下:code
//从文件中读取成灰度图像 const char* imagename = "D:\\Data\\imgDemo\\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.cols, img.rows, 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; } }
为了验证本身的算法是否正确,能够经过把二者膨胀的结果经过compare()函数进行比较。compare()函数会逐个比较二者的像素值,若是相同就会返回255(白色),若是不相同就会返回0(黑色)。整个过程的具体实现以下:htm
#include <iostream> #include <algorithm> #include <opencv2\opencv.hpp> using namespace cv; using namespace std; int main() { //从文件中读取成灰度图像 const char* imagename = "D:\\Data\\imgDemo\\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.cols, img.rows, 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; }
其运行结果以下所示。能够发现最后的比较结果是一张白色的图像,说明本身实现的算法是正确的。
blog
一样的办法能够实现图像腐蚀的过程,只要将求局部最大值改为局部最小值就能够了。具体实现过程以下:get
#include <iostream> #include <algorithm> #include <opencv2\opencv.hpp> using namespace cv; using namespace std; int main() { //从文件中读取成灰度图像 const char* imagename = "D:\\Data\\imgDemo\\lena.jpg"; Mat img = imread(imagename, IMREAD_GRAYSCALE); if (img.empty()) { fprintf(stderr, "Can not load image %s\n", imagename); return -1; } //OpenCV方法 Mat eroded_cv; erode(img, eroded_cv, Mat()); //自定义方法 Mat eroded_my; eroded_my.create(img.cols, img.rows, 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)); } } eroded_my.at<uchar>(i, j) = minV; } } //比较二者的结果 Mat c; compare(eroded_cv, eroded_my, c, CMP_EQ); //显示 imshow("原始", img); imshow("膨胀_cv", eroded_cv); imshow("膨胀_my", eroded_my); imshow("比较结果", c); waitKey(); return 0; }
其运行结果以下:
数学