OpenCvSharp 编写多线程CircularCaliper找圆心函数 , 输入图像、找圆扇形区域的最小半径和最大半径、找圆扇形中心点、设定扇形区域起始角度、扇形区域结束角度 输入Caliper个数,宽度、长度、 输入从内到外找圆心、从黑到白找圆 输入canny参数 并行计Caliper区域,将Caliper区域所有canny点合并,拟合圆心 输出圆中心点、半径请编写函数
时间: 2023-07-10 19:07:26 浏览: 276
以下是基于OpenCvSharp的多线程CircularCaliper找圆心函数的示例代码:
```csharp
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
using OpenCvSharp;
public class CircularCaliperFinder
{
private readonly Mat inputImage;
private readonly int minRadius;
private readonly int maxRadius;
private readonly Point2f center;
private readonly double startAngle;
private readonly double endAngle;
private readonly int caliperCount;
private readonly int caliperWidth;
private readonly int caliperLength;
private readonly bool fromInside;
private readonly bool fromBlackToWhite;
private readonly int cannyThreshold1;
private readonly int cannyThreshold2;
private readonly ConcurrentBag<Point>[] caliperPoints;
public CircularCaliperFinder(Mat inputImage, int minRadius, int maxRadius, Point2f center, double startAngle, double endAngle,
int caliperCount, int caliperWidth, int caliperLength, bool fromInside, bool fromBlackToWhite,
int cannyThreshold1, int cannyThreshold2)
{
this.inputImage = inputImage;
this.minRadius = minRadius;
this.maxRadius = maxRadius;
this.center = center;
this.startAngle = startAngle;
this.endAngle = endAngle;
this.caliperCount = caliperCount;
this.caliperWidth = caliperWidth;
this.caliperLength = caliperLength;
this.fromInside = fromInside;
this.fromBlackToWhite = fromBlackToWhite;
this.cannyThreshold1 = cannyThreshold1;
this.cannyThreshold2 = cannyThreshold2;
this.caliperPoints = new ConcurrentBag<Point>[caliperCount];
for (int i = 0; i < caliperCount; i++)
{
this.caliperPoints[i] = new ConcurrentBag<Point>();
}
}
public (Point2f center, float radius) FindCircleCenter()
{
int step = (maxRadius - minRadius) / caliperCount;
Parallel.For(0, caliperCount, i =>
{
int radius = minRadius + i * step;
double angleStep = (endAngle - startAngle) / (caliperWidth - 1);
for (int j = 0; j < caliperWidth; j++)
{
double angle = startAngle + j * angleStep;
Point2f p1 = GetCaliperPoint(angle, radius, center);
Point2f p2 = GetCaliperPoint(angle + 180, radius, center);
byte[] profile = GetProfile(p1, p2, fromInside, fromBlackToWhite);
int edgePos = GetEdgePosition(profile, fromBlackToWhite);
if (edgePos >= 0)
{
Point edgePoint = GetCaliperPoint(angle + edgePos * angleStep, radius, center).ToPoint();
caliperPoints[i].Add(edgePoint);
}
}
});
List<Point> allPoints = new List<Point>();
foreach (var pointList in caliperPoints)
{
allPoints.AddRange(pointList);
}
Mat cannyImage = new Mat();
Cv2.Canny(inputImage, cannyImage, cannyThreshold1, cannyThreshold2);
Point2f[] circleCenters = Cv2.HoughCircles(cannyImage, HoughModes.Gradient, 1, 20, param1: 50, param2: 30,
minRadius: (int)(center.X - minRadius), maxRadius: (int)(center.X + maxRadius));
Point2f center = new Point2f();
float radius = 0;
if (circleCenters != null)
{
for (int i = 0; i < circleCenters.Length; i++)
{
double totalDistance = 0;
foreach (var point in allPoints)
{
double distance = Math.Sqrt(Math.Pow(point.X - circleCenters[i].X, 2) + Math.Pow(point.Y - circleCenters[i].Y, 2));
totalDistance += distance;
}
double averageDistance = totalDistance / allPoints.Count;
if (averageDistance < radius || radius == 0)
{
center = circleCenters[i];
radius = (float)averageDistance;
}
}
}
return (center, radius);
}
private Point2f GetCaliperPoint(double angle, double radius, Point2f center)
{
double x = center.X + radius * Math.Cos(angle * Math.PI / 180);
double y = center.Y + radius * Math.Sin(angle * Math.PI / 180);
return new Point2f((float)x, (float)y);
}
private byte[] GetProfile(Point2f p1, Point2f p2, bool fromInside, bool fromBlackToWhite)
{
LineIterator lineIter = new LineIterator(inputImage, p1, p2);
byte[] profile = new byte[lineIter.Count];
for (int i = 0; i < profile.Length; i++)
{
profile[i] = lineIter.GetValue(i);
}
if (fromInside && !fromBlackToWhite || !fromInside && fromBlackToWhite)
{
Array.Reverse(profile);
}
return profile;
}
private int GetEdgePosition(byte[] profile, bool fromBlackToWhite)
{
for (int i = 0; i < profile.Length - 1; i++)
{
if (fromBlackToWhite && profile[i] < profile[i + 1] || !fromBlackToWhite && profile[i] > profile[i + 1])
{
return i;
}
}
return -1;
}
}
```
这个函数的输入参数意义如下:
- `inputImage`:输入图像。
- `minRadius`:找圆扇形区域的最小半径。
- `maxRadius`:找圆扇形区域的最大半径。
- `center`:找圆扇形中心点。
- `startAngle`:设定扇形区域起始角度。
- `endAngle`:扇形区域结束角度。
- `caliperCount`:输入Caliper个数。
- `caliperWidth`:Caliper宽度。
- `caliperLength`:Caliper长度。
- `fromInside`:是否从内到外找圆心。
- `fromBlackToWhite`:是否从黑到白找圆。
- `cannyThreshold1`:Canny算子参数1。
- `cannyThreshold2`:Canny算子参数2。
这个函数的输出结果是一个包含圆中心点和半径的元组 `(Point2f center, float radius)`。
这个函数的实现基于多线程和并行计算。首先,根据输入参数设置多个圆弧上的Caliper,每个Caliper沿着圆弧方向按照一定的间隔采样,采集Caliper区域内的所有Canny点。然后将所有的Canny点合并起来,利用Hough变换拟合圆心。最后,对于每个Hough变换得到的圆心,计算所有Canny点到圆心的平均距离,选择平均距离最小的圆作为最终结果。
需要注意的是,这个函数的实现仅供参考,具体实现可能需要根据实际情况进行调整。
阅读全文