|
|
@@ -421,8 +421,8 @@ namespace CCDCount.DLL
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
- IsPrintLightOnError = false;
|
|
|
}
|
|
|
+ IsPrintLightOnError = false;
|
|
|
lock (_lockObj)
|
|
|
{
|
|
|
foreach (var region in currentRegions)
|
|
|
@@ -519,6 +519,7 @@ namespace CCDCount.DLL
|
|
|
{
|
|
|
List<ValidRegionModelClass> regions = new List<ValidRegionModelClass>();
|
|
|
int start = -1; // 当前区域起始标记
|
|
|
+ int end = -1;
|
|
|
// 遍历所有像素列
|
|
|
if (shuLiConfig.IsIdentifyRoiOpen)
|
|
|
{
|
|
|
@@ -530,16 +531,18 @@ namespace CCDCount.DLL
|
|
|
}
|
|
|
else if (start != -1) // 遇到白色像素且存在进行中的区域
|
|
|
{
|
|
|
+ end = (i - 1) % (int)image.Width;
|
|
|
// 检查区域宽度是否达标
|
|
|
- if (i - start >= shuLiConfig.MIN_OBJECT_WIDTH)
|
|
|
+ if (end - start >= shuLiConfig.NoiseFilter_Threshold)
|
|
|
{
|
|
|
regions.Add(new ValidRegionModelClass()
|
|
|
{
|
|
|
Start = start,
|
|
|
- End = (i - 1) % (int)image.Width
|
|
|
+ End = end
|
|
|
}); // 记录有效区域
|
|
|
}
|
|
|
start = -1; // 重置区域标记
|
|
|
+ end = -1;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -553,23 +556,25 @@ namespace CCDCount.DLL
|
|
|
}
|
|
|
else if (start != -1) // 遇到白色像素且存在进行中的区域
|
|
|
{
|
|
|
+ end = (i - 1) % (int)image.Width;
|
|
|
// 检查区域宽度是否达标
|
|
|
- if (i - start >= shuLiConfig.MIN_OBJECT_WIDTH)
|
|
|
+ if (end - start >= shuLiConfig.NoiseFilter_Threshold)
|
|
|
{
|
|
|
regions.Add(new ValidRegionModelClass()
|
|
|
{
|
|
|
Start = start,
|
|
|
- End = (i - 1) % (int)image.Width
|
|
|
+ End = end
|
|
|
}); // 记录有效区域
|
|
|
}
|
|
|
start = -1; // 重置区域标记
|
|
|
+ end = -1;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
// 处理行尾未闭合的区域
|
|
|
- if (start != -1 && image.Width - start >= shuLiConfig.MIN_OBJECT_WIDTH)
|
|
|
+ if (start != -1 && image.Width - start >= shuLiConfig.NoiseFilter_Threshold)
|
|
|
{
|
|
|
regions.Add(new ValidRegionModelClass()
|
|
|
{
|
|
|
@@ -625,9 +630,20 @@ namespace CCDCount.DLL
|
|
|
/// <returns></returns>
|
|
|
private double GetActionMaxLength(List<RowStartEndCol> Rows)
|
|
|
{
|
|
|
+ //Stopwatch stopwatch = Stopwatch.StartNew();
|
|
|
List<Point> points = ConvexHull(Rows);
|
|
|
- return RotatingCalipers(points);
|
|
|
-
|
|
|
+ //stopwatch.Stop();
|
|
|
+ //Console.WriteLine($"凸包计算耗时:{stopwatch.Elapsed}");
|
|
|
+ //var test = CalculateMinimumBoundingRectangle(points);
|
|
|
+ var result = RotatingCalipers(points);
|
|
|
+ if (result!= null)
|
|
|
+ {
|
|
|
+ return result.Height;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -668,8 +684,9 @@ namespace CCDCount.DLL
|
|
|
/// </summary>
|
|
|
/// <param name="hull"></param>
|
|
|
/// <returns></returns>
|
|
|
- private double RotatingCalipers(List<Point> hull)
|
|
|
+ private BoundingRectangleMdoel RotatingCalipers(List<Point> hull)
|
|
|
{
|
|
|
+ /* 老方法注释
|
|
|
int n = hull.Count;
|
|
|
if (n == 1) return 0;
|
|
|
if (n == 2) return Distance(hull[0], hull[1]);
|
|
|
@@ -690,8 +707,160 @@ namespace CCDCount.DLL
|
|
|
}
|
|
|
|
|
|
return maxDist;
|
|
|
+ */
|
|
|
+
|
|
|
+ BoundingRectangleMdoel result = null;
|
|
|
+ int n = hull.Count;
|
|
|
+ if (n == 1)
|
|
|
+ {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ if (n == 2)
|
|
|
+ {
|
|
|
+ result = new BoundingRectangleMdoel
|
|
|
+ {
|
|
|
+ points = hull,
|
|
|
+ CenterPoint = new Point() { X = (hull[1].X + hull[0].X) / 2, Y = (hull[1].Y + hull[0].Y) / 2 },
|
|
|
+ Width = 0,
|
|
|
+ Height = Distance(hull[0], hull[1]),
|
|
|
+ Angle = Math.Atan2(hull[1].Y - hull[0].Y, hull[1].X - hull[0].X)
|
|
|
+ };
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ double maxDist = 0;
|
|
|
+ int pointIndex1 = 0;
|
|
|
+ int pointIndex2 = 0;
|
|
|
+
|
|
|
+ for (int i = 0; i < n; i++)
|
|
|
+ {
|
|
|
+ for (int j = i + 1; j < n; j++)
|
|
|
+ {
|
|
|
+ if (Distance(hull[i], hull[j]) > maxDist)
|
|
|
+ {
|
|
|
+ maxDist = Distance(hull[i], hull[j]);
|
|
|
+ pointIndex1 = i;
|
|
|
+ pointIndex2 = j;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ double angle = Math.Atan2(hull[pointIndex2].Y - hull[pointIndex1].Y, hull[pointIndex2].X - hull[pointIndex2].X);
|
|
|
+ var rotatedPoints = hull.Select(p => RotatePoint(p, -angle)).ToList();
|
|
|
+ // 找到包围盒
|
|
|
+ int minX = rotatedPoints.Min(p => p.X);
|
|
|
+ int maxX = rotatedPoints.Max(p => p.X);
|
|
|
+ int minY = rotatedPoints.Min(p => p.Y);
|
|
|
+ int maxY = rotatedPoints.Max(p => p.Y);
|
|
|
+ int centerX = (minX + maxX) / 2;
|
|
|
+ int centerY = (minY + maxY) / 2;
|
|
|
+
|
|
|
+ int height = maxX - minX;
|
|
|
+ int width = maxY - minY;
|
|
|
+
|
|
|
+ // 构造矩形的四个顶点并旋转回原来的角度
|
|
|
+ var rectangle = new List<Point>
|
|
|
+ {
|
|
|
+ RotatePoint(new Point(minX, minY), angle),
|
|
|
+ RotatePoint(new Point(maxX, minY), angle),
|
|
|
+ RotatePoint(new Point(maxX, maxY), angle),
|
|
|
+ RotatePoint(new Point(minX, maxY), angle)
|
|
|
+ };
|
|
|
+
|
|
|
+ result = new BoundingRectangleMdoel
|
|
|
+ {
|
|
|
+ points = rectangle,
|
|
|
+ CenterPoint = RotatePoint(new Point() { X = centerX, Y = centerY }, angle),
|
|
|
+ Width = width,
|
|
|
+ Height = height,
|
|
|
+ Angle = angle
|
|
|
+ };
|
|
|
+
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// 计算凸包的最小外接矩形
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="convexHull">凸包顶点列表(按逆时针顺序排列)</param>
|
|
|
+ /// <returns>最小外接矩形的四个顶点</returns>
|
|
|
+ public List<Point> CalculateMinimumBoundingRectangle(List<Point> convexHull)
|
|
|
+ {
|
|
|
+ if (convexHull == null || convexHull.Count < 3)
|
|
|
+ return null;
|
|
|
+
|
|
|
+ double minArea = double.MaxValue;
|
|
|
+ List<Point> minRectangle = null;
|
|
|
+
|
|
|
+ int n = convexHull.Count;
|
|
|
+
|
|
|
+ // 遍历每一条边作为基准边
|
|
|
+ for (int i = 0; i < n; i++)
|
|
|
+ {
|
|
|
+ Point edgeStart = convexHull[i];
|
|
|
+ Point edgeEnd = convexHull[(i + 1) % n];
|
|
|
+
|
|
|
+ // 计算当前边的角度
|
|
|
+ double angle = Math.Atan2(edgeEnd.Y - edgeStart.Y, edgeEnd.X - edgeStart.X);
|
|
|
+
|
|
|
+ // 将所有点绕原点旋转-angle角度,使当前边与x轴平行
|
|
|
+ var rotatedPoints = convexHull.Select(p => RotatePoint(p, -angle)).ToList();
|
|
|
+
|
|
|
+ // 找到包围盒
|
|
|
+ int minX = rotatedPoints.Min(p => p.X);
|
|
|
+ int maxX = rotatedPoints.Max(p => p.X);
|
|
|
+ int minY = rotatedPoints.Min(p => p.Y);
|
|
|
+ int maxY = rotatedPoints.Max(p => p.Y);
|
|
|
+
|
|
|
+ // 计算面积
|
|
|
+ double area = (maxX - minX) * (maxY - minY);
|
|
|
+
|
|
|
+ // 如果面积更小,则更新最小矩形
|
|
|
+ if (area < minArea)
|
|
|
+ {
|
|
|
+ minArea = area;
|
|
|
+
|
|
|
+ // 构造矩形的四个顶点并旋转回原来的角度
|
|
|
+ var rectangle = new List<Point>
|
|
|
+ {
|
|
|
+ RotatePoint(new Point(minX, minY), angle),
|
|
|
+ RotatePoint(new Point(maxX, minY), angle),
|
|
|
+ RotatePoint(new Point(maxX, maxY), angle),
|
|
|
+ RotatePoint(new Point(minX, maxY), angle)
|
|
|
+ };
|
|
|
+
|
|
|
+ minRectangle = rectangle;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return minRectangle;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 绕原点旋转点
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="point">待旋转的点</param>
|
|
|
+ /// <param name="angle">旋转角度(弧度)</param>
|
|
|
+ /// <returns>旋转后的点</returns>
|
|
|
+ private static Point RotatePoint(Point point, double angle)
|
|
|
+ {
|
|
|
+ double cos = Math.Cos(angle);
|
|
|
+ double sin = Math.Sin(angle);
|
|
|
+
|
|
|
+ return new Point(
|
|
|
+ (int)(point.X * cos - point.Y * sin),
|
|
|
+ (int)(point.X * sin + point.Y * cos)
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 计算点到线段的距离
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="a">线段点1</param>
|
|
|
+ /// <param name="b">线段点2</param>
|
|
|
+ /// <param name="c">点三</param>
|
|
|
+ /// <returns></returns>
|
|
|
private double DistanceToLine(Point a, Point b, Point c)
|
|
|
{
|
|
|
double area = Math.Abs(Area2(a, b, c));
|
|
|
@@ -732,13 +901,13 @@ namespace CCDCount.DLL
|
|
|
/// </summary>
|
|
|
private void IdentifyImageProcess()
|
|
|
{
|
|
|
- Stopwatch stopwatch = Stopwatch.StartNew();
|
|
|
+ //Stopwatch stopwatch = Stopwatch.StartNew();
|
|
|
while (IsIdentify)
|
|
|
{
|
|
|
//判断队列中是否有数据
|
|
|
if (IFrameDatas.Count() > 0)
|
|
|
{
|
|
|
- stopwatch.Restart();
|
|
|
+ //stopwatch.Restart();
|
|
|
if (IFrameDatas.Count() > 50)
|
|
|
FaultLog.RecordErrorMessage($"图像数据队列中数据过多,请及时处理!当前数据数量为:{IFrameDatas.Count()}");
|
|
|
IFrameDatas.TryDequeue(out IImage IframeData);
|
|
|
@@ -754,8 +923,8 @@ namespace CCDCount.DLL
|
|
|
continue;
|
|
|
}
|
|
|
//输出耗时
|
|
|
- stopwatch.Stop();
|
|
|
- Console.WriteLine($"识别线程识别一张图片耗时:{stopwatch.Elapsed},待识别队列剩余数量{IFrameDatas.Count()}");
|
|
|
+ //stopwatch.Stop();
|
|
|
+ //Console.WriteLine($"识别线程识别一张图片耗时:{stopwatch.Elapsed},待识别队列剩余数量{IFrameDatas.Count()}");
|
|
|
}
|
|
|
else
|
|
|
{
|