OpenCvSharp 编写多线程CircularCaliper找圆心函数 , 输入图像、找圆扇形区域的最小半径和最大半径、找圆扇形中心点、设定扇形区域起始角度、扇形区域结束角度 先剪出找圆扇形区域图像 输入Caliper个数,宽度、长度、 输入从内到外找圆心、从黑到白找圆 输入canny参数 并行计Caliper区域 中心圆可设定请编写函数、
时间: 2023-07-10 07:07:51 浏览: 68
下面是使用OpenCvSharp编写多线程CircularCaliper找圆心函数的示例代码:
```csharp
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
using OpenCvSharp;
namespace CircularCaliper
{
class Program
{
static void Main(string[] args)
{
// 读入输入图像
Mat inputImg = Cv2.ImRead("input.jpg", ImreadModes.GrayScale);
// 找圆心
Point2f center = FindCircleCenter(inputImg, 20, 50, new Point2f(inputImg.Width / 2, inputImg.Height / 2), 0, 360, 10, 30, 0, 0, 100);
// 输出结果
Console.WriteLine("Circle center: ({0}, {1})", center.X, center.Y);
}
static Point2f FindCircleCenter(Mat src, int minRadius, int maxRadius, Point2f center, double startAngle, double endAngle, int numCalipers, int caliperWidth, int caliperLength, int method, int threshold1, int threshold2)
{
// 剪出找圆扇形区域图像
Mat roi = new Mat();
Rect rect = new Rect((int)(center.X - maxRadius), (int)(center.Y - maxRadius), maxRadius * 2, maxRadius * 2);
src.SubMat(rect).CopyTo(roi);
// 并行计算Caliper区域
ConcurrentBag<CaliperResult> results = new ConcurrentBag<CaliperResult>();
Parallel.For(0, numCalipers, i =>
{
double angle = startAngle + (endAngle - startAngle) / (numCalipers - 1) * i;
CaliperResult result = FindCircleCenterInCaliper(roi, minRadius, maxRadius, center, angle, caliperWidth, caliperLength, method, threshold1, threshold2);
results.Add(result);
});
// 找到最优的圆心
Point2f bestCenter = new Point2f(center.X, center.Y);
double bestScore = 0;
foreach (CaliperResult result in results)
{
if (result.Score > bestScore)
{
bestCenter = result.Center;
bestScore = result.Score;
}
}
return bestCenter;
}
static CaliperResult FindCircleCenterInCaliper(Mat roi, int minRadius, int maxRadius, Point2f center, double angle, int caliperWidth, int caliperLength, int method, int threshold1, int threshold2)
{
// 计算Caliper的起始点和结束点
Point2f startPoint = new Point2f(center.X + minRadius * (float)Math.Cos(angle * Math.PI / 180), center.Y + minRadius * (float)Math.Sin(angle * Math.PI / 180));
Point2f endPoint = new Point2f(center.X + maxRadius * (float)Math.Cos(angle * Math.PI / 180), center.Y + maxRadius * (float)Math.Sin(angle * Math.PI / 180));
// 获取Caliper区域图像
Mat caliperRoi = new Mat();
double caliperLengthHalf = caliperLength / 2.0;
if (Math.Abs(startPoint.X - endPoint.X) < 1e-6)
{
// 计算斜率不存在的情况
int caliperX = (int)startPoint.X;
int caliperY1 = (int)(center.Y - caliperLengthHalf);
int caliperY2 = (int)(center.Y + caliperLengthHalf);
if (caliperY1 < 0)
{
caliperY1 = 0;
caliperY2 = (int)caliperLength;
}
else if (caliperY2 > roi.Height - 1)
{
caliperY2 = roi.Height - 1;
caliperY1 = (int)(roi.Height - caliperLength);
}
rect = new Rect(caliperX - caliperWidth / 2, caliperY1, caliperWidth, caliperY2 - caliperY1);
caliperRoi = roi.SubMat(rect);
}
else
{
// 计算斜率存在的情况
double k = (endPoint.Y - startPoint.Y) / (endPoint.X - startPoint.X);
double b = endPoint.Y - k * endPoint.X;
double angleRad = angle * Math.PI / 180;
double cosAngle = Math.Cos(angleRad);
double sinAngle = Math.Sin(angleRad);
Point2f[] points = new Point2f[4];
points[0] = new Point2f((float)(startPoint.X + caliperWidth / 2 * sinAngle), (float)(startPoint.Y - caliperWidth / 2 * cosAngle));
points[1] = new Point2f((float)(startPoint.X - caliperWidth / 2 * sinAngle), (float)(startPoint.Y + caliperWidth / 2 * cosAngle));
points[2] = new Point2f((float)(endPoint.X - caliperWidth / 2 * sinAngle), (float)(endPoint.Y + caliperWidth / 2 * cosAngle));
points[3] = new Point2f((float)(endPoint.X + caliperWidth / 2 * sinAngle), (float)(endPoint.Y - caliperWidth / 2 * cosAngle));
Point2f[] pointsTransformed = new Point2f[4];
for (int i = 0; i < 4; i++)
{
double x = (points[i].Y - b) / k;
double y = k * points[i].X + b;
pointsTransformed[i] = new Point2f((float)x, (float)y);
}
int minX = (int)Math.Min(Math.Min(Math.Min(pointsTransformed[0].X, pointsTransformed[1].X), pointsTransformed[2].X), pointsTransformed[3].X);
int maxX = (int)Math.Max(Math.Max(Math.Max(pointsTransformed[0].X, pointsTransformed[1].X), pointsTransformed[2].X), pointsTransformed[3].X);
int minY = (int)Math.Min(Math.Min(Math.Min(pointsTransformed[0].Y, pointsTransformed[1].Y), pointsTransformed[2].Y), pointsTransformed[3].Y);
int maxY = (int)Math.Max(Math.Max(Math.Max(pointsTransformed[0].Y, pointsTransformed[1].Y), pointsTransformed[2].Y), pointsTransformed[3].Y);
if (minX < 0) minX = 0;
if (maxX > roi.Width - 1) maxX = roi.Width - 1;
if (minY < 0) minY = 0;
if (maxY > roi.Height - 1) maxY = roi.Height - 1;
rect = new Rect(minX, minY, maxX - minX + 1, maxY - minY + 1);
caliperRoi = roi.SubMat(rect);
// 进行边缘检测
if (method == 0)
{
Cv2.Canny(caliperRoi, caliperRoi, threshold1, threshold2);
}
else if (method == 1)
{
Cv2.Sobel(caliperRoi, caliperRoi, MatType.CV_32F, 1, 0);
Cv2.ConvertScaleAbs(caliperRoi, caliperRoi);
Cv2.Threshold(caliperRoi, caliperRoi, threshold1, 255, ThresholdTypes.Binary);
}
}
// 计算圆心
Point2f centerInCaliper = new Point2f(0, 0);
double score = 0;
if (caliperRoi.Rows >= caliperLength)
{
for (int x = 0; x < caliperRoi.Width - caliperWidth; x++)
{
int y1 = 0, y2 = caliperLength - 1;
while (y2 < caliperRoi.Rows - 1)
{
// 计算Caliper区域中心
Point2f centerTemp = new Point2f(x + caliperWidth / 2.0f, (y1 + y2) / 2.0f);
// 计算Caliper区域得分
double scoreTemp = 0;
if (method == 0)
{
for (int y = y1; y <= y2; y++)
{
scoreTemp += caliperRoi.At<byte>(y, x);
}
}
else if (method == 1)
{
for (int y = y1; y <= y2; y++)
{
scoreTemp += caliperRoi.At<byte>(y, x);
}
}
if (scoreTemp > score)
{
centerInCaliper = centerTemp;
score = scoreTemp;
}
// 移动Caliper区域
y1++;
y2++;
}
}
}
// 计算圆心在原图中的位置
Point2f centerInSrc = new Point2f(centerInCaliper.X + rect.X, centerInCaliper.Y + rect.Y);
// 返回结果
return new CaliperResult(centerInSrc, score);
}
class CaliperResult
{
public Point2f Center { get; set; }
public double Score { get; set; }
public CaliperResult(Point2f center, double score)
{
Center = center;
Score = score;
}
}
}
}
```
上述代码中,我们定义了一个 `FindCircleCenter()` 函数和一个 `FindCircleCenterInCaliper()` 函数,前者用于找到整个扇形区域的圆心,后者用于在单个Caliper区域内找到圆心。这两个函数都是多线程的,可以并行计算多个Caliper区域。
在 `FindCircleCenter()` 函数中,我们首先剪出扇形区域的图像,并对每个Caliper区域调用 `FindCircleCenterInCaliper()` 函数进行计算。计算完成后,我们选择得分最高的圆心作为整个扇形区域的圆心。
在 `FindCircleCenterInCaliper()` 函数中,我们首先计算Caliper的起始点和结束点,并获取Caliper区域的图像。如果需要进行边缘检测,则对图像进行处理。然后我们在Caliper区域内移动一个固定大小的滑动窗口,计算每个窗口的得分,并选择得分最高的窗口的中心作为圆心。最后,我们将圆心在Caliper区域中的位置转换为在原图中的位置,并返回结果。
需要说明的是,本代码仅是一个示例,实际应用中还需要根据具体情况进行调整。
阅读全文