OpenCvSharp 编写多线程CircularCaliper找圆心函数 , 输入图像、找圆扇形区域的最小半径和最大半径、找圆扇形中心点、设定扇形区域起始角度、扇形区域结束角度 输入Caliper个数,宽度、长度、 输入从内到外找圆心、从黑到白找圆 输入canny参数 并行计Caliper区域,将Caliper区域所有canny点合并,拟合圆心 输出圆中心点、半径请编写函数
时间: 2023-07-10 16:07:48 浏览: 132
下面是一个使用 OpenCvSharp 编写多线程 CircularCaliper 找圆心的示例函数:
```csharp
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using OpenCvSharp;
public static class CircularCaliper
{
public static CircleInfo FindCircle(Mat image, int minRadius, int maxRadius, Point center, double startAngle, double endAngle, int caliperCount, int caliperWidth, int caliperLength, bool fromInsideToOutside, bool fromBlackToWhite, double cannyThreshold1, double cannyThreshold2)
{
// 建立圆弧上的采样点
int pointCount = 360;
double deltaAngle = (endAngle - startAngle) / pointCount;
Point[] points = new Point[pointCount];
for (int i = 0; i < pointCount; i++)
{
double angle = startAngle + deltaAngle * i;
double x = center.X + maxRadius * Math.Cos(angle);
double y = center.Y + maxRadius * Math.Sin(angle);
points[i] = new Point((int)Math.Round(x), (int)Math.Round(y));
}
// 建立 Caliper 区域
int caliperStep = pointCount / caliperCount;
Caliper[] calipers = new Caliper[caliperCount];
for (int i = 0; i < caliperCount; i++)
{
int startIndex = i * caliperStep;
int endIndex = (i + 1) * caliperStep - 1;
calipers[i] = new Caliper(points[startIndex], points[endIndex], caliperWidth, caliperLength);
}
// 多线程计算 Caliper 区域所有 Canny 点
ConcurrentBag<Point> cannyPoints = new ConcurrentBag<Point>();
Parallel.ForEach(calipers, caliper =>
{
Mat caliperImage = image.Clone();
caliperImage = caliperImage.CvtColor(ColorConversionCodes.BGR2GRAY);
if (fromBlackToWhite)
{
caliperImage = caliperImage.Threshold(0, 255, ThresholdTypes.BinaryInv | ThresholdTypes.Otsu);
}
else
{
caliperImage = caliperImage.Threshold(0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
}
Point[] edgePoints = caliper.FindEdgePoints(caliperImage);
foreach (Point edgePoint in edgePoints)
{
cannyPoints.Add(edgePoint);
}
});
// 拟合圆心
Point[] cannyArray = cannyPoints.ToArray();
CircleInfo circleInfo = new CircleInfo();
if (cannyArray.Length >= 3)
{
circleInfo.Center = Cv2.MinEnclosingCircle(cannyArray).Center;
circleInfo.Radius = (int)Math.Round(circleInfo.Center.DistanceTo(center));
}
else
{
circleInfo.Center = new Point(-1, -1);
circleInfo.Radius = -1;
}
return circleInfo;
}
}
public class Caliper
{
public Point Start { get; set; }
public Point End { get; set; }
public int Width { get; set; }
public int Length { get; set; }
public Caliper(Point start, Point end, int width, int length)
{
Start = start;
End = end;
Width = width;
Length = length;
}
public Point[] FindEdgePoints(Mat image)
{
int x1 = Start.X;
int y1 = Start.Y;
int x2 = End.X;
int y2 = End.Y;
double dx = x2 - x1;
double dy = y2 - y1;
double length = Math.Sqrt(dx * dx + dy * dy);
double ux = dx / length;
double uy = dy / length;
Point[] edgePoints = new Point[Length];
for (int i = 0; i < Length; i++)
{
int x = (int)Math.Round(x1 + i * ux);
int y = (int)Math.Round(y1 + i * uy);
int halfWidth = Width / 2;
int minX = x - halfWidth;
int maxX = x + halfWidth;
int minY = y - halfWidth;
int maxY = y + halfWidth;
if (minX < 0 || maxX >= image.Width || minY < 0 || maxY >= image.Height)
{
edgePoints[i] = new Point(-1, -1);
continue;
}
Mat roi = image[new Rect(minX, minY, Width, Width)];
double gradient = GetGradient(roi);
edgePoints[i] = new Point(x, y) + new Point((int)Math.Round(gradient * uy), (int)Math.Round(-gradient * ux));
}
return edgePoints;
}
private double GetGradient(Mat roi)
{
int width = roi.Width;
int height = roi.Height;
byte[] data = new byte[width * height];
Marshal.Copy(roi.Data, data, 0, data.Length);
double[] gradientValues = new double[data.Length - width];
for (int i = 0; i < height - 1; i++)
{
for (int j = 0; j < width; j++)
{
int index1 = i * width + j;
int index2 = (i + 1) * width + j;
gradientValues[index1] = Math.Abs(data[index1] - data[index2]);
}
}
return gradientValues.Average();
}
}
public class CircleInfo
{
public Point Center { get; set; }
public int Radius { get; set; }
}
```
这个函数接收的参数包括:
- `image`:输入图像。
- `minRadius`:找圆扇形区域的最小半径。
- `maxRadius`:找圆扇形区域的最大半径。
- `center`:找圆扇形中心点。
- `startAngle`:设定扇形区域起始角度。
- `endAngle`:扇形区域结束角度。
- `caliperCount`:输入 Caliper 个数。
- `caliperWidth`:Caliper 宽度。
- `caliperLength`:Caliper 长度。
- `fromInsideToOutside`:是否从内到外找圆心。
- `fromBlackToWhite`:是否从黑到白找圆。
- `cannyThreshold1`:Canny 边缘检测的第一个阈值。
- `cannyThreshold2`:Canny 边缘检测的第二个阈值。
函数返回的是一个 `CircleInfo` 对象,其中包含圆的中心点和半径。
阅读全文