膨脹與腐蝕是數學形態學在圖像處理中最基礎的操做。在筆者以前的文章《圖像的卷積(濾波)運算(一)——圖像梯度》、《圖像的卷積(濾波)運算(二)——高斯濾波》具體介紹了圖像卷積\濾波的具體的概念與操做,圖像的膨脹與腐蝕其實也是一種相似的卷積操做。其卷積操做很是簡單,對於圖像的每一個像素,取其必定的鄰域,計算最大值/最小值做爲新圖像對應像素位置的像素值。其中,取最大值就是膨脹,取最小值就是腐蝕。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; }
其運行結果以下:
數學