一、膨脹腐蝕學習筆記
二、代碼及結果分享
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
//定義腐蝕函數
void myErode(Mat Src, Mat Tem, Mat Dst)
{
int m = (Tem.rows - 1) / 2;
int n = (Tem.cols - 1) / 2;
for (int i = m; i < Src.rows - m; i++)//i、j的范圍保證結構元始終在擴展后的圖像內部
{
for (int j = n; j < Src.cols - n; j++)
{
Mat SrcROI = Src(Rect(j - m, i - n, Tem.cols, Tem.rows));
double sum = 0;
sum = SrcROI.dot(Tem);//矩陣對應位置相乘后求和
if (sum == 9)//結構元的9個元素均為1,和為9才能保證結構元完全包含於相應集合
Dst.at<uchar>(i, j) = 255;
else
Dst.at<uchar>(i, j) = 0;
}
}
}
//定義膨脹函數
void myDilate(Mat Src, Mat Tem, Mat Dst)
{
int m = (Tem.rows - 1) / 2;
int n = (Tem.cols - 1) / 2;
for (int i = m; i < Src.rows - m; i++)//i、j的范圍保證結構元始終在擴展后的圖像內部
{
for (int j = n; j < Src.cols - n; j++)
{
Mat SrcROI = Src(Rect(j - m, i - n, Tem.cols, Tem.rows));
double sum = 0;
sum = SrcROI.dot(Tem);//矩陣對應位置相乘后求和
if (sum != 0)//結構元的9個元素均為1,只要和不為0,就能說明結構元與相應集合有交集
Dst.at<uchar>(i, j) = 255;
else
Dst.at<uchar>(i, j) = 0;
}
}
}
int main()
{
Mat mImage = imread("dada.jpg", 0);
if (mImage.data == 0)
{
cerr << "Image reading error !" << endl;
system("pause");
return -1;
}
namedWindow("The original image", WINDOW_NORMAL);
imshow("The original image", mImage);
//設置閾值將圖像二值化
const int binThreshold = 80;
for (int i = 0; i < mImage.rows; i++)
{
uchar* pImage = mImage.ptr<uchar>(i);
for (int j = 0; j < mImage.cols; j++)
{
if (pImage[j] > binThreshold)//事實上應將灰度值大於閾值的賦值為255,但為了方便后續膨脹腐蝕的計算,在這里將其賦值為1
pImage[j]= 1;
else
pImage[j] = 0;
}
}
//定義並初始化結構元
Mat mTemplate(3, 3, CV_8UC1, Scalar(1));
if (mTemplate.rows * mTemplate.cols % 2 == 0)
{
cerr << "The size doesn't meet the requirement !" << endl;
system("pause");
return -1;
}
//擴展圖像邊界
copyMakeBorder(mImage, mImage, mTemplate.rows, mTemplate.rows, mTemplate.cols, mTemplate.cols, BORDER_CONSTANT, Scalar(0));
//進行圖像腐蝕
Mat mEResult = mImage.clone();
myErode(mImage, mTemplate, mEResult);
//進行圖像膨脹
Mat mDResult = mImage.clone();
myDilate(mImage, mTemplate, mDResult);
//進行顯示
namedWindow("The eroding image", WINDOW_NORMAL);
imshow("The eroding image", mEResult);
namedWindow("The dilating image", WINDOW_NORMAL);
imshow("The dilating image", mDResult);
waitKey();
destroyAllWindows();
return 0;
}
膨脹(dilate)和腐蝕(erode)均是對白色區域而言。由結果可明顯看出,膨脹后的白色面積要比腐蝕后的大。由圖像左下角的水印變化也可直觀看出兩種操作對圖像的不同影響。
三、注意事項
在本次編程實現過程中,為了確定結構元是否包含於集合(或與集合是否有交集),需要讓結構元中各元素與圖像中對應位置像素值相乘后求和。Mat類型中有幾種不同類型的乘法,在這里加以總結。
Mat A, B ;
3.1A.dot(B)
A、B對應位置元素相乘,之后將所有乘積相加求和,返回值是double型數字。要求A、B size必須相同。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
uchar A[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
uchar B[3][3] = { { 1,1,1 },{ 1,1,1 },{ 1,1,1 } };
Mat Src(3, 3, CV_8UC1, A);
Mat Dst(3, 3, CV_8UC1, B);
double Result = Src.dot(Dst);
cout << "Src:" << Src << endl;
cout << "Dst:" << Dst << endl;
cout << "Result:" << Result << endl;
system("pause");
return 0;
}
3.2A.mul(B)
A、B對應位置元素相乘,返回值是和A、B等大小,同類型的Mat型矩陣。要求A、B size必須相同。若計算結果溢出,則溢出值自動變為當前數據類型下允許的的最大值。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
uchar A[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
uchar B[3][3] = { { 1,1,1 },{ 1,1,1 },{ 1,1,1 } };
Mat Src(3, 3, CV_8UC1, A);
Mat Dst(3, 3, CV_8UC1, B);
Mat Result = Src.mul(Dst);
cout << "Src:" << Src << endl;
cout << "Dst:" << Dst << endl;
cout << "Result:" << Result << endl;
system("pause");
return 0;
}
注:錯誤之處,敬請雅正!