说明
1、EmguCV中Harris角点检测函数:CvInvoke.CornerHarris()
;
参数harrisResponse为CV_32FC1的图像,计算后需要进行归一化或者阈值化,转换为CV8U再显示;
参数blockSize : 领域大小,和协方差矩阵M的计算有关(影响M的值)
2、Harris检测的结果衡量(角点响应度量):M为协方差矩阵,度量R判断是否为角点,需要自己选择判断合适的阈值;
3、Shi-Tomasi角点检测:EmguCV没有封装goodFeatureToTrack()方法,只能使用GFTTDetector类的Detect()方法来检测特征点;可以自己控制想要的角点数,使用更方便;
参数minDistance控制角点之间的距离;
4、亚像素级角点检测:cornerSubPix()
;
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV;
using Emgu.Util;
using Emgu.CV.Structure;
using Emgu.CV.CvEnum;
using Emgu.CV.Util;
using System.Drawing;
using Emgu.CV.Features2D;
namespace lesson31
{
class Program
{
static void Main(string[] args)
{
///Harris角点检测
//Mat src = CvInvoke.Imread("3.jpg");
//CvInvoke.Imshow("input", src);
//Mat gray = new Mat();
//CvInvoke.CvtColor(src, gray, ColorConversion.Bgr2Gray);
//Mat dst = new Mat();
//CvInvoke.CornerHarris(gray, dst, 2, 3, 0.04);//角点检测
//CvInvoke.Threshold(dst, dst, 0.005, 255, ThresholdType.Binary);
//Console.WriteLine("Depth: {0}\nChannels: {1}", dst.Depth, dst.NumberOfChannels);
//dst.ConvertTo(dst, DepthType.Cv8U);
//CvInvoke.Imshow("CornerHarris", dst);
//Image<Gray, Byte> img = dst.ToImage<Gray, Byte>();
//for (int i = 0; i < img.Rows; i++)
//{
// for (int j = 0; j < img.Cols; j++)
// {
// if (img.Data[i, j, 0] == 255)
// {
// CvInvoke.Circle(src, new Point(j, i), 2, new MCvScalar(0, 255, 0), -1);
// }
// }
//}
//CvInvoke.Imshow("result", src);
//CvInvoke.WaitKey(0);
///另一种方法
//Mat src = CvInvoke.Imread("3.jpg");
//Mat grayImg = new Mat();
//CvInvoke.CvtColor(src, grayImg, ColorConversion.Bgr2Gray);
//Mat dst = new Mat();
//CvInvoke.CornerHarris(grayImg, dst, 2, 3, 0.04, BorderType.Default);
//Mat scaleImg = new Mat();
//CvInvoke.Normalize(dst, dst, 0, 255, NormType.MinMax, DepthType.Cv32F);
//CvInvoke.ConvertScaleAbs(dst, scaleImg, 1, 0);
//Image<Gray, Byte> img = scaleImg.ToImage<Gray, Byte>();
//for(int i = 0; i < img.Rows;i++)
//{
// for(int j =0; j < img.Cols; j++)
// {
// if(img.Data[i,j,0] > 100) //阈值选取很重要,控制角点个数
// {
// CvInvoke.Circle(src, new Point(j, i), 3, new MCvScalar(0, 255, 0), -1);
// }
// }
//}
//CvInvoke.Imshow("result", src);
//CvInvoke.WaitKey(0);
///Shi-Tomasi角点检测
//Mat src = CvInvoke.Imread("mask2.jpg");
//Mat grayImg = new Mat();
//CvInvoke.CvtColor(src, grayImg, ColorConversion.Bgr2Gray);
//GFTTDetector gFTT = new GFTTDetector(12, 0.01, 1, 3, false, 0.04);
//MKeyPoint[] points = gFTT.Detect(grayImg); //使用Shi-Tomasi检测算法检测特征点
//for(int i = 0; i < points.Length; i++)
//{
// Point pt = new Point();
// pt.X = (int)points[i].Point.X;
// pt.Y = (int)points[i].Point.Y;
// CvInvoke.Circle(src, pt, 3, new MCvScalar(0, 0, 255), -1);
//}
//CvInvoke.Imshow("result", src);
//CvInvoke.WaitKey(0);
///亚像素角点检测
Mat src = CvInvoke.Imread("3.jpg");
CvInvoke.Imshow("input", src);
Mat grayImg = new Mat();
CvInvoke.CvtColor(src, grayImg, ColorConversion.Bgr2Gray);
Mat harrisImg = new Mat();
CvInvoke.CornerHarris(grayImg, harrisImg, 2, 3, 0.04);
CvInvoke.Threshold(harrisImg, harrisImg, 0.01, 255, ThresholdType.Binary);
Mat dst = new Mat();
harrisImg.ConvertTo(dst, DepthType.Cv8U);
CvInvoke.Imshow("mask", dst);
VectorOfPointF corners = new VectorOfPointF();
Image<Gray, Byte> img = dst.ToImage<Gray, Byte>();
for(int i = 0; i < img.Rows; i++)
{
for(int j = 0; j < img.Cols; j++)
{
if(img.Data[i,j,0] == 255)
{
CvInvoke.Circle(src, new Point(j, i), 3, new MCvScalar(0, 0, 255), -1);
PointF[] pt = new PointF[1];
pt[0].X = j;
pt[0].Y = i;
corners.Push(pt);
}
}
}
CvInvoke.Imshow("result", src);
MCvTermCriteria termCriteria = new MCvTermCriteria(40, 0.001);
CvInvoke.CornerSubPix(grayImg, corners, new Size(5, 5), new Size(-1, -1), termCriteria); //亚像素级角点精确化
for(int i = 0; i < corners.Size; i++)
{
Console.WriteLine("corner {0} : ({1:F2},{1:F2})", i, corners[i].X, corners[i].Y);
}
CvInvoke.WaitKey(0);
}
}
}
效果
1、Harris角点检测:
使用不同阈值,检测到的角点数也不同:
2、Shi-Tomasi检测:(GFTTDetector)
3、亚像素级角点精确化: