|
@@ -0,0 +1,449 @@
|
|
|
|
|
+using MvCameraControl;
|
|
|
|
|
+using MvvmScaffoldFrame48.DLL.LogTools;
|
|
|
|
|
+using MvvmScaffoldFrame48.DLL.ThreadManager;
|
|
|
|
|
+using MvvmScaffoldFrame48.Model.StorageModel.ImageAlgorithm.ShuLI;
|
|
|
|
|
+using System;
|
|
|
|
|
+using System.Collections.Generic;
|
|
|
|
|
+using System.Diagnostics;
|
|
|
|
|
+using System.Drawing;
|
|
|
|
|
+using System.Linq;
|
|
|
|
|
+using System.Text;
|
|
|
|
|
+using System.Threading;
|
|
|
|
|
+using System.Threading.Tasks;
|
|
|
|
|
+
|
|
|
|
|
+namespace MvvmScaffoldFrame48.DLL.ImageAlgorithm
|
|
|
|
|
+{
|
|
|
|
|
+ public class ProcessingAlgorithm_CCDShuLi : IImageProcessingAlgorithmHikVision
|
|
|
|
|
+ {
|
|
|
|
|
+ private List<ActiveObjectClassModel> activeObjects = new List<ActiveObjectClassModel>(); // 当前跟踪中的物体
|
|
|
|
|
+ private List<ActiveObjectClassModel> lostObjects = new List<ActiveObjectClassModel>();
|
|
|
|
|
+ private List<ActiveObjectClassModel> historyActiveObjects = new List<ActiveObjectClassModel>(); // 历史物体
|
|
|
|
|
+ BoundRectangleClass BoundRectangle = new BoundRectangleClass();
|
|
|
|
|
+ private long currentLine = 0; //行数记录
|
|
|
|
|
+ private int ObjectNum = 0;
|
|
|
|
|
+ private int ChannelWidth = 0;//每个区域的宽度
|
|
|
|
|
+ private ShuLiConfigClassModel shuLiConfig = new ShuLiConfigClassModel();
|
|
|
|
|
+ public List<int> ChannelsRoi { get { return _ChannelsRoi; } }
|
|
|
|
|
+ private List<int> _ChannelsRoi = new List<int>();
|
|
|
|
|
+ private bool IsPrintLightOnError = false;
|
|
|
|
|
+ public string AlgorithmName => "ProcessingAlgorithm_CCDShuLi";
|
|
|
|
|
+
|
|
|
|
|
+ public void Configure(string parameters)
|
|
|
|
|
+ {
|
|
|
|
|
+ throw new NotImplementedException();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public object GetParameters()
|
|
|
|
|
+ {
|
|
|
|
|
+ throw new NotImplementedException();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public string GetSaveJson()
|
|
|
|
|
+ {
|
|
|
|
|
+ throw new NotImplementedException();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public object ProcessImage(IImage imageData, int cameraId)
|
|
|
|
|
+ {
|
|
|
|
|
+ bool result = ProcessImageSequence(imageData, out List<ActiveObjectClassModel> resultValue);
|
|
|
|
|
+ if (result)
|
|
|
|
|
+ {
|
|
|
|
|
+ return resultValue;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// 处理图像序列的主入口
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ /// <param name="image">图像像素数据</param>
|
|
|
|
|
+ /// <param name="ImageWidth">图像宽</param>
|
|
|
|
|
+ /// <param name="currentLine">当前行数</param>
|
|
|
|
|
+ /// <returns>检测到的物体总数</returns>
|
|
|
|
|
+ public bool ProcessImageSequence(IImage image,out List<ActiveObjectClassModel> resultValue)
|
|
|
|
|
+ {
|
|
|
|
|
+ bool result = false;
|
|
|
|
|
+ for (int i = 0; i < image.Height; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ ProcessLine(image, i);
|
|
|
|
|
+ currentLine += 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ //识别到结果并输出
|
|
|
|
|
+ // 清理超时未更新的物体
|
|
|
|
|
+ lostObjects = activeObjects
|
|
|
|
|
+ .Where(o => (currentLine - o.LastSeenLine) > shuLiConfig.MAX_GAP || (o.LastSeenLine - o.StartLine) > shuLiConfig.MAX_Idetify_Height)
|
|
|
|
|
+ .ToList();
|
|
|
|
|
+
|
|
|
|
|
+ resultValue = new List<ActiveObjectClassModel>();
|
|
|
|
|
+
|
|
|
|
|
+ // 有物体转变为活跃物体,返回值转为true
|
|
|
|
|
+ if (lostObjects.Count > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ foreach (var item in lostObjects)
|
|
|
|
|
+ {
|
|
|
|
|
+ //噪点判定
|
|
|
|
|
+ if (item.Area < shuLiConfig.NoiseFilter_Threshold)
|
|
|
|
|
+ {
|
|
|
|
|
+ item.StateCode = 9;
|
|
|
|
|
+ //LOG.log(string.Format("噪点过滤,噪点面积:{0}", item.Area), 6);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ //转为历史物体,添加缺少的参数
|
|
|
|
|
+ item.Num = Interlocked.Increment(ref ObjectNum) + 1;
|
|
|
|
|
+ //item.ChannelNO = ActiveChannel(item);
|
|
|
|
|
+ item.EndCheckTime = DateTime.Now;
|
|
|
|
|
+ item.MaxLength = GetActionMaxLength(item.RowsData);
|
|
|
|
|
+ if ((item.LastSeenLine - item.StartLine) > shuLiConfig.MAX_Idetify_Height)
|
|
|
|
|
+ {
|
|
|
|
|
+ item.StateCode = 7;
|
|
|
|
|
+ //FaultLog.RecordLogMessage("ShuLiClass-ProcessLine:非颗粒,视野异常", 3);
|
|
|
|
|
+ TxtLog.log(string.Format("ShuLiClass-ProcessLine:非颗粒,视野异常"), 6);
|
|
|
|
|
+ //Console.WriteLine("ShuLiClass-ProcessLine:非颗粒,视野异常");
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (shuLiConfig.PandingCode != -1)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (item.StateCode != -1)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (item.StateCode == 8)
|
|
|
|
|
+ {
|
|
|
|
|
+ TxtLog.log(string.Format("颗粒编号{0}:疑似叠片或缺损", item.Num));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (item.Area < shuLiConfig.MinArea
|
|
|
|
|
+ && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 1))
|
|
|
|
|
+ {
|
|
|
|
|
+ item.StateCode = 5;
|
|
|
|
|
+ TxtLog.log(string.Format("颗粒编号{0}:面积过小", item.Num));
|
|
|
|
|
+ Console.WriteLine("颗粒编号{0}:面积过小", item.Num);
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (item.Area > shuLiConfig.MaxArea
|
|
|
|
|
+ && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 1))
|
|
|
|
|
+ {
|
|
|
|
|
+ item.StateCode = 6;
|
|
|
|
|
+ TxtLog.log(string.Format("颗粒编号{0}:面积过大", item.Num));
|
|
|
|
|
+ Console.WriteLine("颗粒编号{0}:面积过大", item.Num);
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (item.MaxLength < shuLiConfig.MIN_Object_LENGTH
|
|
|
|
|
+ && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
|
|
|
|
|
+ {
|
|
|
|
|
+ item.StateCode = 2;
|
|
|
|
|
+ TxtLog.log(string.Format("颗粒编号{0}:超短粒", item.Num));
|
|
|
|
|
+ Console.WriteLine("颗粒编号{0}:超短粒", item.Num);
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (item.MaxLength > shuLiConfig.MAX_Object_LENGTH
|
|
|
|
|
+ && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
|
|
|
|
|
+ {
|
|
|
|
|
+ item.StateCode = 1;
|
|
|
|
|
+ TxtLog.log(string.Format("颗粒编号{0}:超长粒", item.Num));
|
|
|
|
|
+ Console.WriteLine("颗粒编号{0}:超长粒", item.Num);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ item.StateCode = 0;
|
|
|
|
|
+ TxtLog.log(string.Format("颗粒编号{0}:正常粒", item.Num));
|
|
|
|
|
+ Console.WriteLine("颗粒编号{0}:正常粒", item.Num);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ resultValue.Add(item);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (resultValue.Count > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ result = true;
|
|
|
|
|
+ //LOG.log(string.Format("识别完成,首个颗粒编号:{0},颗粒数量:{1}", OneActive[0].Num, OneActive.Count), 6);
|
|
|
|
|
+ //触发回调事件
|
|
|
|
|
+ //Task.Run(() =>
|
|
|
|
|
+ //{
|
|
|
|
|
+ // OnWorkCompleted(OneActive);
|
|
|
|
|
+ //});
|
|
|
|
|
+ //ThreadPool.QueueUserWorkItem(_ => OnWorkCompleted(OneActive));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ resultValue.Clear();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 累加到总数并从活跃物体转移到历史物体
|
|
|
|
|
+ resultValue.ForEach(o => TryAdd(historyActiveObjects, o, 2500));
|
|
|
|
|
+ //lostObjects.Where(o => o.StateCode != 7 && o.StateCode != 9).ToList().ForEach(o => TryAdd(historyActiveObjects, o, 2500));
|
|
|
|
|
+ lostObjects.ForEach(o => activeObjects.Remove(o));
|
|
|
|
|
+
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// 处理单行像素数据
|
|
|
|
|
+ /// 返回值为false的时候无活跃物体转变为历史物体
|
|
|
|
|
+ /// 返回值为true的时候有活跃物体转变为历史物体
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ /// <param name="image">当前行像素数组</param>
|
|
|
|
|
+ private bool ProcessLine(IImage imagedata, int RowNo)
|
|
|
|
|
+ {
|
|
|
|
|
+ Stopwatch stopwatch = Stopwatch.StartNew();
|
|
|
|
|
+ bool result = false;
|
|
|
|
|
+ // 步骤1:检测当前行的有效区域
|
|
|
|
|
+ var currentRegions = FindValidRegions(imagedata, RowNo);
|
|
|
|
|
+
|
|
|
|
|
+ if (currentRegions.Count == 1)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (currentRegions[0].End - (currentRegions[0]).Start + 1 == imagedata.Width)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!IsPrintLightOnError)
|
|
|
|
|
+ {
|
|
|
|
|
+ //FaultLog.RecordLogMessage("当前行有效区域为整行,检查视野和光源", 5);
|
|
|
|
|
+ IsPrintLightOnError = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ IsPrintLightOnError = false;
|
|
|
|
|
+ stopwatch.Stop();
|
|
|
|
|
+ if (stopwatch.ElapsedMilliseconds > 1)
|
|
|
|
|
+ {
|
|
|
|
|
+ //FaultLog.RecordErrorMessage($"ShuLiClass-ProcessLine:图像连通域检测超时,此次识别耗时:{stopwatch.Elapsed}");
|
|
|
|
|
+ }
|
|
|
|
|
+ stopwatch.Restart();
|
|
|
|
|
+ //lock (_lockObj)
|
|
|
|
|
+ //{
|
|
|
|
|
+ foreach (var region in currentRegions)
|
|
|
|
|
+ {
|
|
|
|
|
+ // 查找全部可合并的活跃物体(有重叠+在允许间隔内)
|
|
|
|
|
+ var matcheds = activeObjects.Where(o =>
|
|
|
|
|
+ IsOverlapping(o, region) &&
|
|
|
|
|
+ (currentLine - o.LastSeenLine - 1) <= shuLiConfig.MAX_GAP).ToList();
|
|
|
|
|
+ //当有多个可合并的活跃物体时,将多个物体合并
|
|
|
|
|
+ if (matcheds.Count >= 2)
|
|
|
|
|
+ {
|
|
|
|
|
+ // 合并有效区域队列
|
|
|
|
|
+ var CopeRowsData = new List<RowStartEndColModel>();
|
|
|
|
|
+ matcheds.ForEach(o => CopeRowsData = CopeRowsData.Concat(o.RowsData).ToList());
|
|
|
|
|
+ // 合并有效区域并保存在新的区域中
|
|
|
|
|
+ var MergeMatched = new ActiveObjectClassModel
|
|
|
|
|
+ {
|
|
|
|
|
+ MinStartCol = matcheds.Min(o => o.MinStartCol),
|
|
|
|
|
+ MaxEndCol = matcheds.Max(o => o.MaxEndCol),
|
|
|
|
|
+ StartLine = matcheds.Min(o => o.StartLine),
|
|
|
|
|
+ LastSeenLine = matcheds.Max(o => o.LastSeenLine),
|
|
|
|
|
+ LastSeenLineStartCol = matcheds.Min(o => o.LastSeenLineStartCol),
|
|
|
|
|
+ LastSeenLineEndCol = matcheds.Max(o => o.LastSeenLineEndCol),
|
|
|
|
|
+ StartCheckTime = matcheds.Min(o => o.StartCheckTime),
|
|
|
|
|
+ EndCheckTime = matcheds.Max(o => o.EndCheckTime),
|
|
|
|
|
+ Area = matcheds.Sum(o => o.Area),
|
|
|
|
|
+ RowsData = CopeRowsData,
|
|
|
|
|
+ ImageWidth = matcheds.FirstOrDefault().ImageWidth,
|
|
|
|
|
+ //StateCode = 8
|
|
|
|
|
+ };
|
|
|
|
|
+ // 从活跃区域中删除被合并的区域
|
|
|
|
|
+ matcheds.ForEach(o => activeObjects.Remove(o));
|
|
|
|
|
+ // 保存新的区域到活跃区域中
|
|
|
|
|
+ activeObjects.Add(MergeMatched);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 搜获可用且可合并的活跃区域
|
|
|
|
|
+ var matched = activeObjects.FirstOrDefault(o =>
|
|
|
|
|
+ IsOverlapping(o, region) &&
|
|
|
|
|
+ (currentLine - o.LastSeenLine - 1) <= shuLiConfig.MAX_GAP);
|
|
|
|
|
+ if (matched != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ // 合并区域:扩展物体边界并更新状态
|
|
|
|
|
+ matched.MinStartCol = Math.Min(matched.MinStartCol, region.Start);
|
|
|
|
|
+ matched.MaxEndCol = Math.Max(matched.MaxEndCol, region.End);
|
|
|
|
|
+ matched.Area += region.End - region.Start + 1;
|
|
|
|
|
+ matched.LastSeenLine = currentLine;
|
|
|
|
|
+ matched.RowsData.Add(new RowStartEndColModel
|
|
|
|
|
+ {
|
|
|
|
|
+ StartCol = region.Start,
|
|
|
|
|
+ EndCol = region.End,
|
|
|
|
|
+ RowsCol = currentLine,
|
|
|
|
|
+ });
|
|
|
|
|
+ matched.LastSeenLineStartCol = region.Start;
|
|
|
|
|
+ matched.LastSeenLineEndCol = region.End;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // 创建新物体(首次出现的区域)
|
|
|
|
|
+ activeObjects.Add(new ActiveObjectClassModel
|
|
|
|
|
+ {
|
|
|
|
|
+ MinStartCol = region.Start,
|
|
|
|
|
+ MaxEndCol = region.End,
|
|
|
|
|
+ StartLine = currentLine,
|
|
|
|
|
+ LastSeenLine = currentLine,
|
|
|
|
|
+ LastSeenLineStartCol = region.Start,
|
|
|
|
|
+ LastSeenLineEndCol = region.End,
|
|
|
|
|
+ StartCheckTime = DateTime.Now,
|
|
|
|
|
+ Area = region.End - region.Start + 1,
|
|
|
|
|
+ ImageWidth = shuLiConfig.ImageWidth,
|
|
|
|
|
+ RowsData = new List<RowStartEndColModel> {
|
|
|
|
|
+ new RowStartEndColModel {
|
|
|
|
|
+ StartCol = region.Start,
|
|
|
|
|
+ EndCol = region.End,
|
|
|
|
|
+ RowsCol = currentLine,
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ //}
|
|
|
|
|
+ stopwatch.Stop();
|
|
|
|
|
+ if (stopwatch.ElapsedMilliseconds > 1)
|
|
|
|
|
+ {
|
|
|
|
|
+ //FaultLog.RecordErrorMessage($"ShuLiClass-ProcessLine:图像区域合并超时,此次识别耗时:{stopwatch.Elapsed}");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ currentRegions.Clear();
|
|
|
|
|
+
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+ List<ValidRegionModel> regions = new List<ValidRegionModel>();
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// 检测有效物体区域(横向连续黑色像素段)
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ /// <param name="line">当前行像素数组</param>
|
|
|
|
|
+ /// <returns>有效区域列表(起始/结束位置)</returns>
|
|
|
|
|
+ private List<ValidRegionModel> FindValidRegions(IImage image, int RowNo)
|
|
|
|
|
+ {
|
|
|
|
|
+ regions.Clear();
|
|
|
|
|
+ int start = -1; // 当前区域起始标记
|
|
|
|
|
+ int end = -1;
|
|
|
|
|
+ // 遍历所有像素列
|
|
|
|
|
+ if (shuLiConfig.IsIdentifyRoiOpen)
|
|
|
|
|
+ {
|
|
|
|
|
+ for (int i = (int)image.Width * RowNo + shuLiConfig.IdentifyStartX; i < (int)image.Width * RowNo + shuLiConfig.IdentifyStopX; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (image.PixelData[i] < shuLiConfig.RegionThreshold) // 发现黑色像素
|
|
|
|
|
+ {
|
|
|
|
|
+ if (start == -1) start = i % (int)image.Width; // 开始新区域
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (start != -1) // 遇到白色像素且存在进行中的区域
|
|
|
|
|
+ {
|
|
|
|
|
+ end = (i - 1) % (int)image.Width;
|
|
|
|
|
+ // 检查区域宽度是否达标
|
|
|
|
|
+ if (end - start >= shuLiConfig.NoiseFilter_Threshold)
|
|
|
|
|
+ {
|
|
|
|
|
+ regions.Add(new ValidRegionModel()
|
|
|
|
|
+ {
|
|
|
|
|
+ Start = start,
|
|
|
|
|
+ End = end
|
|
|
|
|
+ }); // 记录有效区域
|
|
|
|
|
+ }
|
|
|
|
|
+ start = -1; // 重置区域标记
|
|
|
|
|
+ end = -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ for (int i = (int)image.Width * RowNo; i < (int)image.Width * (RowNo + 1); i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (image.PixelData[i] < shuLiConfig.RegionThreshold) // 发现黑色像素
|
|
|
|
|
+ {
|
|
|
|
|
+ if (start == -1) start = i % (int)image.Width; // 开始新区域
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (start != -1) // 遇到白色像素且存在进行中的区域
|
|
|
|
|
+ {
|
|
|
|
|
+ end = (i - 1) % (int)image.Width;
|
|
|
|
|
+ // 检查区域宽度是否达标
|
|
|
|
|
+ if (end - start >= shuLiConfig.NoiseFilter_Threshold)
|
|
|
|
|
+ {
|
|
|
|
|
+ regions.Add(new ValidRegionModel()
|
|
|
|
|
+ {
|
|
|
|
|
+ Start = start,
|
|
|
|
|
+ End = end
|
|
|
|
|
+ }); // 记录有效区域
|
|
|
|
|
+ }
|
|
|
|
|
+ start = -1; // 重置区域标记
|
|
|
|
|
+ end = -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // 处理行尾未闭合的区域
|
|
|
|
|
+ if (start != -1 && image.Width - start >= shuLiConfig.NoiseFilter_Threshold)
|
|
|
|
|
+ {
|
|
|
|
|
+ regions.Add(new ValidRegionModel()
|
|
|
|
|
+ {
|
|
|
|
|
+ Start = start,
|
|
|
|
|
+ End = (int)image.Width - 1
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ return regions;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// 判断区域重叠(与活跃物体的横向坐标重叠检测)
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ /// <param name="obj">活跃物体</param>
|
|
|
|
|
+ /// <param name="region">当前区域</param>
|
|
|
|
|
+ /// <returns>是否发生重叠</returns>
|
|
|
|
|
+ private bool IsOverlapping(ActiveObjectClassModel obj, ValidRegionModel region)
|
|
|
|
|
+ {
|
|
|
|
|
+ // 判断区域是否不相交的逆条件
|
|
|
|
|
+ return !(region.End < obj.LastSeenLineStartCol || region.Start > obj.LastSeenLineEndCol);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private bool TryAdd(List<ActiveObjectClassModel> list, ActiveObjectClassModel item, int maxSize)
|
|
|
|
|
+ {
|
|
|
|
|
+ list.Add(item);
|
|
|
|
|
+ if (list.Count > maxSize)
|
|
|
|
|
+ {
|
|
|
|
|
+ list[list.Count - maxSize].RowsData.Clear();
|
|
|
|
|
+ }
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// 获取结果最长长边
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ /// <param name="Rows"></param>
|
|
|
|
|
+ /// <returns></returns>
|
|
|
|
|
+ private double GetActionMaxLength(List<RowStartEndColModel> Rows)
|
|
|
|
|
+ {
|
|
|
|
|
+ //外轮廓点集
|
|
|
|
|
+ List<Point> points = Rows.Select(o => new Point(o.StartCol, (int)o.RowsCol)).ToList();
|
|
|
|
|
+ points.AddRange(Rows.Select(o => new Point(o.EndCol, (int)o.RowsCol)).ToList());
|
|
|
|
|
+ //获取凸包点集
|
|
|
|
|
+ points = BoundRectangle.ConvexHull(points);
|
|
|
|
|
+ //获取凸包长度最长的外接矩形
|
|
|
|
|
+ var result = BoundRectangle.RotatingCalipers(points);
|
|
|
|
|
+ if (result != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ return result.Height;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// 通道区域判定
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ /// <param name="activeObject"></param>
|
|
|
|
|
+ /// <returns></returns>
|
|
|
|
|
+ private int ActiveChannel(ActiveObjectClassModel activeObject)
|
|
|
|
|
+ {
|
|
|
|
|
+ int result = -1;
|
|
|
|
|
+ int StartChannel = activeObject.MinStartCol / ChannelWidth;
|
|
|
|
|
+ int EndChannel = activeObject.MaxEndCol / ChannelWidth;
|
|
|
|
|
+ if (StartChannel == EndChannel)
|
|
|
|
|
+ {
|
|
|
|
|
+ result = StartChannel;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (EndChannel - StartChannel > 1)
|
|
|
|
|
+ {
|
|
|
|
|
+ Console.WriteLine("ActiveChannel-Error");
|
|
|
|
|
+ //error
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ result = _ChannelsRoi[StartChannel] - activeObject.MinStartCol > activeObject.MaxEndCol - _ChannelsRoi[StartChannel] ? StartChannel : EndChannel;
|
|
|
|
|
+ }
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|