OpenCvSharp 编写多线程CircularCaliper找圆心函数 , 输入图像、找圆扇形区域的最小半径和最大半径、找圆扇形中心点、设定扇形区域起始角度、扇形区域结束角度 先剪出找圆扇形区域图像 输入Caliper个数,宽度、长度、 输入从内到外找圆心、从黑到白找圆 输入canny参数 并行计Caliper区域,将Caliper区域所有canny点合并,拟合圆心 输出圆中心点、半径请编写函数
时间: 2023-07-10 22:07:51 浏览: 87
以下是基于OpenCvSharp编写的多线程CircularCaliper找圆心函数的代码:
```
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using OpenCvSharp;
public static class CircularCaliperFinder
{
public static (Point2d center, double radius) FindCircleCenter(Mat image, int minRadius, int maxRadius, Point centerPoint, double startAngle, double endAngle, int caliperCount, int caliperWidth, int caliperLength, bool findFromInside, bool findFromBlackToWhite, double cannyThreshold1, double cannyThreshold2)
{
// 剪出找圆扇形区域图像
Rect roi = new Rect(centerPoint.X - maxRadius, centerPoint.Y - maxRadius, maxRadius * 2, maxRadius * 2);
Mat roiImage = new Mat(image, roi);
// 计算每个Caliper的角度
double caliperAngle = (endAngle - startAngle) / caliperCount;
// 并行计算每个Caliper的结果
List<Task<Circle>> tasks = new List<Task<Circle>>();
for (int i = 0; i < caliperCount; i++)
{
double angle = startAngle + caliperAngle * i;
tasks.Add(Task.Run(() => FindCircleCenterInCaliper(roiImage, minRadius, maxRadius, centerPoint, angle, caliperWidth, caliperLength, findFromInside, findFromBlackToWhite, cannyThreshold1, cannyThreshold2)));
}
Task.WaitAll(tasks.ToArray());
// 合并所有Caliper的结果
List<Point> points = new List<Point>();
foreach (Task<Circle> task in tasks)
{
if (task.Result != null)
{
points.AddRange(task.Result.Points);
}
}
// 拟合圆心
if (points.Count >= 3)
{
Point2f[] pointArray = points.ToArray();
Point2f center;
float radius;
Cv2.MinEnclosingCircle(pointArray, out center, out radius);
return (new Point2d(center.X + roi.X, center.Y + roi.Y), radius);
}
else
{
return (new Point2d(-1, -1), -1);
}
}
private static Circle FindCircleCenterInCaliper(Mat image, int minRadius, int maxRadius, Point centerPoint, double angle, int caliperWidth, int caliperLength, bool findFromInside, bool findFromBlackToWhite, double cannyThreshold1, double cannyThreshold2)
{
double x = centerPoint.X + Math.Cos(angle * Math.PI / 180) * minRadius;
double y = centerPoint.Y + Math.Sin(angle * Math.PI / 180) * minRadius;
Point startPoint = new Point((int)x, (int)y);
x = centerPoint.X + Math.Cos(angle * Math.PI / 180) * maxRadius;
y = centerPoint.Y + Math.Sin(angle * Math.PI / 180) * maxRadius;
Point endPoint = new Point((int)x, (int)y);
// 计算Caliper在图像上的矩形区域
Point2f[] rectPoints = new Point2f[4];
double halfWidth = caliperWidth / 2.0;
double halfLength = caliperLength / 2.0;
rectPoints[0] = new Point2f((float)(startPoint.X + halfWidth * Math.Sin(angle * Math.PI / 180)), (float)(startPoint.Y - halfWidth * Math.Cos(angle * Math.PI / 180)));
rectPoints[1] = new Point2f((float)(startPoint.X - halfWidth * Math.Sin(angle * Math.PI / 180)), (float)(startPoint.Y + halfWidth * Math.Cos(angle * Math.PI / 180)));
rectPoints[2] = new Point2f((float)(endPoint.X - halfWidth * Math.Sin(angle * Math.PI / 180)), (float)(endPoint.Y + halfWidth * Math.Cos(angle * Math.PI / 180)));
rectPoints[3] = new Point2f((float)(endPoint.X + halfWidth * Math.Sin(angle * Math.PI / 180)), (float)(endPoint.Y - halfWidth * Math.Cos(angle * Math.PI / 180)));
RotatedRect rect = Cv2.MinAreaRect(rectPoints);
// 获取Caliper的像素值
Mat caliperImage = new Mat(image, rect.BoundingRect());
Mat grayImage = new Mat();
Cv2.CvtColor(caliperImage, grayImage, ColorConversionCodes.BGR2GRAY);
Mat binaryImage = new Mat();
if (findFromBlackToWhite)
{
Cv2.Threshold(grayImage, binaryImage, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
}
else
{
Cv2.Threshold(grayImage, binaryImage, 255, 255, ThresholdTypes.BinaryInv | ThresholdTypes.Otsu);
}
// 计算Canny边缘
Mat cannyImage = new Mat();
Cv2.Canny(binaryImage, cannyImage, cannyThreshold1, cannyThreshold2);
// 获取所有的Canny点
List<Point> points = new List<Point>();
for (int i = 0; i < cannyImage.Rows; i++)
{
for (int j = 0; j < cannyImage.Cols; j++)
{
if (cannyImage.At<byte>(i, j) == 255)
{
Point point = new Point(j, i);
if (rect.BoundingRect().Contains(point))
{
points.Add(point);
}
}
}
}
// 从所有的Canny点中寻找圆心
if (points.Count >= 3)
{
Point2f[] pointArray = points.ToArray();
Point2f center;
float radius;
Cv2.MinEnclosingCircle(pointArray, out center, out radius);
return new Circle(center, radius, points);
}
else
{
return null;
}
}
}
public class Circle
{
public Point2f Center { get; set; }
public float Radius { get; set; }
public List<Point> Points { get; set; }
public Circle(Point2f center, float radius, List<Point> points)
{
Center = center;
Radius = radius;
Points = points;
}
}
```
这个函数的参数比较多,需要具体解释一下:
* `image`:输入图像。
* `minRadius`:找圆扇形区域的最小半径。
* `maxRadius`:找圆扇形区域的最大半径。
* `centerPoint`:找圆扇形中心点。
* `startAngle`:设定扇形区域起始角度。
* `endAngle`:扇形区域结束角度。
* `caliperCount`:输入Caliper个数。
* `caliperWidth`:每个Caliper的宽度。
* `caliperLength`:每个Caliper的长度。
* `findFromInside`:是否从内到外找圆心。
* `findFromBlackToWhite`:是否从黑到白找圆。
* `cannyThreshold1`:Canny边缘检测参数1。
* `cannyThreshold2`:Canny边缘检测参数2。
这个函数通过并行计算每个Caliper的结果,然后将所有的Canny点合并,最后拟合圆心。返回的结果是圆中心点和半径。如果找不到合适的圆心,则返回(-1, -1)和-1。
阅读全文