OpenCvSharp 编写多线程CircularCaliper找圆心函数 , 输入图像、找圆弧区域的半径、估计圆弧中心点、设定圆弧域起始角度、圆弧区域结束角度 输入Caliper个数,宽度、长度、 将每个Caliper区域按输入圆弧与半径的交点作小矩形的中心剪出小区域图像 将每个Caliper区域roi内从整体图像中复制成小图像来分析以提高速度,得到的点坐标转换到整体大图的坐标系中 输入从内到外找圆心、从黑到白找圆 输入canny参数 并行计Caliper区域,将Caliper区域所有canny点合并,拟合圆心 输出圆中心点out double centerX, out double centerY,out double Radius请编写函数
时间: 2024-02-03 12:12:02 浏览: 84
以下是使用OpenCvSharp编写多线程CircularCaliper找圆心函数的示例代码:
```csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using OpenCvSharp;
public static class CircularCaliper {
public static void FindCircleCenter(Mat image, int radius, Point2f center, double startAngle, double endAngle, int numCalipers, int caliperWidth, int caliperLength, out double centerX, out double centerY, out double Radius, bool insideToOutside = true, bool blackToWhite = true, double cannyThreshold1 = 50, double cannyThreshold2 = 150) {
// Convert the input image to grayscale
Mat grayImage = new Mat();
Cv2.CvtColor(image, grayImage, ColorConversionCodes.BGR2GRAY);
// Create a new image to visualize the results
Mat resultImage = new Mat();
Cv2.CvtColor(grayImage, resultImage, ColorConversionCodes.GRAY2BGR);
// Initialize the output variables
centerX = 0;
centerY = 0;
Radius = 0;
// Calculate the angles for each caliper
double angleStep = (endAngle - startAngle) / (numCalipers - 1);
double[] angles = new double[numCalipers];
for (int i = 0; i < numCalipers; i++) {
angles[i] = startAngle + i * angleStep;
}
// Create a list to hold the points detected by each caliper
List<Point>[] caliperPoints = new List<Point>[numCalipers];
for (int i = 0; i < numCalipers; i++) {
caliperPoints[i] = new List<Point>();
}
// Create a list to hold the ROIs for each caliper
Rect[] caliperROIs = new Rect[numCalipers];
// Create a list to hold the small images for each caliper
Mat[] caliperImages = new Mat[numCalipers];
// Calculate the start and end angles for the circle
double startRadians = startAngle * Math.PI / 180;
double endRadians = endAngle * Math.PI / 180;
// Calculate the x and y coordinates of the circle center
double x = center.X;
double y = center.Y;
// Create a list to hold the tasks for each caliper
List<Task> tasks = new List<Task>();
// Loop through each caliper
for (int i = 0; i < numCalipers; i++) {
// Calculate the start and end points of the caliper
double startX = x + radius * Math.Cos(angles[i] * Math.PI / 180);
double startY = y + radius * Math.Sin(angles[i] * Math.PI / 180);
double endX = startX + caliperLength * Math.Cos(angles[i] * Math.PI / 180);
double endY = startY + caliperLength * Math.Sin(angles[i] * Math.PI / 180);
// Calculate the perpendicular line to the caliper
double perpAngle = angles[i] + 90;
double perpStartX = startX + caliperWidth / 2 * Math.Cos(perpAngle * Math.PI / 180);
double perpStartY = startY + caliperWidth / 2 * Math.Sin(perpAngle * Math.PI / 180);
double perpEndX = endX + caliperWidth / 2 * Math.Cos(perpAngle * Math.PI / 180);
double perpEndY = endY + caliperWidth / 2 * Math.Sin(perpAngle * Math.PI / 180);
// Create a new line segment for the caliper
LineSegmentPoint caliperLine = new LineSegmentPoint(new Point((int)startX, (int)startY), new Point((int)endX, (int)endY));
// Create a new line segment for the perpendicular line
LineSegmentPoint perpLine = new LineSegmentPoint(new Point((int)perpStartX, (int)perpStartY), new Point((int)perpEndX, (int)perpEndY));
// Calculate the intersection points between the two lines
Point[] intersections = caliperLine.Intersect(perpLine);
// Calculate the ROI for the caliper
int roiX = (int)intersections[0].X - caliperWidth / 2;
int roiY = (int)intersections[0].Y - caliperWidth / 2;
int roiWidth = caliperWidth;
int roiHeight = caliperLength + caliperWidth;
Rect roi = new Rect(roiX, roiY, roiWidth, roiHeight);
// Add the ROI to the list
caliperROIs[i] = roi;
// Create a new task to process the caliper
Task task = Task.Factory.StartNew(() => {
// Select the region of interest for the caliper
Mat caliperImage = grayImage[roi];
// Create a new image to visualize the results for the caliper
Mat caliperResult = new Mat();
Cv2.CvtColor(caliperImage, caliperResult, ColorConversionCodes.GRAY2BGR);
// Calculate the Canny edge detector parameters
double cannyThresh1 = cannyThreshold1;
double cannyThresh2 = cannyThreshold2;
// Check if we need to reverse the order of the canny thresholds
if (blackToWhite) {
cannyThresh1 = cannyThreshold2;
cannyThresh2 = cannyThreshold1;
}
// Detect edges in the caliper region
Mat edges = new Mat();
Cv2.Canny(caliperImage, edges, cannyThresh1, cannyThresh2);
// Loop through each pixel in the edges image
for (int y = 0; y < edges.Rows; y++) {
for (int x = 0; x < edges.Cols; x++) {
// Check if the pixel is an edge pixel
if (edges.At<byte>(y, x) != 0) {
// Calculate the coordinates of the pixel in the full image
int globalX = roi.X + x;
int globalY = roi.Y + y;
// Add the point to the list for this caliper
caliperPoints[i].Add(new Point(globalX, globalY));
// Draw a circle at the point in the result image
Cv2.Circle(caliperResult, new Point(x, y), 1, Scalar.Red, -1);
}
}
}
// Add the result for the caliper to the output image
caliperResult.CopyTo(resultImage[roi]);
// Store the small image for this caliper
caliperImages[i] = caliperImage;
});
// Add the task to the list
tasks.Add(task);
}
// Wait for all tasks to complete
Task.WaitAll(tasks.ToArray());
// Merge the points detected by each caliper
List<Point> allPoints = new List<Point>();
for (int i = 0; i < numCalipers; i++) {
allPoints.AddRange(caliperPoints[i]);
}
// Fit a circle to the points
Cv2.MinEnclosingCircle(allPoints, out Point2f circleCenter, out float circleRadius);
// Update the output variables
centerX = circleCenter.X;
centerY = circleCenter.Y;
Radius = circleRadius;
// Draw the circle on the result image
Cv2.Circle(resultImage, new Point((int)centerX, (int)centerY), (int)Radius, Scalar.Green, 2);
// Show the result image
Cv2.ImShow("Result", resultImage);
Cv2.WaitKey();
}
}
```
该函数使用了OpenCvSharp的线段类`LineSegmentPoint`和圆拟合函数`Cv2.MinEnclosingCircle`。
要使用该函数,只需将输入图像、圆弧区域的半径、估计圆弧中心点、设定圆弧域起始角度、圆弧区域结束角度、Caliper个数、宽度、长度、内到外或外到内找圆心、从黑到白或白到黑找圆、以及canny参数作为参数传入即可。函数将在多个线程上并行处理每个Caliper区域,并将结果合并以拟合圆心。输出的圆中心点和半径将保存在输出参数`centerX`、`centerY`和`Radius`中。
阅读全文