Opencv2.4學習::形態學濾波-角點檢測
阿新 • • 發佈:2018-12-20
形態學濾波-角點檢測
就是利用形態學處理中的腐蝕和膨脹操作進行的角點檢測、邊緣檢測。
基本步驟
第一步:十字型核-------->【對原圖:膨脹操作】
效果:原圖在水平和垂直方向會擴充套件,而45度.135度方向沒有得到擴充套件
目的:目的是使得在下一步的腐蝕操作中,保證腐蝕後的邊緣與原圖一致,而只有角點被腐蝕掉
第二步:菱形核-------->【對第一步的結果:腐蝕操作】
效果:使得第一步的結果在水平和垂直方向被腐蝕,而在45度.135度等方向也有一定腐蝕效果,使用菱形而不用十字進行腐蝕是為了斜方向得到腐蝕
第一步+第二部的最終結果:原圖的邊緣不發生變化,僅有角點被腐蝕
個人認為,角點檢測到這裡就應該結束了,最後一步直接用原圖與第二步的結果相減,就可以得出角點了
這裡給出測試程式碼:
#include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc.hpp> #include<iostream> using namespace std; using namespace cv; void main() { Mat srcImg = imread("F:\\opencv_re_learn\\contour1.jpg"); if (!srcImg.data){ cout << "failed to read" << endl; system("pause"); return; } Mat srcGray; cvtColor(srcImg, srcGray, CV_RGB2GRAY); Mat thresh; thresh = srcGray.clone(); threshold(srcGray, thresh, 176, 255, CV_THRESH_BINARY_INV); imshow("thresh", thresh); //定義核 Mat CrossMat(5, 5, CV_8U, Scalar(0)); Mat diamondMat(5, 5, CV_8U, Scalar(1)); Mat squareMat(5, 5, CV_8U, Scalar(1)); Mat X(5, 5, CV_8U, Scalar(0)); //十字形核 for (int i = 0; i < 5; i++){ CrossMat.at<uchar>(2, i) = 1; CrossMat.at<uchar>(i, 2) = 1; } //菱形形狀核 diamondMat.at<uchar>(0, 0) = 0; diamondMat.at<uchar>(0, 1) = 0; diamondMat.at<uchar>(1, 0) = 0; diamondMat.at<uchar>(4, 4) = 0; diamondMat.at<uchar>(3, 4) = 0; diamondMat.at<uchar>(4, 3) = 0; diamondMat.at<uchar>(4, 0) = 0; diamondMat.at<uchar>(4, 1) = 0; diamondMat.at<uchar>(3, 0) = 0; diamondMat.at<uchar>(0, 4) = 0; diamondMat.at<uchar>(0, 3) = 0; diamondMat.at<uchar>(1, 4) = 0; //X形狀核 for (int i = 0; i < 5; i++){ X.at<uchar>(i, i) = 1; X.at<uchar>(4 - i, i) = 1; } //第一步:十字型核,【膨脹操作】 //原圖在水平和垂直方向會擴充套件,而45度.135度方向沒有得到擴充套件 //目的是使得在下一步的腐蝕操作中,保證腐蝕後的邊緣與原圖一致, //而只有角點被腐蝕掉 Mat result; dilate(thresh, result, CrossMat); imshow("1:Cross", result); //第二步:菱形核,【腐蝕操作】 //效果:使得第一步的結果在水平和垂直方向被腐蝕,而在45度.135度等方向也, //有一定腐蝕效果,使用菱形而不用十字進行腐蝕是為了斜方向得到腐蝕 //第一第二步操作後的結果是:原圖的邊緣不發生變化,僅有角點被腐蝕 erode(result, result, diamondMat); imshow("2:diamond", result); //計算差值 absdiff(thresh, result, result); threshold(result, result, 30, 255, THRESH_BINARY); //繪製 for (int i = 0; i < result.rows; i++){ //獲取行指標 const uchar* data = result.ptr<uchar>(i); for (int j = 0; j < result.cols; j++){ //如果是角點,則繪製圓圈 if (data[j]){ circle(srcImg, Point(j, i), 8, Scalar(0, 0, 255)); } } } imshow("src", srcImg); imshow("result", result); waitKey(0); }
測試結果:
實際上,演算法給出還有第三第四步
第三步: X型核-------->【對原圖:膨脹操作】
效果:使得原圖在水平和垂直,45度,135度等傾斜方向都有擴充套件
第四步:正方形核---------->【對第三步結果:腐蝕操作】
效果:又腐蝕掉一次
第三第四部操作後的結果是:原圖角點不發生變化,而水平和垂直方向的邊緣似乎被腐蝕掉
最後一步:將第二步與第四步的結果相減,獲得角點
以上四步的全部程式碼如下:
#include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc.hpp> #include<iostream> using namespace std; using namespace cv; void main() { Mat srcImg = imread("F:\\opencv_re_learn\\contour1.jpg"); if (!srcImg.data){ cout << "failed to read" << endl; system("pause"); return; } Mat srcGray; cvtColor(srcImg, srcGray, CV_RGB2GRAY); Mat thresh; thresh = srcGray.clone(); threshold(srcGray, thresh, 176, 255, CV_THRESH_BINARY_INV); imshow("thresh", thresh); //定義核 Mat CrossMat(5, 5, CV_8U, Scalar(0)); Mat diamondMat(5, 5, CV_8U, Scalar(1)); Mat squareMat(5, 5, CV_8U, Scalar(1)); Mat X(5, 5, CV_8U, Scalar(0)); //十字形核 for (int i = 0; i < 5; i++){ CrossMat.at<uchar>(2, i) = 1; CrossMat.at<uchar>(i, 2) = 1; } //菱形形狀核 diamondMat.at<uchar>(0, 0) = 0; diamondMat.at<uchar>(0, 1) = 0; diamondMat.at<uchar>(1, 0) = 0; diamondMat.at<uchar>(4, 4) = 0; diamondMat.at<uchar>(3, 4) = 0; diamondMat.at<uchar>(4, 3) = 0; diamondMat.at<uchar>(4, 0) = 0; diamondMat.at<uchar>(4, 1) = 0; diamondMat.at<uchar>(3, 0) = 0; diamondMat.at<uchar>(0, 4) = 0; diamondMat.at<uchar>(0, 3) = 0; diamondMat.at<uchar>(1, 4) = 0; //X形狀核 for (int i = 0; i < 5; i++){ X.at<uchar>(i, i) = 1; X.at<uchar>(4 - i, i) = 1; } //第一步:十字型核,【膨脹操作】 //原圖在水平和垂直方向會擴充套件,而45度.135度方向沒有得到擴充套件 //目的是使得在下一步的腐蝕操作中,保證腐蝕後的邊緣與原圖一致, //而只有角點被腐蝕掉 Mat result; dilate(thresh, result, CrossMat); imshow("1:Cross", result); //第二步:菱形核,【腐蝕操作】 //效果:使得第一步的結果在水平和垂直方向被腐蝕,而在45度.135度等方向也, //有一定腐蝕效果,使用菱形而不用十字進行腐蝕是為了斜方向得到腐蝕 //第一第二步操作後的結果是:原圖的邊緣不發生變化,僅有角點被腐蝕 erode(result, result, diamondMat); imshow("2:diamond", result); //第三步:X型核對原圖膨脹 //效果:使得原圖在水平和垂直,45度,135度等傾斜方向都有擴充套件 Mat result2; dilate(thresh, result2, X); imshow("X", result2); //第四步:正方形核,【腐蝕操作】 //效果:又腐蝕掉一次,第三第四部操作後的結果是,原圖角點不發生變化, //而水平和垂直方向的邊緣似乎被腐蝕掉 erode(result2, result2, squareMat); imshow("squ", result2); //計算差值 absdiff(result2, result, result); threshold(result, result, 30, 255, THRESH_BINARY); //繪製 for (int i = 0; i < result.rows; i++){ //獲取行指標 const uchar* data = result.ptr<uchar>(i); for (int j = 0; j < result.cols; j++){ //如果是角點,則繪製圓圈 if (data[j]){ circle(srcImg, Point(j, i), 8, Scalar(0, 0, 255)); } } } imshow("src", srcImg); imshow("result", result); waitKey(0); }