opencvsharp编写一个高精度找圆心函数, 这个函数会输入一张图、一个圆心中心位置的大约位置、输入找圆扇形区域的最小半径和最大半径、设定扇形区域起始角度、扇形区域结束角度、扇形区域的法线上找交点个数 、找边沿点宽度、从内到外找圆心、从黑到白找圆惦、找圆分数、 canny参数 根据给定的圆心位置和半径范围定义一个圆环区域。 为了加快找圆心速度,将圆环区域分成多份,可设定,并行计算找出边沿点 在边缘图像中找到最长的轮廓。 对轮廓上的点进行拟合,得到圆心和半径。
时间: 2023-07-10 13:05:44 浏览: 81
以下是一个使用 OpenCVSharp 编写的高精度找圆心函数的示例代码:
```csharp
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Linq;
namespace CircleDetector
{
class CircleDetector
{
private Mat _src;
private Point _approxCenter;
private int _minRadius;
private int _maxRadius;
private double _startAngle;
private double _endAngle;
private int _numIntersections;
private int _edgeWidth;
private int _numSectors;
private double _minScore;
private int _cannyThreshold1;
private int _cannyThreshold2;
public CircleDetector(Mat src, Point approxCenter, int minRadius, int maxRadius,
double startAngle, double endAngle, int numIntersections, int edgeWidth,
int numSectors, double minScore, int cannyThreshold1, int cannyThreshold2)
{
_src = src;
_approxCenter = approxCenter;
_minRadius = minRadius;
_maxRadius = maxRadius;
_startAngle = startAngle;
_endAngle = endAngle;
_numIntersections = numIntersections;
_edgeWidth = edgeWidth;
_numSectors = numSectors;
_minScore = minScore;
_cannyThreshold1 = cannyThreshold1;
_cannyThreshold2 = cannyThreshold2;
}
public CircleResult FindCircle()
{
// Define the circular region of interest
int roiRadius = (_maxRadius - _minRadius) / 2;
int roiRadiusSquared = roiRadius * roiRadius;
Point roiCenter = new Point(_approxCenter.X - roiRadius, _approxCenter.Y - roiRadius);
Rect roiRect = new Rect(roiCenter, new Size(roiRadius * 2, roiRadius * 2));
// Create a mask for the circular region of interest
Mat mask = new Mat(_src.Size(), MatType.CV_8UC1, Scalar.All(0));
Cv2.Circle(mask, roiCenter + new Point(roiRadius, roiRadius), roiRadius, Scalar.All(255), -1);
// Apply Canny edge detection to the region of interest
Mat edges = new Mat();
Cv2.Canny(_src, edges, _cannyThreshold1, _cannyThreshold2);
edges = edges.And(mask);
// Divide the circular region of interest into sectors
List<Point>[] sectorPoints = new List<Point>[_numSectors];
for (int i = 0; i < _numSectors; i++)
{
sectorPoints[i] = new List<Point>();
}
for (int y = roiCenter.Y; y < roiCenter.Y + roiRadius * 2; y++)
{
for (int x = roiCenter.X; x < roiCenter.X + roiRadius * 2; x++)
{
Point p = new Point(x, y) - roiCenter - new Point(roiRadius, roiRadius);
int rSquared = p.X * p.X + p.Y * p.Y;
if (rSquared >= roiRadiusSquared - _edgeWidth && rSquared <= roiRadiusSquared)
{
double angle = Math.Atan2(p.Y, p.X) * 180 / Math.PI;
if (angle < 0)
{
angle += 360;
}
int sectorIndex = (int)Math.Floor(angle / 360 * _numSectors);
sectorPoints[sectorIndex].Add(new Point(x, y));
}
}
}
// Find the longest contour in each sector
List<Point>[] sectorContours = new List<Point>[_numSectors];
for (int i = 0; i < _numSectors; i++)
{
List<Point> sectorEdges = new List<Point>();
foreach (Point p in sectorPoints[i])
{
if (edges.At<byte>(p.Y, p.X) != 0)
{
sectorEdges.Add(p);
}
}
if (sectorEdges.Count > 0)
{
Mat sectorEdgesMat = new Mat(sectorEdges.Count, 1, MatType.CV_32SC2, sectorEdges.Select(p => new Point2i(p.X, p.Y)).ToArray());
Mat hull = new Mat();
Cv2.ConvexHull(sectorEdgesMat, hull);
List<Point> contour = Cv2.Polylines(hull, true).ToList();
sectorContours[i] = contour;
}
}
// Find the best circle using the intersections of the longest contours
double bestScore = 0;
CircleResult bestCircle = null;
for (int i = 0; i < _numSectors; i++)
{
List<Point> contour = sectorContours[i];
if (contour != null && contour.Count >= _numIntersections)
{
double sectorStartAngle = i * 360.0 / _numSectors;
double sectorEndAngle = (i + 1) * 360.0 / _numSectors;
double sectorScore = ScoreContour(contour, sectorStartAngle, sectorEndAngle);
if (sectorScore >= bestScore && sectorScore >= _minScore)
{
CircleResult circle = FitCircle(contour);
if (circle != null)
{
bestScore = sectorScore;
bestCircle = circle;
}
}
}
}
return bestCircle;
}
private double ScoreContour(List<Point> contour, double startAngle, double endAngle)
{
int numSamples = _numIntersections;
double angleIncrement = (endAngle - startAngle) / numSamples;
double score = 0;
for (int i = 0; i < numSamples; i++)
{
double angle = startAngle + i * angleIncrement;
double closestDistance = double.MaxValue;
foreach (Point p in contour)
{
double pAngle = Math.Atan2(p.Y - _approxCenter.Y, p.X - _approxCenter.X) * 180 / Math.PI;
if (pAngle < 0)
{
pAngle += 360;
}
if (pAngle >= angle && pAngle < angle + angleIncrement)
{
double distance = Math.Sqrt((p.X - _approxCenter.X) * (p.X - _approxCenter.X) + (p.Y - _approxCenter.Y) * (p.Y - _approxCenter.Y));
if (distance < closestDistance)
{
closestDistance = distance;
}
}
}
score += closestDistance;
}
return score;
}
private CircleResult FitCircle(List<Point> contour)
{
if (contour.Count < 5)
{
return null;
}
Mat contourMat = new Mat(contour.Count, 1, MatType.CV_32SC2, contour.Select(p => new Point2i(p.X, p.Y)).ToArray());
double[] center = new double[2];
double[] radius = new double[1];
Cv2.MinEnclosingCircle(contourMat, center, radius);
CircleResult circle = new CircleResult(new Point((int)Math.Round(center[0]), (int)Math.Round(center[1])), (int)Math.Round(radius[0]));
int numInliers = 0;
for (int i = 0; i < contour.Count; i++)
{
double distance = Math.Sqrt((contour[i].X - circle.Center.X) * (contour[i].X - circle.Center.X) + (contour[i].Y - circle.Center.Y) * (contour[i].Y - circle.Center.Y));
if (distance < circle.Radius)
{
numInliers++;
}
}
if (numInliers < 5)
{
return null;
}
return circle;
}
}
class CircleResult
{
public Point Center { get; private set; }
public int Radius { get; private set; }
public CircleResult(Point center, int radius)
{
Center = center;
Radius = radius;
}
}
}
```
这个 `CircleDetector` 类的构造函数需要传入许多参数,包括输入图像、圆心的大约位置、最小半径和最大半径、扇形区域的起始角度和结束角度、扇形区域的法线上找交点的个数、找边沿点的宽度、分割圆环区域的数量等等。然后,你可以调用 `FindCircle` 方法来执行圆心检测。这个方法将返回一个 `CircleResult` 对象,其中包含检测到的圆心位置和半径。
阅读全文