解决 float point division by zero

本文详细介绍了如何在程序创建阶段通过设置8087协处理器寄存器来解决浮点除零错误的问题,并提供了实用的代码实现。此方法对于避免程序运行时出现不可预见的崩溃至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//解决 float point division by zero

在formcreate 中添加

  Set8087CW(Default8087CW or $0004);

private List<Mask> DrawSegmentationOnYoloCanvas(SKBitmap bitmap, List<Segmentation> results) { List<Mask> maskList = new List<Mask>(); // 生成新的SKImage var newImage = SKImage.FromBitmap(bitmap); // 创建一个新的 Bitmap 来绘制所有轮廓 using (var surface = SKSurface.Create(new SKImageInfo(bitmap.Width, bitmap.Height))) { var canvas = surface.Canvas; // 绘制 newImage 到画布 canvas.DrawImage(newImage, new SKRect(0, 0, bitmap.Width, bitmap.Height)); // 设置画笔 using (var paint = new SKPaint()) { paint.Style = SKPaintStyle.Stroke; paint.StrokeWidth = 1; // 遍历所有结果并绘制轮廓 foreach (var result in results) { Pixel[] pixels = result.SegmentedPixels; // 创建一个与原图相同大小的透明图层 Mat overlay = new Mat(new OpenCvSharp.Size(bitmap.Width, bitmap.Height), MatType.CV_8UC4, Scalar.All(0)); // 在透明图层上绘制掩码 foreach (var pixel in pixels) { paint.Color = new SKColor(1, 1, 1, 66); // 绘制每个像素的轮廓到 SkiaSharp 的 canvas canvas.DrawPoint(pixel.X, pixel.Y, paint); overlay.Circle(new OpenCvSharp.Point(pixel.X, pixel.Y), 1, new Scalar(0, 0, 255, 127), -1); } // 用梯度算法计算梯度 Mat laplacian = overlay.CvtColor(ColorConversionCodes.BGRA2GRAY).Laplacian(overlay.Type(), 1, 5).ConvertScaleAbs(); // 从梯度图查找轮廓 var contours = laplacian.FindContoursAsArray(RetrievalModes.External, ContourApproximationModes.ApproxSimple); laplacian.Dispose(); // 最小外接矩形的宽度和高度和最大内接圆的半径 float width = 0; float height = 0; float rectWidth = 0; float rectHeight = 0; float radius = 0; RotatedRect minRect = new RotatedRect(); SKPoint centerMask = new SKPoint(0, 0); // 画最大内接圆和最小外接矩形 if (contours.Length > 0) { // 计算最小外接矩形 minRect = Cv2.MinAreaRect(contours[0]); // 绘制外接矩形到 SkiaSharp 的 canvas Point2f[] rectPoints = minRect.Points(); foreach (var point in rectPoints) { paint.Color = SKColors.Red; // 绘制矩形的边界 canvas.DrawLine(point.X, point.Y, rectPoints[(Array.IndexOf(rectPoints, point) + 1) % 4].X, rectPoints[(Array.IndexOf(rectPoints, point) + 1) % 4].Y, paint); } // 获取矩形的宽度和高度 width = minRect.Size.Width; height = minRect.Size.Height; // 如果宽度大于高度,交换值以确保 width 是较小的边,height 是较大的边 if (width > height) { float temp = width; width = height; height = temp; } if (null != skglControlColor.Tag) { // 从画布 Tag 属性中取出深度相机数据帧 var skgData = skglControlColor.Tag as SkgData; if (skgData != null) { // 获取深度数据值 var point0 = pxToImgMatrix.MapPoint(new SKPoint(rectPoints[0].X, rectPoints[0].Y)); int depthValue0 = GetDepthValueAtXY(skgData, (int)point0.X, (int)point0.Y); var point1 = pxToImgMatrix.MapPoint(new SKPoint(rectPoints[1].X, rectPoints[1].Y)); int depthValue1 = GetDepthValueAtXY(skgData, (int)point1.X, (int)point1.Y); var point2 = pxToImgMatrix.MapPoint(new SKPoint(rectPoints[2].X, rectPoints[2].Y)); int depthValue2 = GetDepthValueAtXY(skgData, (int)point2.X, (int)point2.Y); double widthD = CalculateDistance(point0, depthValue0, point1, depthValue1); double heightD = CalculateDistance(point1, depthValue1, point2, depthValue2); // 判断小的值为w,大的值为h if (widthD < heightD) { rectWidth = (float)widthD; rectHeight = (float)heightD; } else { rectWidth = (float)heightD; rectHeight = (float)widthD; } } else { LogError("深度数据为空,无法计算掩码的长宽。"); } } // 计算轮廓的质心(几何中心) Moments moments = Cv2.Moments(contours[0]); OpenCvSharp.Point2f center = new OpenCvSharp.Point2f( (float)(moments.M10 / moments.M00), (float)(moments.M01 / moments.M00) ); // 计算最大内接圆的半径 float minDistance = float.MaxValue; foreach (var point in contours[0]) { // 确保 pointPoint2f 类型 OpenCvSharp.Point2f contourPoint = new OpenCvSharp.Point2f(point.X, point.Y); // 手动计算点到质心的距离 float distance = (float)Math.Sqrt(Math.Pow(contourPoint.X - center.X, 2) + Math.Pow(contourPoint.Y - center.Y, 2)); if (distance < minDistance) { minDistance = distance; } } // 限制最大内接圆的半径,确保圆完全位于最小外接矩形内 float maxRadius = width / 2; minDistance = Math.Min(minDistance, maxRadius); // 绘制最大内接圆到 SkiaSharp 的 canvas paint.Color = SKColors.LightBlue; canvas.DrawCircle(center.X, center.Y, minDistance, paint); if (null != skglControlColor.Tag) { // 从画布 Tag 属性中取出深度相机数据帧 var skgData = skglControlColor.Tag as SkgData; if (skgData != null) { // 和外接矩形同理,计算圆的半径 var pointCenter = pxToImgMatrix.MapPoint(new SKPoint(center.X, center.Y)); int depthValueCenter = GetDepthValueAtXY(skgData, (int)pointCenter.X, (int)pointCenter.Y); // 算一个圆心正上方的一个圆上坐标 var pointC = pxToImgMatrix.MapPoint(new SKPoint(center.X, center.Y + minDistance)); int depthValueC = GetDepthValueAtXY(skgData, (int)pointC.X, (int)pointC.Y); // 计算圆的半径 radius = (float)CalculateDistance(pointCenter, depthValueCenter, pointC, depthValueC); } else { LogError("深度数据为空,无法计算掩码的圆半径。"); } } // 在圆心处画上 分数result.Confidence paint.Color = SKColors.Blue; canvas.DrawText($"{result.Confidence * 100 :F0}", center.X + 5, center.Y - 5, paint); centerMask = new SKPoint(center.X, center.Y); } // 画掩码轮廓 if (contours.Length > 0) { // 绘制轮廓边缘 foreach (var contour in contours) { // 创建一个完整的封闭轮廓 OpenCvSharp.Point[] contourAll = new OpenCvSharp.Point[contour.Length + 1]; // 遍历轮廓点并添加到 contourAll for (int i = 0; i < contour.Length; i++) { contourAll[i] = new OpenCvSharp.Point(contour[i].X, contour[i].Y); } // 闭合轮廓,添加最后一个点到第一个点的连接 contourAll[contour.Length] = new OpenCvSharp.Point(contour[0].X, contour[0].Y); // 绘制封闭轮廓 paint.Color = SKColors.LightGray; for (int i = 0; i < contourAll.Length - 1; i++) { canvas.DrawLine(new SKPoint(contourAll[i].X, contourAll[i].Y), new SKPoint(contourAll[i + 1].X, contourAll[i + 1].Y), paint); } RotatedRect maxInscribedRect = GetMaxInscribedRectangle(contourAll); //绘制最大内接矩形 Point2f[] maxRectPoints = maxInscribedRect.Points(); for (int j = 0; j < 4; j++) { paint.Color = SKColors.Yellow; canvas.DrawLine( maxRectPoints[j].X, maxRectPoints[j].Y, maxRectPoints[(j + 1) % 4].X, maxRectPoints[(j + 1) % 4].Y, paint ); } } } // 获取圆心,判断圆半径是否满足14mm以上的要求 吸嘴的圆半径是14mm if (radius > fixedTempRadius) { // 创建一个新的Mask对象 var mask = new Mask { Name = result.Label.Name, Iou = result.Confidence, Cx = centerMask.X, Cy = centerMask.Y, X = 0, Y = 0, Area = 0, Deep = 0, // 深度信息可以根据需要设置 MaskImage = null, // 可以根据需要生成对应的Mask图像 BoxArea = 0, RectCenterX = 0, RectCenterY = 0, RectWidth = rectWidth, RectHeight = rectHeight, RectAngle = 0, RectPoints = null }; var (widthRatio, heightRatio) = GetMaskAspectRatios(mask, fixedTemplateWidth, fixedTemplateHeight); // 判断尺寸范围是否在预设范围内 if (widthRatio >= ratioMin && widthRatio <= ratioMax && heightRatio >= ratioMin && heightRatio <= ratioMax) { maskList.Add(mask); } else { // 在圆心画一个“x” paint.Color = SKColors.Red; canvas.DrawLine(centerMask.X - 5, centerMask.Y - 5, centerMask.X + 5, centerMask.Y + 5, paint); canvas.DrawLine(centerMask.X - 5, centerMask.Y + 5, centerMask.X + 5, centerMask.Y - 5, paint); } } else { // 在圆心画一个“x” paint.Color = SKColors.Red; canvas.DrawLine(centerMask.X - 5, centerMask.Y - 5, centerMask.X + 5, centerMask.Y + 5, paint); canvas.DrawLine(centerMask.X - 5, centerMask.Y + 5, centerMask.X + 5, centerMask.Y - 5, paint); } } } // 获取绘制后的图像作为 SKImage var outlinedImage = surface.Snapshot(); newImage = outlinedImage; } // 绘制检测框和置信度 var resultImage = newImage.Draw(results); // 生成一个完整的画面,置入到skglControlYolo的Tag中,调用Invalidate()方法来刷新画面 skglControlYolo.Tag = newImage; skglControlYolo.Invalidate(); return maskList; } // 使用中心扩散法获取最大内接矩形 public RotatedRect GetMaxInscribedRectangle(OpenCvSharp.Point[] contour) { // 获取轮廓的最小外接矩形 RotatedRect minRect = Cv2.MinAreaRect(contour); // 初始化最大内接矩形 RotatedRect maxInscribedRect = minRect; // 获取最小外接矩形的中心点、角度和尺寸 Point2f center = minRect.Center; float angle = minRect.Angle; Size2f size = minRect.Size; // 确保最长边是 height,最短边是 width float width = Math.Min(size.Width, size.Height); float height = Math.Max(size.Width, size.Height); // 检查宽边(最短边)的两个角点是否都在轮廓内 Point2f leftEdge = RotatePoint(new Point2f(center.X - width / 2, center.Y), center, angle); Point2f rightEdge = RotatePoint(new Point2f(center.X + width / 2, center.Y), center, angle); bool isWidthFixed = Cv2.PointPolygonTest(contour, leftEdge, false) >= 0 && Cv2.PointPolygonTest(contour, rightEdge, false) >= 0; // 检查长边(最长边)的两个角点是否都在轮廓内 Point2f topEdge = RotatePoint(new Point2f(center.X, center.Y - height / 2), center, angle); Point2f bottomEdge = RotatePoint(new Point2f(center.X, center.Y + height / 2), center, angle); bool isHeightFixed = Cv2.PointPolygonTest(contour, topEdge, false) >= 0 && Cv2.PointPolygonTest(contour, bottomEdge, false) >= 0; // 如果宽边不固定,调整宽度 if (!isWidthFixed) { while (true) { leftEdge = RotatePoint(new Point2f(center.X - width / 2, center.Y), center, angle); rightEdge = RotatePoint(new Point2f(center.X + width / 2, center.Y), center, angle); if (Cv2.PointPolygonTest(contour, leftEdge, false) >= 0 && Cv2.PointPolygonTest(contour, rightEdge, false) >= 0) { break; // 宽边已经在轮廓内 } // 如果不在轮廓内,缩小宽度 width -= 0.5f; if (width <= 0) break; // 防止宽度变为负数 } } // 如果长边不固定,调整高度 if (!isHeightFixed) { while (true) { topEdge = RotatePoint(new Point2f(center.X, center.Y - height / 2), center, angle); bottomEdge = RotatePoint(new Point2f(center.X, center.Y + height / 2), center, angle); if (Cv2.PointPolygonTest(contour, topEdge, false) >= 0 && Cv2.PointPolygonTest(contour, bottomEdge, false) >= 0) { break; // 长边已经在轮廓内 } // 如果不在轮廓内,缩小高度 height -= 0.5f; if (height <= 0) break; // 防止高度变为负数 } } // 返回最大内接矩形 return new RotatedRect(center, new Size2f(width, height), angle); } 在我的代码中,我绘制了一个最小外接矩形,然后基于给出的点绘制出轮廓, paint.Color = SKColors.LightGray; for (int i = 0; i < contourAll.Length - 1; i++) { canvas.DrawLine(new SKPoint(contourAll[i].X, contourAll[i].Y), new SKPoint(contourAll[i + 1].X, contourAll[i + 1].Y), paint); } 这个是我轮廓的代码。我想要获得这个轮廓的最大内接矩形。 RotatedRect maxInscribedRect = GetMaxInscribedRectangle(contourAll); //绘制最大内接矩形 Point2f[] maxRectPoints = maxInscribedRect.Points(); for (int j = 0; j < 4; j++) { paint.Color = SKColors.Yellow; canvas.DrawLine( maxRectPoints[j].X, maxRectPoints[j].Y, maxRectPoints[(j + 1) % 4].X, maxRectPoints[(j + 1) % 4].Y, paint ); }。但是我的代码中我绘制了这个最大内接矩形,效果不是很好。请你帮我查阅资料帮我修改,我看到网上很多使用python已经实现了,你帮我转成C#写入我的代码,像什么凸包什么的,或者你遍历每一个角度都可以。要保证是轮廓的最大内接矩形,然后就是分割出来的图形不论是什么角度都可以获得正确的最大内接矩形
07-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值