1. 程式人生 > >Opencv2.4學習::形態學濾波-角點檢測

Opencv2.4學習::形態學濾波-角點檢測

形態學濾波-角點檢測

就是利用形態學處理中的腐蝕和膨脹操作進行的角點檢測、邊緣檢測。

基本步驟

第一步:十字型核-------->【對原圖:膨脹操作】

效果:原圖在水平和垂直方向會擴充套件,而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);


}