OpenCvSharp 编写CircularCaliper找圆心函数 , 输入图像、找圆扇形区域的最小半径和最大半径、设定扇形区域起始角度、扇形区域结束角度 先剪出找圆扇形区域图像 输入Caliper个数,宽度、长度、 输入从内到外找圆心、从黑到白找圆 并行计算遍历所有刻度线 中心圆可设定请编写函数
时间: 2023-07-31 09:10:11 浏览: 122
以下是一个示例函数,可以用 OpenCvSharp 实现 CircularCaliper 找圆心的功能:
```csharp
using System;
using OpenCvSharp;
public static class CircularCaliper
{
public static Point2f FindCircleCenter(Mat image, float minRadius, float maxRadius, float startAngle, float endAngle, int numCalipers, int caliperWidth, int caliperLength, bool fromInside = true, bool darkToLight = true)
{
// 剪出扇形区域图像
Point2f center = new Point2f(image.Width / 2f, image.Height / 2f);
float radius = (minRadius + maxRadius) / 2f;
float startRadians = startAngle * (float)Math.PI / 180f;
float endRadians = endAngle * (float)Math.PI / 180f;
float halfAngle = (endRadians - startRadians) / 2f;
float startRadians2 = startRadians - halfAngle;
float endRadians2 = endRadians - halfAngle;
Point2f pt1 = new Point2f((float)Math.Cos(startRadians2), (float)Math.Sin(startRadians2)) * radius + center;
Point2f pt2 = new Point2f((float)Math.Cos(endRadians2), (float)Math.Sin(endRadians2)) * radius + center;
Point2f pt3 = new Point2f((float)Math.Cos(endRadians2), (float)Math.Sin(endRadians2)) * maxRadius + center;
Point2f pt4 = new Point2f((float)Math.Cos(startRadians2), (float)Math.Sin(startRadians2)) * maxRadius + center;
using (Mat roiMask = new Mat(image.Size(), MatType.CV_8UC1, Scalar.Black))
{
Point[] roiPoints = new Point[] { pt1, pt2, pt3, pt4 }.ToRectPolygon();
roiMask.FillPoly(new Point[][] { roiPoints }, Scalar.White);
Mat roiImage = new Mat(image.Size(), image.Type(), Scalar.Black);
image.CopyTo(roiImage, roiMask);
image = roiImage;
}
// 计算刻度线位置
float stepAngle = (endAngle - startAngle) / (numCalipers - 1);
float startAngle2 = startAngle - halfAngle;
float endAngle2 = endAngle - halfAngle;
Point2f[] caliperPoints = new Point2f[numCalipers * 2];
for (int i = 0; i < numCalipers; i++)
{
float angle = startAngle2 + stepAngle * i;
Point2f pt = new Point2f((float)Math.Cos(angle), (float)Math.Sin(angle)) * radius + center;
Point2f pt2 = pt + new Point2f((float)Math.Cos(angle + (float)Math.PI / 2f), (float)Math.Sin(angle + (float)Math.PI / 2f)) * caliperWidth;
Point2f pt3 = pt + new Point2f((float)Math.Cos(angle), (float)Math.Sin(angle)) * caliperLength * 2f;
caliperPoints[i * 2] = pt2;
caliperPoints[i * 2 + 1] = pt3;
}
// 遍历刻度线计算得分
float bestScore = float.MaxValue;
Point2f bestCenter = new Point2f(-1f, -1f);
for (float x = 0f; x < image.Width; x += 1f)
{
for (float y = 0f; y < image.Height; y += 1f)
{
Point2f pt = new Point2f(x, y);
float score = CalculateScore(image, pt, caliperPoints, fromInside, darkToLight);
if (score < bestScore)
{
bestScore = score;
bestCenter = pt;
}
}
}
return bestCenter;
}
private static float CalculateScore(Mat image, Point2f center, Point2f[] caliperPoints, bool fromInside, bool darkToLight)
{
float score = 0f;
for (int i = 0; i < caliperPoints.Length / 2; i++)
{
Point2f pt1 = caliperPoints[i * 2];
Point2f pt2 = caliperPoints[i * 2 + 1];
float distance = (pt1 - pt2).Length();
Point2f direction = (pt1 - pt2).Normalized();
Point2f pt3 = center + direction * distance * (fromInside ? -1f : 1f);
LineSegmentPoint line = new LineSegmentPoint(pt1.ToPoint(), pt2.ToPoint());
float value1 = GetValue(image, pt1, pt2, darkToLight);
float value2 = GetValue(image, pt3, pt3 + direction, darkToLight);
float diff = Math.Abs(value1 - value2);
float weight = distance;
score += diff * weight;
}
return score;
}
private static float GetValue(Mat image, Point2f pt1, Point2f pt2, bool darkToLight)
{
float value = 0f;
LineSegmentPoint line = new LineSegmentPoint(pt1.ToPoint(), pt2.ToPoint());
foreach (Point pt in line.GetPoints())
{
if (pt.X >= 0 && pt.X < image.Width && pt.Y >= 0 && pt.Y < image.Height)
{
value += image.At<byte>(pt.Y, pt.X);
}
}
value /= line.Length;
return darkToLight ? (255f - value) : value;
}
}
```
这个函数的输入参数包括:
- image:输入图像。
- minRadius:找圆的最小半径。
- maxRadius:找圆的最大半径。
- startAngle:扇形区域的起始角度。
- endAngle:扇形区域的结束角度。
- numCalipers:刻度线数量。
- caliperWidth:刻度线宽度。
- caliperLength:刻度线长度。
- fromInside:是否从内到外找圆心。
- darkToLight:是否从黑到白找圆心。
输出为找到的圆心的坐标。
阅读全文