Opencv2.3 图像特征检测总结
来源:互联网 发布:数据挖掘前景 知乎 编辑:程序博客网 时间:2024/05/16 12:46
图像特征检测总结
Sobel算子
//Sobel算子
private string SobelFeatureDetect()
拉普拉斯算子
private string LaplaceFeatureDetect()
{
//获取参数
int apertureSize = int.Parse((string)cmbLaplaceApertureSize.SelectedItem);
//计算
Stopwatch sw = newStopwatch();
sw.Start();
Image<Gray, Single> imageDest = imageSourceGrayscale.Laplace(apertureSize);
sw.Stop();
//显示
pbResult.Image = imageDest.Bitmap;
//释放资源
imageDest.Dispose();
//返回
return string.Format("·拉普拉斯变换,用时{0:F05}毫秒,参数(方形滤波器宽度:{1})rn",sw.Elapsed.TotalMilliseconds, apertureSize);
}
而cvCanny只能处理灰度图像,不过可以自定义apertureSize。cvCanny和Canny的方法参数名有点点不同,下面是参数对照表。
Image<TColor,TDepth>.Canny
thresh
threshLinking
3
值得注意的是,apertureSize只能取3,5或者7,这可以在cvcanny.cpp第87行看到:
if((aperture_size & 1)== 0 ||aperture_size < 3 ||aperture_size > 7 )
CV_ERROR( CV_StsBadFlag, "" );
private string CannyFeatureDetect()
{
//获取参数
double lowThresh = double.Parse(txtCannyLowThresh.Text);
double highThresh = double.Parse(txtCannyHighThresh.Text);
int apertureSize = int.Parse((string)cmbCannyApertureSize.SelectedItem);
//计算
Stopwatch sw = newStopwatch();
sw.Start();
Image<Gray, Byte> imageDest = null;
Image<Bgr, Byte> imageDest2 = null;
if (rbCannyUseCvCanny.Checked)
{
imageDest = new Image<Gray, byte>(imageSourceGrayscale.Size);
CvInvoke.cvCanny(imageSourceGrayscale.Ptr, imageDest.Ptr,lowThresh, highThresh, apertureSize);
}
else
imageDest2 =imageSource.Canny(new Bgr(lowThresh, lowThresh, lowThresh),new Bgr(highThresh, highThresh, highThresh));
sw.Stop();
//显示
pbResult.Image = rbCannyUseCvCanny.Checked ? imageDest.Bitmap : imageDest2.Bitmap;
//释放资源
if (imageDest != null)
imageDest.Dispose();
if (imageDest2 != null)
imageDest2.Dispose();
//返回
return string.Format("·Canny算子,用时{0:F05}毫秒,参数(方式:{1},阀值下限:{2},阀值上限:{3},方形滤波器宽度:{4})rn",sw.Elapsed.TotalMilliseconds, rbCannyUseCvCanny.Checked? "cvCanny" :"Image<TColor,TDepth>.Canny", lowThresh,highThresh, apertureSize);
}
private string HoughLinesFeatureDetect()
{
//获取参数
HOUGH_TYPE method = rbHoughLinesSHT.Checked ? HOUGH_TYPE.CV_HOUGH_STANDARD :(rbHoughLinesPPHT.Checked ? HOUGH_TYPE.CV_HOUGH_PROBABILISTIC :HOUGH_TYPE.CV_HOUGH_MULTI_SCALE);
double rho =double.Parse(txtHoughLinesRho.Text);
double theta =double.Parse(txtHoughLinesTheta.Text);
int threshold = int.Parse(txtHoughLinesThreshold.Text);
double param1 = double.Parse(txtHoughLinesParam1.Text);
double param2 = double.Parse(txtHoughLinesParam2.Text);
MemStorage storage =new MemStorage();
int linesCount = 0;
StringBuilder sbResult =new StringBuilder();
//计算,先运行Canny边缘检测(参数来自Canny算子属性页),然后再用计算霍夫线变换
double lowThresh = double.Parse(txtCannyLowThresh.Text);
double highThresh = double.Parse(txtCannyHighThresh.Text);
int apertureSize = int.Parse((string)cmbCannyApertureSize.SelectedItem);
Image<Gray, Byte> imageCanny = newImage<Gray, byte>(imageSourceGrayscale.Size);
CvInvoke.cvCanny(imageSourceGrayscale.Ptr, imageCanny.Ptr,lowThresh, highThresh, apertureSize);
Stopwatch sw =new Stopwatch();
sw.Start();
IntPtr ptrLines =CvInvoke.cvHoughLines2(imageCanny.Ptr,storage.Ptr, method, rho, theta, threshold, param1, param2);
Seq<LineSegment2D> linesSeq = null;
Seq<PointF> linesSeq2 = null;
if (method == HOUGH_TYPE.CV_HOUGH_PROBABILISTIC)
linesSeq = new Seq<LineSegment2D>(ptrLines, storage);
else
linesSeq2 = new Seq<PointF>(ptrLines, storage);
sw.Stop();
//显示
Image<Bgr, Byte> imageResult = imageSourceGrayscale.Convert<Bgr, Byte>();
if (linesSeq != null)
{
linesCount =linesSeq.Total;
foreach (LineSegment2D line in linesSeq)
{
imageResult.Draw(line, new Bgr(255d,0d, 0d), 4);
sbResult.AppendFormat("{0}-{1},", line.P1,line.P2);
}
}
else
{
linesCount =linesSeq2.Total;
foreach (PointF line in linesSeq2)
{
floatr = line.X;
float t= line.Y;
double a =Math.Cos(t), b = Math.Sin(t);
double x0 =a * r, y0= b *r;
int x1= (int)(x0+ 1000 *(-b));
int y1= (int)(y0+ 1000 *(a));
int x2= (int)(x0- 1000 *(-b));
int y2= (int)(y0- 1000 *(a));
Point pt1 = new Point(x1,y1);
Point pt2 = new Point(x2,y2);
imageResult.Draw(newLineSegment2D(pt1, pt2),new Bgr(255d, 0d, 0d), 4);
sbResult.AppendFormat("{0}-{1},", pt1,pt2);
}
}
pbResult.Image =imageResult.Bitmap;
//释放资源
imageCanny.Dispose();
imageResult.Dispose();
storage.Dispose();
//返回
return string.Format("·霍夫线变换,用时{0:F05}毫秒,参数(变换方式:{1},距离精度:{2},弧度精度:{3},阀值:{4},参数1:{5},参数2:{6}),找到{7}条直线rn{8}",
sw.Elapsed.TotalMilliseconds, method.ToString("G"), rho,theta, threshold, param1, param2, linesCount, linesCount!= 0 ?(sbResult.ToString()+ "rn") :"");
}
//霍夫圆变换
private string HoughCirclesFeatureDetec
{
double dp =double.Parse(txtHoughCirclesDp.Text);
double minDist = double.Parse(txtHoughCirclesMinDist.Text);
double param1 = double.Parse(txtHoughCirclesParam1.Text);
double param2 = double.Parse(txtHoughCirclesParam2.Text);
int minRadius = int.Parse(txtHoughCirclesMinRadius
StringBuilder sbResult
//计算
Stopwatch sw = newStopwatch();
sw.Start();
CircleF[][] circles =imageSourceGrayscale.HoughCircles(newGray(param1), new Gray(param2), dp, minDist, minRadius,maxRadius);
sw.Stop();
//显示
Image<Bgr, Byte> imageResult = imageSourceGrayscale.Convert<Bgr, Byte>();
int circlesCount = 0;
foreach (CircleF[] cs in circles)
{
foreach(CircleF circle in cs)
{
imageResult.Draw(circle, new Bgr(255d,0d, 0d), 4);
sbResult.AppendFormat("圆心{0}半径{1},",circle.Center, circle.Radius);
circlesCount++;
}
}
pbResult.Image =imageResult.Bitmap;
//释放资源
imageResult.Dispose();
//返回
return string.Format("·霍夫圆变换,用时{0:F05}毫秒,参数(累加器图像的最小分辨率:{1},不同圆之间的最小距离:{2},边缘阀值:{3},累加器阀值:{4},最小圆半径:{5},最大圆半径:{6}),找到{7}个圆rn{8}",
sw.Elapsed.TotalMilliseconds, dp, minDist, param1, param2,minRadius, maxRadius, circlesCount, sbResult.Length> 0 ?(sbResult.ToString()+ "rn") :"");
}
Harris角点
//Harris角点
private string CornerHarrisFeatureDetec
{
int blockSize = int.Parse(txtCornerHarrisBlockSize
//计算
Image<Gray, Single> imageDest = newImage<Gray, float>(imageSourceGrayscale.Size);
Stopwatch sw =new Stopwatch();
sw.Start();
CvInvoke.cvCornerHarris(imageSourceGrayscale.Ptr, imageDest.Ptr,blockSize, apertureSize, k);
sw.Stop();
//显示
pbResult.Image = imageDest.Bitmap;
//释放资源
imageDest.Dispose();
//返回
return string.Format("·Harris角点,用时{0:F05}毫秒,参数(邻域大小:{1},方形滤波器宽度:{2},权重系数:{3})rn",sw.Elapsed.TotalMilliseconds, blockSize, apertureSize, k);
}
如果要计算Harris角点列表,需要使用cvGoodFeatureToTrack函数,并传递适当的参数。
ShiTomasi角点
使用cvGoodFeatureToTrack函数的示例代码如下:
//ShiTomasi角点
private string CornerShiTomasiFeatureDe
{
int cornerCount = int.Parse(txtGoodFeaturesCornerCou
double k =double.Parse(txtGoodFeaturesK.Text);
//计算
Stopwatch sw = newStopwatch();
sw.Start();
PointF[][] corners =imageSourceGrayscale.GoodFeaturesToTrack(cornerCount,qualityLevel, minDistance, blockSize, useHarris, k);
sw.Stop();
//显示
Image<Bgr, Byte> imageResult = imageSourceGrayscale.Convert<Bgr, Byte>();
int cornerCount2 = 0;
StringBuilder sbResult =new StringBuilder();
int radius = (int)(minDistance / 2)+ 1;
int thickness = (int)(minDistance / 4)+ 1;
foreach (PointF[] cs in corners)
{
foreach(PointF p in cs)
{
imageResult.Draw(newCircleF(p, radius),new Bgr(255d, 0d, 0d), thickness);
cornerCount2++;
sbResult.AppendFormat("{0},", p);
}
}
pbResult.Image =imageResult.Bitmap;
//释放资源
imageResult.Dispose();
//返回
return string.Format("·ShiTomasi角点,用时{0:F05}毫秒,参数(最大角点数目:{1},最小特征值:{2},角点间的最小距离:{3},邻域大小:{4},角点类型:{5},权重系数:{6}),检测到{7}个角点rn{8}",
sw.Elapsed.TotalMilliseconds, cornerCount, qualityLevel,minDistance, blockSize, useHarris ? "Harris": "ShiTomasi", k,cornerCount2, cornerCount2 > 0 ?(sbResult.ToString()+ "rn") :"");
}
亚像素级角点
//亚像素级角点
private string CornerSubPixFeatureDetec
{
int winWidth = int.Parse(txtCornerSubPixWinWidth.Text);
int winHeight = int.Parse(txtCornerSubPixWinHeight
Size win
int zeroZoneWidth = int.Parse(txtCornerSubPixZeroZoneW
Size zeroZone
int maxIter=int.Parse(txtCornerSubPixMaxIter.Text);
double epsilon=double.Parse(txtCornerSubPixEpsilon.Text);
MCvTermCriteria criteria = newMCvTermCriteria(maxIter,epsilon);
//先计算得到易于跟踪的点(ShiTomasi角点)
int cornerCount = int.Parse(txtGoodFeaturesCornerCou
double k =double.Parse(txtGoodFeaturesK.Text);
PointF[][] corners =imageSourceGrayscale.GoodFeaturesToTrack(cornerCount,qualityLevel, minDistance, blockSize, useHarris, k);
//计算
Stopwatch sw = newStopwatch();
sw.Start();
imageSourceGrayscale.FindCornerSubPix(corners, win, zeroZone,criteria);
sw.Stop();
//显示
Image<Bgr, Byte> imageResult = imageSourceGrayscale.Convert<Bgr, Byte>();
int cornerCount2 = 0;
StringBuilder sbResult =new StringBuilder();
int radius = (int)(minDistance / 2)+ 1;
int thickness = (int)(minDistance / 4)+ 1;
foreach (PointF[] cs in corners)
{
foreach(PointF p in cs)
{
imageResult.Draw(newCircleF(p, radius),new Bgr(255d, 0d, 0d), thickness);
cornerCount2++;
sbResult.AppendFormat("{0},", p);
}
}
pbResult.Image =imageResult.Bitmap;
//释放资源
imageResult.Dispose();
//返回
return string.Format("·亚像素级角点,用时{0:F05}毫秒,参数(搜索窗口:{1},死区:{2},最大迭代次数:{3},亚像素值的精度:{4}),检测到{5}个角点rn{6}",
sw.Elapsed.TotalMilliseconds, win, zeroZone, maxIter, epsilon,cornerCount2, cornerCount2 > 0 ?(sbResult.ToString()+ "rn") :"");
}
SURF角点
//SURF角点
private string SurfFeatureDetect()
{
//获取参数
bool getDescriptors = cbSurfGetDescriptors.Checked;
MCvSURFParams surfParam = newMCvSURFParams();
surfParam.extended=rbSurfBasicDescriptor.Checked ? 0: 1;
surfParam.hessianThreshold=double.Parse(txtSurfHessianThreshold.Text);
surfParam.nOctaves=int.Parse(txtSurfNumberOfOctaves.Text);
surfParam.nOctaveLayers=int.Parse(txtSurfNumberOfOctaveLay
SURFFeature[] features = null;
MKeyPoint[] keyPoints =null;
Stopwatch sw =new Stopwatch();
sw.Start();
if(getDescriptors)
features = imageSourceGrayscale.ExtractSURF(refsurfParam);
else
keyPoints = surfParam.DetectKeyPoints(imageSourceGrayscale,null);
sw.Stop();
//显示
bool showDetail = cbSurfShowDetail.Checked;
Image<Bgr, Byte> imageResult = imageSourceGrayscale.Convert<Bgr, Byte>();
StringBuilder sbResult =new StringBuilder();
int idx= 0;
if (getDescriptors)
{
foreach(SURFFeature featurein features)
{
imageResult.Draw(newCircleF(feature.Point.pt,5), newBgr(255d, 0d, 0d), 2);
if (showDetail)
{
sbResult.AppendFormat("第{0}点(坐标:{1},尺寸:{2},方向:{3}°,hessian值:{4},拉普拉斯标志:{5},描述:[",
idx, feature.Point.pt, feature.Point.size, feature.Point.dir,feature.Point.hessian, feature.Point.laplacian);
foreach (floatd in feature.Descriptor)
sbResult.AppendFormat("{0},", d);
sbResult.Append("]),");
}
idx++;
}
}
else
{
foreach(MKeyPoint keypointin keyPoints)
{
imageResult.Draw(newCircleF(keypoint.Point,5), newBgr(255d, 0d, 0d), 2);
if (showDetail)
sbResult.AppendFormat("第{0}点(坐标:{1},尺寸:{2},方向:{3}°,响应:{4},octave:{5}),",
idx, keypoint.Point, keypoint.Size, keypoint.Angle,keypoint.Response, keypoint.Octave);
idx++;
}
}
pbResult.Image =imageResult.Bitmap;
//释放资源
imageResult.Dispose();
//返回
return string.Format("·SURF角点,用时{0:F05}毫秒,参数(描述:{1},hessian阀值:{2},octave数目:{3},每个octave的层数:{4},检测到{5}个角点rn{6}",
sw.Elapsed.TotalMilliseconds, getDescriptors ? (surfParam.extended == 0? "获取基本描述": "获取扩展描述") :"不获取描述",surfParam.hessianThreshold,
surfParam.nOctaves, surfParam.nOctaveLayers, getDescriptors? features.Length : keyPoints.Length,showDetail ?sbResult.ToString()+ "rn": "");
}
Star关键点
//Star关键点
private string StarKeyPointFeatureDetec
{
StarDetector starParam = newStarDetector();
starParam.MaxSize =int.Parse((string)cmbStarMaxSize.SelectedItem);
starParam.ResponseThreshold = int.Parse(txtStarResponseThreshold
starParam.LineThresholdProjected
starParam.LineThresholdBinarized
starParam.SuppressNonmaxSize
Stopwatch sw = newStopwatch();
sw.Start();
MCvStarKeypoint[] keyPoints = imageSourceGrayscale.GetStarKeypoints(refstarParam);
sw.Stop();
//显示
Image<Bgr, Byte> imageResult = imageSourceGrayscale.Convert<Bgr, Byte>();
StringBuilder sbResult =new StringBuilder();
int idx= 0;
foreach (MCvStarKeypoint keypoint in keyPoints)
{
imageResult.Draw(newCircleF(new PointF(keypoint.pt.X, keypoint.pt.Y),keypoint.size /2), newBgr(255d, 0d, 0d),keypoint.size /4);
sbResult.AppendFormat("第{0}点(坐标:{1},尺寸:{2},强度:{3}),", idx,keypoint.pt, keypoint.size, keypoint.response);
idx++;
}
pbResult.Image =imageResult.Bitmap;
//释放资源
imageResult.Dispose();
//返回
return string.Format("·Star关键点,用时{0:F05}毫秒,参数(MaxSize:{1},ResponseThreshold:{2},LineThresholdProjected:{3},LineThresholdBinarized:{4},SuppressNonmaxSize:{5}),检测到{6}个关键点rn{7}",
sw.Elapsed.TotalMilliseconds, starParam.MaxSize,starParam.ResponseThreshold, starParam.LineThresholdProjected,starParam.LineThresholdBinarized, starParam.SuppressNonmaxSize,keyPoints.Length, keyPoints.Length > 0 ?(sbResult.ToString()+ "rn") :"");
}
FAST角点检测
void cvCornerFast( const CvArr* image, int threshold, intN,
image:
threshold:
N:
nonmax_suppression: Whether to perform nonmaximalsuppression.
ret_number_of_corners: The number of detected corners isreturned here.
ret_corners: The corners are returned here.
EmguCv中的Image<TColor,TDepth>.GetFASTKeypoints方法也实现了FAST角点检测,不过参数少了一些,只有threshold和nonmaxSupression,其中N我估计取的默认值9,但是返回的角点数目我不知道是怎么设置的。
使用FAST角点检测的示例代码如下:
//FAST关键点
private string FASTKeyPointFeatureDetec
{
int threshold = int.Parse(txtFASTThreshold.Text);
bool nonmaxSuppression = cbFASTNonmaxSuppression.Checked;
bool showDetail = cbFASTShowDetail.Checked;
//计算
Stopwatch sw = newStopwatch();
sw.Start();
MKeyPoint[] keyPoints =imageSourceGrayscale.GetFASTKeypoints(threshold,nonmaxSuppression);
sw.Stop();
//显示
Image<Bgr, Byte> imageResult = imageSourceGrayscale.Convert<Bgr, Byte>();
StringBuilder sbResult =new StringBuilder();
int idx= 0;
foreach (MKeyPoint keypoint in keyPoints)
{
imageResult.Draw(newCircleF(keypoint.Point,(int)(keypoint.Size / 2)),new Bgr(255d, 0d, 0d), (int)(keypoint.Size / 4));
if (showDetail)
sbResult.AppendFormat("第{0}点(坐标:{1},尺寸:{2},方向:{3}°,响应:{4},octave:{5}),",
idx, keypoint.Point, keypoint.Size, keypoint.Angle,keypoint.Response, keypoint.Octave);
idx++;
}
pbResult.Image =imageResult.Bitmap;
//释放资源
imageResult.Dispose();
//返回
return string.Format("·FAST关键点,用时{0:F05}毫秒,参数(阀值:{1},nonmaxSupression:{2}),检测到{3}个关键点rn{4}",
sw.Elapsed.TotalMilliseconds, threshold, nonmaxSuppression,keyPoints.Length, showDetail ? (sbResult.ToString() + "rn") :"");
}
Lepetit关键点
//Lepetit关键点
private string LepetitKeyPointFeatureDe
{
LDetector lepetitDetector = newLDetector();
lepetitDetector.BaseFeatureSize = double.Parse(txtLepetitBaseFeatureSiz
lepetitDetector.ClusteringDistance
lepetitDetector.NOctaves
lepetitDetector.NViews
lepetitDetector.Radius =int.Parse(txtLepetitRadius.Text);
lepetitDetector.Threshold = int.Parse(txtLepetitThreshold.Text);
lepetitDetector.Verbose = cbLepetitVerbose.Checked;
int maxCount = int.Parse(txtLepetitMaxCount.Text);
bool scaleCoords = cbLepetitScaleCoords.Checked;
bool showDetail = cbLepetitShowDetail.Checked;
//计算
Stopwatch sw = newStopwatch();
sw.Start();
MKeyPoint[] keyPoints =lepetitDetector.DetectKeyPoints(imageSourceGrayscale,maxCount, scaleCoords);
sw.Stop();
//显示
Image<Bgr, Byte> imageResult = imageSourceGrayscale.Convert<Bgr, Byte>();
StringBuilder sbResult =new StringBuilder();
int idx= 0;
foreach (MKeyPoint keypoint in keyPoints)
{
//imageResult.Draw(new CircleF(keypoint.Point,(int)(keypoint.Size / 2)), new Bgr(255d, 0d, 0d),(int)(keypoint.Size / 4));
imageResult.Draw(new CircleF(keypoint.Point, 4),new Bgr(255d, 0d, 0d), 2);
if (showDetail)
sbResult.AppendFormat("第{0}点(坐标:{1},尺寸:{2},方向:{3}°,响应:{4},octave:{5}),",
idx, keypoint.Point, keypoint.Size, keypoint.Angle,keypoint.Response, keypoint.Octave);
idx++;
}
pbResult.Image =imageResult.Bitmap;
//释放资源
imageResult.Dispose();
//返回
return string.Format("·Lepetit关键点,用时{0:F05}毫秒,参数(基础特征尺寸:{1},集群距离:{2},阶数:{3},视图数:{4},半径:{5},阀值:{6},计算详细结果:{7},最大关键点数目:{8},缩放坐标:{9}),检测到{10}个关键点rn{11}",
sw.Elapsed.TotalMilliseconds, lepetitDetector.BaseFeatureSize,lepetitDetector.ClusteringDistance, lepetitDetector.NOctaves,lepetitDetector.NViews,
lepetitDetector.Radius, lepetitDetector.Threshold,lepetitDetector.Verbose, maxCount, scaleCoords, keyPoints.Length,showDetail ?(sbResult.ToString()+ "rn") :"");
}
SIFT角点
//通过P/Invoke调用vlfeat函数来进行SIFT检测
unsafe private string SiftFeatureDetectByPinvo
{
StringBuilder sbResult =new StringBuilder();
//初始化
IntPtrptrSiftFilt =VlFeatInvoke.vl_sift_new(imageSource.Width,imageSource.Height, noctaves, nlevels, o_min);
if (ptrSiftFilt == IntPtr.Zero)
return "Sift特征检测:初始化失败。";
//处理
Image<Gray, Single> imageSourceSingle = imageSourceGrayscale.ConvertScale<Single>(1d,0d);
Image<Bgr, Byte> imageResult = imageSourceGrayscale.Convert<Bgr, Byte>();
int pointCount = 0;
int idx= 0;
//依次遍历每一组
if (VlFeatInvoke.vl_sift_process_first_octave(ptrSiftFilt,imageSourceSingle.MIplImage.imageData) != VlFeatInvoke.VL_ERR_EOF)
{
while(true)
{
//计算每组中的关键点
VlFeatInvoke.vl_sift_detect(ptrSiftFilt);
//遍历并绘制每个点
VlSiftFilt siftFilt = (VlSiftFilt)Marshal.PtrToStructure(ptrSiftFilt,typeof(VlSiftFilt));
pointCount +=siftFilt.nkeys;
VlSiftKeypoint*pKeyPoints = (VlSiftKeypoint*)siftFilt.keys.ToPointer();
for (inti = 0; i< siftFilt.nkeys; i++)
{
VlSiftKeypoint keyPoint = *pKeyPoints;
pKeyPoints++;
imageResult.Draw(newCircleF(new PointF(keyPoint.x, keyPoint.y),keyPoint.sigma /2), newBgr(255d, 0d, 0d), 2);
if (showDetail)
sbResult.AppendFormat("第{0}点,坐标:({1},{2}),阶:{3},缩放:{4},s:{5},",idx, keyPoint.x, keyPoint.y, keyPoint.o, keyPoint.sigma,keyPoint.s);
idx++;
//计算并遍历每个点的方向
double[]angles = new double[4];
int angleCount = VlFeatInvoke.vl_sift_calc_keypoint_orientations(ptrSiftFilt,angles, ref keyPoint);
if (showDetail)
sbResult.AppendFormat("共{0}个方向,",angleCount);
for(int j= 0; j< angleCount; j++)
{
doubleangle = angles[j];
if (showDetail)
sbResult.AppendFormat("【方向:{0},描述:",angle);
//计算每个方向的描述
IntPtrptrDescriptors =Marshal.AllocHGlobal(128 *sizeof(float));
VlFeatInvoke.vl_sift_calc_keypoint_descriptor(ptrSiftFilt,ptrDescriptors, refkeyPoint, angle);
float* pDescriptors = (float*)ptrDescriptors.ToPointer();
for (intk = 0; k< 128;k++)
{
floatdescriptor = *pDescriptors;
pDescriptors++;
if (showDetail)
sbResult.AppendFormat("{0},",descriptor);
}
sbResult.Append("】,");
Marshal.FreeHGlobal(ptrDescriptors);
}
}
//下一阶
if (VlFeatInvoke.vl_sift_process_next_octave(ptrSiftFilt)== VlFeatInvoke.VL_ERR_EOF)
break;
}
}
//显示
pbResult.Image = imageResult.Bitmap;
//释放资源
VlFeatInvoke.vl_sift_delete(ptrSiftFilt);
imageSourceSingle.Dispose();
imageResult.Dispose();
//返回
return string.Format("·SIFT特征检测(P/Invoke),用时:未统计,参数(阶数:{0},每阶层数:{1},最小阶索引:{2}),{3}个关键点rn{4}",
noctaves, nlevels, o_min, pointCount, showDetail? (sbResult.ToString() + "rn") :"");
}
//通过dotnet封装的SiftDetector类来进行SIFT检测
private string SiftFeatureDetectByDotNe
{
//初始化对象
SiftDetector siftDetector = newSiftDetector(imageSource.Size,noctaves, nlevels, o_min);
//计算
Image<Gray, Single> imageSourceSingle = imageSourceGrayscale.Convert<Gray, Single>();
Stopwatch sw =new Stopwatch();
sw.Start();
List<SiftFeature> features = siftDetector.Process(imageSourceSingle,showDetail ?SiftDetectorResultType.Extended :SiftDetectorResultType.Basic);
sw.Stop();
//显示结果
Image<Bgr, Byte> imageResult = imageSourceGrayscale.Convert<Bgr, Byte>();
StringBuilder sbResult =new StringBuilder();
int idx=0;
foreach (SiftFeature feature in features)
{
imageResult.Draw(newCircleF(new PointF(feature.keypoint.x, feature.keypoint.y),feature.keypoint.sigma /2), newBgr(255d, 0d, 0d), 2);
if (showDetail)
{
sbResult.AppendFormat("第{0}点,坐标:({1},{2}),阶:{3},缩放:{4},s:{5},",
idx, feature.keypoint.x, feature.keypoint.y, feature.keypoint.o,feature.keypoint.sigma, feature.keypoint.s);
sbResult.AppendFormat("共{0}个方向,",feature.keypointOrientations != null? feature.keypointOrientations.Length :0);
if (feature.keypointOrientations != null)
{
foreach(SiftKeyPointOrientationorientation infeature.keypointOrientations)
{
if (orientation.descriptors != null)
{
sbResult.AppendFormat("【方向:{0},描述:",orientation.angle);
foreach (floatdescriptor in orientation.descriptors)
sbResult.AppendFormat("{0},",descriptor);
}
else
sbResult.AppendFormat("【方向:{0},",orientation.angle);
sbResult.Append("】,");
}
}
}
}
pbResult.Image =imageResult.Bitmap;
//释放资源
siftDetector.Dispose();
imageSourceSingle.Dispose();
imageResult.Dispose();
//返回
return string.Format("·SIFT特征检测(.net),用时:{0:F05}毫秒,参数(阶数:{1},每阶层数:{2},最小阶索引:{3}),{4}个关键点rn{5}",
sw.Elapsed.TotalMilliseconds, noctaves, nlevels, o_min,features.Count, showDetail ? (sbResult.ToString() + "rn") :"");
}
usingSystem;
using System.Collections.Generic;
usingSystem.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespaceImageProcessLearn
{
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct VlSiftKeypoint
{
/// int
public int o;
/// int
public int ix;
/// int
public int iy;
/// int
public int @is;
/// float
public float x;
/// float
public float y;
/// float
public float s;
/// float
public float sigma;
}
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct VlSiftFilt
{
/// double
public double sigman;
/// double
public double sigma0;
/// double
public double sigmak;
/// double
public double dsigma0;
/// int
public int width;
/// int
public int height;
/// int
public int O;
/// int
public int S;
/// int
public int o_min;
/// int
public int s_min;
/// int
public int s_max;
/// int
public int o_cur;
/// vl_sift_pix*
public System.IntPtr temp;
/// vl_sift_pix*
public System.IntPtr octave;
/// vl_sift_pix*
public System.IntPtr dog;
/// int
public int octave_width;
/// int
public int octave_height;
/// VlSiftKeypoint*
public System.IntPtr keys;
/// int
public int nkeys;
/// int
public int keys_res;
/// double
public double peak_thresh;
/// double
public double edge_thresh;
/// double
public double norm_thresh;
/// double
public double magnif;
/// double
public double windowSize;
/// vl_sift_pix*
public System.IntPtr grad;
/// int
public int grad_o;
/// <summary>
/// 获取SiftFilt指针;
/// 注意在使用完指针之后,需要用Marshal.FreeHGlobal释放内存。
/// </summary>
/// <returns></returns>
unsafe public IntPtrGetPtrOfVlSiftFilt()
{
IntPtr ptrSiftFilt =Marshal.AllocHGlobal(sizeof(VlSiftFilt));
Marshal.StructureToPtr(this,ptrSiftFilt, true);
return ptrSiftFilt;
}
}
publicclass VlFeatInvoke
{
/// VL_ERR_MSG_LEN ->1024
public const int VL_ERR_MSG_LEN = 1024;
/// VL_ERR_OK -> 0
public const int VL_ERR_OK = 0;
/// VL_ERR_OVERFLOW ->1
public const int VL_ERR_OVERFLOW = 1;
/// VL_ERR_ALLOC ->2
public const int VL_ERR_ALLOC = 2;
/// VL_ERR_BAD_ARG ->3
public const int VL_ERR_BAD_ARG = 3;
/// VL_ERR_IO -> 4
public const int VL_ERR_IO = 4;
/// VL_ERR_EOF -> 5
public const int VL_ERR_EOF = 5;
/// VL_ERR_NO_MORE ->5
public const int VL_ERR_NO_MORE = 5;
/// Return Type: VlSiftFilt*
///width:int
///height:int
///noctaves:int
///nlevels:int
///o_min:int
[DllImportAttribute("vl.dll",EntryPoint ="vl_sift_new")]
public static extern System.IntPtr vl_sift_new(int width, int height, int noctaves, int nlevels, int o_min);
/// Return Type: void
///f:VlSiftFilt*
[DllImportAttribute("vl.dll",EntryPoint ="vl_sift_delete")]
public static extern void vl_sift_delete(IntPtr f);
/// Return Type: int
///f:VlSiftFilt*
///im:vl_sift_pix*
[DllImportAttribute("vl.dll",EntryPoint ="vl_sift_process_first_octave")]
public static extern int vl_sift_process_first_octave(IntPtr f, IntPtrim);
/// Return Type: int
///f:VlSiftFilt*
[DllImportAttribute("vl.dll",EntryPoint ="vl_sift_process_next_octave")]
public static extern int vl_sift_process_next_octave(IntPtr f);
/// Return Type: void
///f:VlSiftFilt*
[DllImportAttribute("vl.dll",EntryPoint ="vl_sift_detect")]
public static extern void vl_sift_detect(IntPtr f);
/// Return Type: int
///f:VlSiftFilt*
///angles:double*
///k:VlSiftKeypoint*
[DllImportAttribute("vl.dll",EntryPoint ="vl_sift_calc_keypoint_orientations")]
public static extern int vl_sift_calc_keypoint_orientations(IntPtrf, double[] angles, ref VlSiftKeypoint k);
/// Return Type: void
///f:VlSiftFilt*
///descr:vl_sift_pix*
///k:VlSiftKeypoint*
///angle:double
[DllImportAttribute("vl.dll",EntryPoint ="vl_sift_calc_keypoint_descriptor")]
public static extern void vl_sift_calc_keypoint_descriptor(IntPtr f, IntPtrdescr, ref VlSiftKeypoint k, double angle);
/// Return Type: void
///f:VlSiftFilt*
///image:vl_sift_pix*
///descr:vl_sift_pix*
///widht:int
///height:int
///x:double
///y:double
///s:double
///angle0:double
[DllImportAttribute("vl.dll",EntryPoint ="vl_sift_calc_raw_descriptor")]
public static extern void vl_sift_calc_raw_descriptor(IntPtr f, IntPtrimage, IntPtr descr, intwidht, int height, double x, double y, double s, double angle0);
/// Return Type: void
///f:VlSiftFilt*
///k:VlSiftKeypoint*
///x:double
///y:double
///sigma:double
[DllImportAttribute("vl.dll",EntryPoint ="vl_sift_keypoint_init")]
public static extern void vl_sift_keypoint_init(IntPtr f,ref VlSiftKeypoint k, double x, double y, double sigma);
}
}
SiftDetector类的实现代码如下所示:
using System;
using System.Collections.Generic;
usingSystem.Linq;
using System.Text;
using System.Drawing;
using System.Runtime.InteropServices;
usingEmgu.CV;
using Emgu.CV.Structure;
namespaceImageProcessLearn
{
/// <summary>
/// SIFT检测器
/// </summary>
public class SiftDetector : IDisposable
{
//成员变量
private IntPtrptrSiftFilt;
//属性
/// <summary>
/// SiftFilt指针
/// </summary>
public IntPtr PtrSiftFilt
{
get
{
returnptrSiftFilt;
}
}
/// <summary>
/// 获取SIFT检测器中的SiftFilt
/// </summary>
public VlSiftFilt SiftFilt
{
get
{
return(VlSiftFilt)Marshal.PtrToStructure(ptrSiftFilt,typeof(VlSiftFilt));
}
}
/// <summary>
/// 构造函数
/// </summary>
/// <paramname="width">图像的宽度</param>
/// <paramname="height">图像的高度</param>
/// <paramname="noctaves">阶数</param>
/// <paramname="nlevels">每一阶的层数</param>
/// <paramname="o_min">最小阶的索引</param>
public SiftDetector(int width, int height, int noctaves, int nlevels, int o_min)
{
ptrSiftFilt =VlFeatInvoke.vl_sift_new(width,height, noctaves, nlevels, o_min);
}
publicSiftDetector(int width, int height)
: this(width, height, 4,2, 0)
{ }
publicSiftDetector(Size size,int noctaves, int nlevels, int o_min)
: this(size.Width, size.Height, noctaves, nlevels,o_min)
{ }
publicSiftDetector(Size size)
: this(size.Width, size.Height, 4,2, 0)
{ }
/// <summary>
/// 进行SIFT检测,并返回检测的结果
/// </summary>
/// <paramname="im">单通道浮点型图像数据,图像数据不必归一化到区间[0,1]</param>
/// <paramname="resultType">SIFT检测的结果类型</param>
/// <returns>返回SIFT检测结果——SIFT特征列表;如果检测失败,返回null。</returns>
unsafe public List<SiftFeature> Process(IntPtr im, SiftDetectorResultTyperesultType)
{
//定义变量
List<SiftFeature> features = null;//检测结果:SIFT特征列表
VlSiftFilt siftFilt; //
VlSiftKeypoint* pKeyPoints; //指向关键点的指针
VlSiftKeypoint keyPoint; //关键点
SiftKeyPointOrientation[] orientations;//关键点对应的方向及描述
double[]angles = new double[4];//关键点对应的方向(角度)
int angleCount; //某个关键点的方向数目
double angle; //方向
float[]descriptors; //关键点某个方向的描述
IntPtrptrDescriptors =Marshal.AllocHGlobal(128 *sizeof(float)); //指向描述的缓冲区指针
//依次遍历每一阶
if (VlFeatInvoke.vl_sift_process_first_octave(ptrSiftFilt,im) != VlFeatInvoke.VL_ERR_EOF)
{
features = new List<SiftFeature>(100);
while (true)
{
//计算每组中的关键点
VlFeatInvoke.vl_sift_detect(ptrSiftFilt);
//遍历每个点
siftFilt = (VlSiftFilt)Marshal.PtrToStructure(ptrSiftFilt,typeof(VlSiftFilt));
pKeyPoints =(VlSiftKeypoint*)siftFilt.keys.ToPointer();
for (inti = 0; i< siftFilt.nkeys; i++)
{
keyPoint = *pKeyPoints;
pKeyPoints++;
orientations =null;
if (resultType == SiftDetectorResultType.Normal || resultType == SiftDetectorResultType.Extended)
{
//计算并遍历每个点的方向
angleCount = VlFeatInvoke.vl_sift_calc_keypoint_orientations(ptrSiftFilt,angles, ref keyPoint);
orientations =new SiftKeyPointOrientation[angleCount];
for (intj = 0; j< angleCount; j++)
{
angle = angles[j];
descriptors =null;
if (resultType == SiftDetectorResultType.Extended)
{
//计算每个方向的描述
VlFeatInvoke.vl_sift_calc_keypoint_descriptor(ptrSiftFilt,ptrDescriptors, refkeyPoint, angle);
descriptors =new float[128];
Marshal.Copy(ptrDescriptors, descriptors, 0,128);
}
orientations[j] =new SiftKeyPointOrientation(angle,descriptors); //保存关键点方向和描述
}
}
features.Add(newSiftFeature(keyPoint,orientations)); //将得到的特征添加到列表中
}
//下一阶
if (VlFeatInvoke.vl_sift_process_next_octave(ptrSiftFilt)== VlFeatInvoke.VL_ERR_EOF)
break;
}
}
//释放资源
Marshal.FreeHGlobal(ptrDescriptors);
//返回
return features;
}
/// <summary>
/// 进行基本的SIFT检测,并返回关键点列表
/// </summary>
/// <paramname="im">单通道浮点型图像数据,图像数据不必归一化到区间[0,1]</param>
/// <returns>返回关键点列表;如果获取失败,返回null。</returns>
public List<SiftFeature> Process(IntPtr im)
{
returnProcess(im,SiftDetectorResultType.Basic);
}
/// <summary>
/// 进行SIFT检测,并返回检测的结果
/// </summary>
/// <paramname="image">图像</param>
/// <paramname="resultType">SIFT检测的结果类型</param>
/// <returns>返回SIFT检测结果——SIFT特征列表;如果检测失败,返回null。</returns>
public List<SiftFeature> Process(Image<Gray, Single> image, SiftDetectorResultType resultType)
{
if (image.Width != SiftFilt.width || image.Height != SiftFilt.height)
throw new ArgumentException("图像的尺寸和构造函数中指定的尺寸不一致。","image");
return Process(image.MIplImage.imageData,resultType);
}
/// <summary>
/// 进行基本的SIFT检测,并返回检测的结果
/// </summary>
/// <paramname="image">图像</param>
/// <returns>返回SIFT检测结果——SIFT特征列表;如果检测失败,返回null。</returns>
public List<SiftFeature> Process(Image<Gray, Single> image)
{
returnProcess(image,SiftDetectorResultType.Basic);
}
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
if (ptrSiftFilt != IntPtr.Zero)
VlFeatInvoke.vl_sift_delete(ptrSiftFilt);
}
}
/// <summary>
/// SIFT特征
/// </summary>
public struct SiftFeature
{
publicVlSiftKeypoint keypoint;//关键点
public SiftKeyPointOrientation[]keypointOrientations; //关键点的方向及方向对应的描述
public SiftFeature(VlSiftKeypoint keypoint)
: this(keypoint, null)
{
}
publicSiftFeature(VlSiftKeypoint keypoint,SiftKeyPointOrientation[] keypointOrientations)
{
this.keypoint = keypoint;
this.keypointOrientations = keypointOrientations;
}
}
/// <summary>
/// Sift关键点的方向及描述
/// </summary>
public struct SiftKeyPointOrientation
{
publicdouble angle; //方向
public float[]descriptors; //描述
public SiftKeyPointOrientation(double angle)
: this(angle, null)
{
}
publicSiftKeyPointOrientation(double angle, float[]descriptors)
{
this.angle = angle;
this.descriptors = descriptors;
}
}
/// <summary>
/// SIFT检测的结果
/// </summary>
public enum SiftDetectorResultType
{
Basic, //基本:仅包含关键点
Normal, //正常:包含关键点、方向
Extended //扩展:包含关键点、方向以及描述
}
}
MSER区域
private string MserFeatureDetect()
{
//获取参数
MCvMSERParams mserParam = newMCvMSERParams();
mserParam.delta =int.Parse(txtMserDelta.Text);
mserParam.maxArea =int.Parse(txtMserMaxArea.Text);
mserParam.minArea =int.Parse(txtMserMinArea.Text);
mserParam.maxVariation =float.Parse(txtMserMaxVariation.Text);
mserParam.minDiversity =float.Parse(txtMserMinDiversity.Text);
mserParam.maxEvolution =int.Parse(txtMserMaxEvolution.Text);
mserParam.areaThreshold = double.Parse(txtMserAreaThreshold.Text);
mserParam.minMargin =double.Parse(txtMserMinMargin.Text);
mserParam.edgeBlurSize =int.Parse(txtMserEdgeBlurSize.Text);
bool showDetail = cbMserShowDetail.Checked;
//计算
Stopwatch sw = newStopwatch();
sw.Start();
MemStorage storage =new MemStorage();
Seq<Point>[] regions = imageSource.ExtractMSER(null,ref mserParam, storage);
sw.Stop();
//显示
Image<Bgr, Byte> imageResult = imageSourceGrayscale.Convert<Bgr, Byte>();
StringBuilder sbResult =new StringBuilder();
int idx= 0;
foreach (Seq<Point> region in regions)
{
imageResult.DrawPolyline(region.ToArray(), true,new Bgr(255d, 0d, 0d), 2);
if (showDetail)
{
sbResult.AppendFormat("第{0}区域,包含{1}个顶点(", idx,region.Total);
foreach (Pointpt in region)
sbResult.AppendFormat("{0},", pt);
sbResult.Append(")rn");
}
idx++;
}
pbResult.Image =imageResult.Bitmap;
//释放资源
imageResult.Dispose();
storage.Dispose();
//返回
return string.Format("·MSER区域,用时{0:F05}毫秒,参数(delta:{1},maxArea:{2},minArea:{3},maxVariation:{4},minDiversity:{5},maxEvolution:{6},areaThreshold:{7},minMargin:{8},edgeBlurSize:{9}),检测到{10}个区域rn{11}",
sw.Elapsed.TotalMilliseconds, mserParam.delta, mserParam.maxArea,mserParam.minArea, mserParam.maxVariation,mserParam.minDiversity,
mserParam.maxEvolution, mserParam.areaThreshold,mserParam.minMargin, mserParam.edgeBlurSize, regions.Length,showDetail ?sbResult.ToString() :"");
}
各种特征检测方法性能对比
(图片尺寸:583x301,处理器:AMD ATHLON IIx2 240,内存:DDR3 4G,显卡:GeForce9500GT,操作系统:Windows 7)
本文来自http://www.cnblogs.com/xrwang/archive/2010/03/03/ImageFeatureDetection.html。作者:王先荣
- Opencv2.3 图像特征检测总结
- Opencv2.3 图像特征检测总结
- androidstudio opencv2.4.10下使用图像拼接,特征检测
- 【OpenCV2.3特征检测与描述】Feature Detection and Description
- 关于opencv2和3在图像特征识别的区别。
- 图像特征检测
- opencv2提取图像LBP特征代码详解
- 图像特征提取:边缘检测
- 图像特征提取:边缘检测
- 图像特征提取,斑点检测
- OpenCV检测图像SURF特征
- 图像特征提取:斑点检测
- 基于图像配准的图像特征检测之sift算法----sift算法总结
- 图像特征提取总结
- 图像特征提取总结
- 图像特征提取总结
- 图像特征提取总结
- 图像特征提取总结
- 基于Matlab的STM32软件快速…
- STM32学习笔记之正交编码器…
- STM32 编码器连接
- 黑马程序员—Java基础加强(反射)
- STM32数据类型定义
- Opencv2.3 图像特征检测总结
- mybatis+spring 使用不同方法备忘
- 基于Lucene4.6+Solr4.6+Heritrix1.14+S2SH实战开发从无到有垂直搜索引擎
- 陈杰:云时代的网络威胁与应对
- mybatis sql in 查询
- m2ts视频格式在windows及mac下的解决方案
- orcale 行转列与列转行 查询临时表名
- TreeMap发展
- 贪心算法