1:圖像形態學用於邊緣的提取:
我們知道,圖像膨脹後邊緣會擴張,腐蝕後會緊縮,通過計算膨脹與緊縮的圖像之差,就可以粗略的檢測出圖像的邊緣;
int _tmain(int argc, _TCHAR* argv[])
{
Mat image = imread("007.jpg",1);
cvtColor(image,image,CV_RGB2GRAY);
namedWindow("原圖");
imshow("原圖",image);
Mat eroded;
erode(image,eroded,Mat());
Mat dilated;
dilate(image,dilated,Mat());
Mat Edge = dilated-eroded;
namedWindow("邊緣");
imshow("邊緣",Edge);
threshold(Edge,Edge,30,255,THRESH_BINARY);
namedWindow("閾值邊緣");
imshow("閾值邊緣",Edge);
waitKey(0);
return 0;
}
得到的結果:
除了做減法之外,morphologyEx() 函數直接提供了一個求邊緣的參數,只需要修改第三個參數即可,得到的結果和上述一致;
int _tmain(int argc, _TCHAR* argv[])
{
Mat image = imread("007.jpg",1);
cvtColor(image,image,CV_RGB2GRAY);
namedWindow("原圖");
imshow("原圖",image);
Mat Edge;
morphologyEx(image,Edge,MORPH_GRADIENT,Mat()); //修改第三個參數,直接求邊緣
threshold(Edge,Edge,30,255,THRESH_BINARY);
namedWindow("閾值邊緣");
imshow("閾值邊緣",Edge);
waitKey(0);
return 0;
}
2:圖像形態學檢測角點
角點最直觀的印象就是水平和豎直方向上變換都很大,即X,Y的梯度都很大;邊緣可以理解爲X,Y方向上只有一個梯度大;而平坦地區水平豎直兩個方向上的梯度都很小;角點不僅保留了圖像的重要的特徵,還有效地減少了信息的數據量,使其信息的含量很高,在三維場景重建、運動估計、目標跟蹤與識別、圖像的配準與匹配等計算機視覺領域有着非常重要的作用;
目前角點檢測的方法主要有基於圖像邊緣的和基於圖像灰度的,前者用的比較少,後者比較常見主要包括Harris算子,Moravec算子和Susan算子。
這裏我們自定義一個類,用來實現圖像角點的檢測;
class MorphologyFeature
{
private:
int Threshold; //用於生成二值圖像的閾值;
//角點檢測用到的結構元素;
Mat cross;
Mat diamond;
Mat square;
Mat x;
public:
MorphologyFeature();
Mat GetCorners(const Mat &image);
void DrawOnImage(Mat &image,const Mat &binary);
Mat getEdge(Mat &image)
{
Mat result;
morphologyEx(image,result,MORPH_GRADIENT,Mat());
applyThreshold(result);
return result;
}
void applyThreshold(Mat &result)
{
if(threshold>0)
{
threshold(result,result,Threshold,255,THRESH_BINARY);
}
}
void setThreshold(int a)
{
Threshold = a;
}
};
MorphologyFeature::MorphologyFeature():Threshold(-1),cross(5,5,CV_8U,Scalar(0)),diamond(5,5,CV_8U,Scalar(1)),
square(5,5,CV_8U,Scalar(1)),x(5,5,CV_8U,Scalar(0))
{
//創建十字形元素
for(int i=0;i<5;i++)
{
cross.at<uchar>(2,i) = 1;
cross.at<uchar>(i,2) = 1;
}
//創建菱形元素
diamond.at<uchar>(0,0)=0;
diamond.at<uchar>(0,1)=0;
diamond.at<uchar>(1,0)=0;
diamond.at<uchar>(0,4)=0;
diamond.at<uchar>(0,3)=0;
diamond.at<uchar>(1,4)=0;
diamond.at<uchar>(3,0)=0;
diamond.at<uchar>(4,0)=0;
diamond.at<uchar>(4,1)=0;
diamond.at<uchar>(4,4)=0;
diamond.at<uchar>(4,3)=0;
diamond.at<uchar>(3,4)=0;
//創建X型
for(int i=0;i<5;i++)
{
x.at<uchar>(i,i) = 1;
x.at<uchar>(i,4-i) = 1;
}
}
Mat MorphologyFeature::GetCorners(const Mat &image)
{
Mat result;
//十字形膨脹;
dilate(image,result,cross);
//菱形腐蝕
erode(result,result,diamond);
Mat result2;
//X型膨脹
dilate(image,result2,x);
//方形腐蝕
erode(result2,result2,square);
//通過兩幅圖像做差得到角點圖像;
absdiff(result2,result,result);
applyThreshold(result);
return result;
}
void MorphologyFeature::DrawOnImage(Mat &image,const Mat &binary)
{
/*Mat_<uchar>::const_iterator it = binary.begin<uchar>();
Mat_<uchar>::const_iterator itend = binary.end<uchar>();
//遍歷圖像像素
for(int i=0;it!=itend;it++,i++)
{
if(*it)
{
circle(image,Point(i*3%image.step,i*3/image.step),5,Scalar(0,255,0));
}
}*/
for(int i=0;i<binary.rows;i++)
{
//獲取行指針
const uchar* data = binary.ptr<uchar>(i);
for(int j=0;j<binary.cols;j++)
{
if(data[j])
{
circle(image,Point(j,i),5,Scalar(0,255,0));
}
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
Mat image = imread("007.jpg",1);
Mat image1 = image;
cvtColor(image,image,CV_RGB2GRAY);
namedWindow("原圖");
imshow("原圖",image);
MorphologyFeature morph;
morph.setThreshold(10);
Mat Edge = morph.GetCorners(image);
morph.DrawOnImage(image1,Edge);
namedWindow("角點");
imshow("角點",Edge);
namedWindow("結果");
imshow("結果",image1);
waitKey(0);
return 0;
}
得到的結果如下: