using CCDCount.MODEL.ConfigModel;
using CCDCount.MODEL.ShuLiClass;
using LogClass;
using MvCameraControl;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
namespace CCDCount.DLL
{
public class ShuLiClass
{
#region 变量
///
/// 当活跃物体转变为历史物体时的回调事件
///
public event EventHandler WorkCompleted;
private List activeObjects = new List(); // 当前跟踪中的物体
private List historyActiveObjects = new List(); // 历史物体
private ConcurrentQueue ImageBytes = new ConcurrentQueue(); //图像数据队列
private ConcurrentQueue IFrameDatas = new ConcurrentQueue(); //图像数据队列
private Thread IdentifyImageProcessThread = null; // 识别线程
private bool IsIdentify = false; //线程是否开始识别的标志
private long currentLine = 0; //行数记录
private ShuLiConfigClass shuLiConfig = null;// 数粒参数配置文件
private List ChannelsRoi = new List();
private int ChannelWidth = 0;//每个区域的宽度
private int IdentifyImageWidth = -1;
private static readonly object _lockObj = new object(); // 专用锁对象\
private int ObjectNum = 0;
public int ImageNum { get { return IFrameDatas.Count; } }
#endregion
#region 公共方法
///
/// 初始化构造方法
///
public ShuLiClass()
{
// 加载默认参数
shuLiConfig = new ShuLiConfigClass()
{
Channel = 8,
PandingCode = 2
};
}
public ShuLiClass(ShuLiConfigClass config)
{
if(config.IsLoadCanfig)
{
// 加载传出的参数
shuLiConfig = config;
}
else
{
// 加载默认参数
shuLiConfig = new ShuLiConfigClass()
{
Channel = 8,
PandingCode = 2
};
}
}
///
/// 处理图像序列的主入口
///
/// 图像像素数据
/// 图像宽
/// 当前行数
/// 检测到的物体总数
public bool ProcessImageSequence(byte[] image, int ImageWidth)
{
bool result = false;
// 每张图像是Width*1的二维数组,判断图象分辨率是否正确
if (image.Count() == ImageWidth)
result = ProcessLine(image);
currentLine += 1;
return result;
}
///
/// 处理图像序列的主入口
///
/// 图像像素数据
/// 图像宽
/// 当前行数
/// 检测到的物体总数
public bool ProcessImageSequence(IFrameOut image)
{
bool result = false;
for (int i = 0;i
/// 返回最后一个历史物品
///
///
public ActiveObjectClass GetLastActive()
{
if (historyActiveObjects.Count() == 0)
return null;
return historyActiveObjects.Last();
}
///
/// 返回历史物品
///
///
public List GetHistoryActive()
{
lock (_lockObj) // 加锁
{
return historyActiveObjects.ToList();
}
}
///
/// 返回缓存在内存的历史物品的总数量
///
///
public int GetHistoryActiveNum()
{
lock (_lockObj) // 加锁
return historyActiveObjects.Count();
}
///
/// 清除缓存的内存的中的历史数据
///
public void ClearHistoryActive()
{
historyActiveObjects.Clear();
}
///
/// 获取历史数据中,正常数据数量
///
///
public int GetOkHistoryNum()
{
lock (_lockObj)
return historyActiveObjects.Where(o=>o.StateCode == 0).Count();
}
///
/// 获取历史数据中,异常数据数量
///
///
public int GetNgHistoryNum()
{
lock (_lockObj)
return historyActiveObjects.Where(o=>o.StateCode != 0).Count();
}
///
/// 开启识别
///
public void StartIdentifyFuntion(int ImaageWidth)
{
UpdateIdentifyImageWidth(ImaageWidth);
InitChannel();
try
{
// 标志位置位true
IsIdentify = true;
// 打开识别线程
IdentifyImageProcessThread = new Thread(IdentifyImageProcess)
{
Priority = ThreadPriority.Highest
};
IdentifyImageProcessThread.Start();
}
catch (Exception ex)
{
LOG.error("Start thread failed!, " + ex.Message);
throw;
}
}
///
/// 关闭识别
///
public void StopIdentifyFuntion()
{
try
{
// 标志位设为false
IsIdentify = false;
if(IdentifyImageProcessThread!=null&& IdentifyImageProcessThread.IsAlive)
IdentifyImageProcessThread.Join();
}
catch (Exception ex)
{
LOG.error("Stop thread failed!, " + ex.Message);
throw;
}
}
///
/// 向识别队列添加一个数据
///
///
public void SetOnceIdentifyImageData(byte[] items)
{
ImageBytes.Enqueue(items.Clone() as byte[]);
}
///
/// 向识别队列添加一个数据
///
///
public void SetOnceIdentifyImageData(IFrameOut items)
{
IFrameDatas.Enqueue(items.Clone() as IFrameOut);
}
///
/// 保存参数
///
public void SaveConfig()
{
if(!Directory.Exists(".\\Config\\")) Directory.CreateDirectory(".\\Config\\");
XmlStorage.SerializeToXml(shuLiConfig, ".\\Config\\ShuLiConfig.xml");
}
///
/// 更新检测宽度信息
///
///
public void UpdateIdentifyImageWidth(int Width)
{
IdentifyImageWidth = Width;
}
///
/// 初始化通道划分
///
///
public void InitChannel()
{
shuLiConfig.ImageWidth = IdentifyImageWidth;
if (shuLiConfig.Channel > 0)
{
if (shuLiConfig.IsIdentifyRoiOpen)
{
ChannelWidth = (shuLiConfig.IdentifyStopX - shuLiConfig.IdentifyStartX) / shuLiConfig.Channel;
}
else
{
ChannelWidth = shuLiConfig.ImageWidth / shuLiConfig.Channel;
}
for (int i = 0; i < shuLiConfig.Channel; i++)
{
ChannelsRoi.Add(ChannelWidth + i * ChannelWidth);
}
}
}
///
/// 获取配置信息
///
///
public ShuLiConfigClass GetConfigValue()
{
ShuLiConfigClass result = shuLiConfig;
return result;
}
#endregion
#region 私有方法
///
/// 对外通知事件
///
private void OnWorkCompleted(List activeObject)
{
ActiveObjectEventArgsClass activeObjectEventArgs = new ActiveObjectEventArgsClass(activeObject);
// 触发事件
WorkCompleted?.Invoke(this, activeObjectEventArgs);
}
///
/// 处理单行像素数据
/// 返回值为false的时候无活跃物体转变为历史物体
/// 返回值为true的时候有活跃物体转变为历史物体
///
/// 当前行像素数组
private bool ProcessLine(byte[] image)
{
bool result = false;
// 步骤1:检测当前行的有效区域
var currentRegions = FindValidRegions(image);
if (currentRegions.Count == 1)
{
if (currentRegions[0].End - (currentRegions[0]).Start + 1 == image.Count())
{
LOG.error("当前行有效区域为整行,检查视野和光源");
return false;
}
}
// 步骤2:处理当前行每个区域
for (int i = 0; i < currentRegions.Count; i++)
{
var region = currentRegions[i];
// 查找全部可合并的活跃物体(有重叠+在允许间隔内)
var matcheds = activeObjects.Where(o =>
IsOverlapping(o, region) &&
(currentLine - o.LastSeenLine - 1) <= shuLiConfig.MAX_GAP).ToList();
//当有多个可合并的活跃物体时,将多个物体合并
if (matcheds.Count >= 2)
{
// 合并有效区域队列
var CopeRowsData = new List();
matcheds.ForEach(o => CopeRowsData = CopeRowsData.Concat(o.RowsData).ToList());
// 合并有效区域并保存在新的区域中
var MergeMatched = new ActiveObjectClass
{
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,
};
// 从活跃区域中删除被合并的区域
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 RowStartEndCol
{
StartCol = region.Start,
EndCol = region.End,
RowsCol = currentLine,
});
}
else
{
// 创建新物体(首次出现的区域)
activeObjects.Add(new ActiveObjectClass
{
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 = IdentifyImageWidth,
RowsData = new List {
new RowStartEndCol {
StartCol = region.Start,
EndCol = region.End,
RowsCol = currentLine,
}
}
});
}
}
// 更新有效物体的最后一行的起始点
activeObjects.Where(o => o.LastSeenLine == currentLine).ToList().ForEach(o => o.LastSeenLineStartCol = o.RowsData.Where(p => p.RowsCol == currentLine).Min(p => p.StartCol));
activeObjects.Where(o => o.LastSeenLine == currentLine).ToList().ForEach(o => o.LastSeenLineEndCol = o.RowsData.Where(p => p.RowsCol == currentLine).Max(p => p.EndCol));
// 步骤3:清理超时未更新的物体
var lostObjects = activeObjects
.Where(o => (currentLine - o.LastSeenLine) > shuLiConfig.MAX_GAP|| (o.LastSeenLine - o.StartLine) > shuLiConfig.MAX_Idetify_Height)
.ToList();
List OneActive = new List();
// 有物体转变为活跃物体,返回值转为true
if (lostObjects.Count()>0)
{
result = true;
foreach (var item in lostObjects)
{
//噪点判定
if(item.LastSeenLine - item.StartLine o.EndCol - o.StartCol)< shuLiConfig.NoiseFilter_Threshold)
continue;
//转为历史物体,添加缺少的参数
item.Num = ObjectNum += 1;
item.ChannelNO = ActiveChannel(item);
item.EndCheckTime = DateTime.Now;
OneActive.Add(item);
if((item.LastSeenLine - item.StartLine) > shuLiConfig.MAX_Idetify_Height)
{
item.StateCode = 7;
LOG.error("ShuLiClass-ProcessLine:非颗粒,视野异常");
Console.WriteLine("ShuLiClass-ProcessLine:非颗粒,视野异常");
}
else if (shuLiConfig.PandingCode != -1)
{
if (item.Area < shuLiConfig.MinArea
&& (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 1))
{
item.StateCode = 5;
LOG.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;
LOG.log(string.Format("颗粒编号{0}:面积过大", item.Num));
Console.WriteLine("颗粒编号{0}:面积过大", item.Num);
}
else if (item.LastSeenLine - item.StartLine < shuLiConfig.MIN_OBJECT_HEIGHT
&& (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
{
item.StateCode = 2;
LOG.log(string.Format("颗粒编号{0}:超短粒", item.Num));
Console.WriteLine("颗粒编号{0}:超短粒", item.Num);
}
else if (item.LastSeenLine - item.StartLine > shuLiConfig.MAX_OBJECT_HEIGHT
&& (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
{
item.StateCode = 1;
LOG.log(string.Format("颗粒编号{0}:超长粒", item.Num));
Console.WriteLine("颗粒编号{0}:超长粒", item.Num);
}
else if (item.RowsData.Max(o => o.EndCol - o.StartCol) > shuLiConfig.MAX_OBJECT_WIDTH
&& (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
{
item.StateCode = 3;
LOG.log(string.Format("颗粒编号{0}:超宽粒", item.Num));
Console.WriteLine("颗粒编号{0}:超宽粒", item.Num);
}
else if (item.RowsData.Max(o => o.EndCol - o.StartCol) < shuLiConfig.MIN_OBJECT_WIDTH
&& (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
{
item.StateCode = 4;
LOG.log(string.Format("颗粒编号{0}:超窄粒", item.Num));
Console.WriteLine("颗粒编号{0}:超窄粒", item.Num);
}
else
{
item.StateCode = 0;
LOG.log(string.Format("颗粒编号{0}:正常粒", item.Num));
Console.WriteLine("颗粒编号{0}:正常粒", item.Num);
}
}
}
if(OneActive.Count>0)
//触发回调事件
OnWorkCompleted(OneActive);
}
else
{
OneActive = null;
}
lock(_lockObj)
{
// 累加到总数并从活跃物体转移到历史物体
lostObjects.Where(o => o.LastSeenLine - o.StartLine >= shuLiConfig.NoiseFilter_Threshold).ToList().ForEach(o => historyActiveObjects.Add(o));
lostObjects.ForEach(o => activeObjects.Remove(o));
}
return result;
}
///
/// 处理单行像素数据
/// 返回值为false的时候无活跃物体转变为历史物体
/// 返回值为true的时候有活跃物体转变为历史物体
///
/// 当前行像素数组
private bool ProcessLine(IImage imagedata,int RowNo)
{
bool result = false;
// 步骤1:检测当前行的有效区域
var currentRegions = FindValidRegions(imagedata,RowNo);
if (currentRegions.Count == 1)
{
if (currentRegions[0].End - (currentRegions[0]).Start + 1 == imagedata.Width)
{
LOG.error("当前行有效区域为整行,检查视野和光源");
return false;
}
}
// 步骤2:处理当前行每个区域
for (int i = 0; i < currentRegions.Count; i++)
{
var region = currentRegions[i];
// 查找全部可合并的活跃物体(有重叠+在允许间隔内)
var matcheds = activeObjects.Where(o =>
IsOverlapping(o, region) &&
(currentLine - o.LastSeenLine - 1) <= shuLiConfig.MAX_GAP).ToList();
//当有多个可合并的活跃物体时,将多个物体合并
if (matcheds.Count >= 2)
{
// 合并有效区域队列
var CopeRowsData = new List();
matcheds.ForEach(o => CopeRowsData = CopeRowsData.Concat(o.RowsData).ToList());
// 合并有效区域并保存在新的区域中
var MergeMatched = new ActiveObjectClass
{
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,
};
// 从活跃区域中删除被合并的区域
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 RowStartEndCol
{
StartCol = region.Start,
EndCol = region.End,
RowsCol = currentLine,
});
}
else
{
// 创建新物体(首次出现的区域)
activeObjects.Add(new ActiveObjectClass
{
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 = IdentifyImageWidth,
RowsData = new List {
new RowStartEndCol {
StartCol = region.Start,
EndCol = region.End,
RowsCol = currentLine,
}
}
});
}
}
currentRegions.Clear();
// 更新有效物体的最后一行的起始点
activeObjects.Where(o => o.LastSeenLine == currentLine).ToList().ForEach(o => o.LastSeenLineStartCol = o.RowsData.Where(p => p.RowsCol == currentLine).Min(p => p.StartCol));
activeObjects.Where(o => o.LastSeenLine == currentLine).ToList().ForEach(o => o.LastSeenLineEndCol = o.RowsData.Where(p => p.RowsCol == currentLine).Max(p => p.EndCol));
// 步骤3:清理超时未更新的物体
var lostObjects = activeObjects
.Where(o => (currentLine - o.LastSeenLine) > shuLiConfig.MAX_GAP || (o.LastSeenLine - o.StartLine) > shuLiConfig.MAX_Idetify_Height)
.ToList();
List OneActive = new List();
// 有物体转变为活跃物体,返回值转为true
if (lostObjects.Count() > 0)
{
result = true;
foreach (var item in lostObjects)
{
//噪点判定
if (item.LastSeenLine - item.StartLine < shuLiConfig.NoiseFilter_Threshold ||
item.RowsData.Max(o => o.EndCol - o.StartCol) < shuLiConfig.NoiseFilter_Threshold)
continue;
//转为历史物体,添加缺少的参数
item.Num = ObjectNum += 1;
item.ChannelNO = ActiveChannel(item);
item.EndCheckTime = DateTime.Now;
OneActive.Add(item);
if ((item.LastSeenLine - item.StartLine) > shuLiConfig.MAX_Idetify_Height)
{
item.StateCode = 7;
LOG.error("ShuLiClass-ProcessLine:非颗粒,视野异常");
Console.WriteLine("ShuLiClass-ProcessLine:非颗粒,视野异常");
}
else if (shuLiConfig.PandingCode != -1)
{
if (item.Area < shuLiConfig.MinArea
&& (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 1))
{
item.StateCode = 5;
LOG.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;
LOG.log(string.Format("颗粒编号{0}:面积过大", item.Num));
Console.WriteLine("颗粒编号{0}:面积过大", item.Num);
}
else if (item.LastSeenLine - item.StartLine < shuLiConfig.MIN_OBJECT_HEIGHT
&& (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
{
item.StateCode = 2;
LOG.log(string.Format("颗粒编号{0}:超短粒", item.Num));
Console.WriteLine("颗粒编号{0}:超短粒", item.Num);
}
else if (item.LastSeenLine - item.StartLine > shuLiConfig.MAX_OBJECT_HEIGHT
&& (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
{
item.StateCode = 1;
LOG.log(string.Format("颗粒编号{0}:超长粒", item.Num));
Console.WriteLine("颗粒编号{0}:超长粒", item.Num);
}
else if (item.RowsData.Max(o => o.EndCol - o.StartCol) > shuLiConfig.MAX_OBJECT_WIDTH
&& (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
{
item.StateCode = 3;
LOG.log(string.Format("颗粒编号{0}:超宽粒", item.Num));
Console.WriteLine("颗粒编号{0}:超宽粒", item.Num);
}
else if (item.RowsData.Max(o => o.EndCol - o.StartCol) < shuLiConfig.MIN_OBJECT_WIDTH
&& (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
{
item.StateCode = 4;
LOG.log(string.Format("颗粒编号{0}:超窄粒", item.Num));
Console.WriteLine("颗粒编号{0}:超窄粒", item.Num);
}
else
{
item.StateCode = 0;
LOG.log(string.Format("颗粒编号{0}:正常粒", item.Num));
Console.WriteLine("颗粒编号{0}:正常粒", item.Num);
}
}
}
if (OneActive.Count > 0)
//触发回调事件
OnWorkCompleted(OneActive);
}
else
{
OneActive = null;
}
lock (_lockObj)
{
// 累加到总数并从活跃物体转移到历史物体
lostObjects.Where(o => o.LastSeenLine - o.StartLine >= shuLiConfig.NoiseFilter_Threshold && o.StateCode != 7).ToList().ForEach(o => historyActiveObjects.Add(o));
lostObjects.ForEach(o => activeObjects.Remove(o));
lostObjects.ForEach(o => historyActiveObjects.Where(P => P.Num == o.Num - 100).ToList().ForEach(P => P.RowsData.Clear()));
}
return result;
}
///
/// 检测有效物体区域(横向连续黑色像素段)
///
/// 当前行像素数组
/// 有效区域列表(起始/结束位置)
private List<(int Start, int End)> FindValidRegions(byte[] image)
{
List<(int Start, int End)> regions = new List<(int Start, int End)>();
int start = -1; // 当前区域起始标记
// 遍历所有像素列
if (shuLiConfig.IsIdentifyRoiOpen)
{
for (int i = shuLiConfig.IdentifyStartX; i < shuLiConfig.IdentifyStopX; i++)
{
if (image[i] < shuLiConfig.RegionThreshold) // 发现黑色像素
{
if (start == -1) start = i; // 开始新区域
}
else if (start != -1) // 遇到白色像素且存在进行中的区域
{
// 检查区域宽度是否达标
if (i - start >= shuLiConfig.MIN_OBJECT_WIDTH)
{
regions.Add((start, i - 1)); // 记录有效区域
}
start = -1; // 重置区域标记
}
}
}
else
{
for (int i = 0; i < image.Length; i++)
{
if (image[i] < shuLiConfig.RegionThreshold) // 发现黑色像素
{
if (start == -1) start = i; // 开始新区域
}
else if (start != -1) // 遇到白色像素且存在进行中的区域
{
// 检查区域宽度是否达标
if (i - start >= shuLiConfig.MIN_OBJECT_WIDTH)
{
regions.Add((start, i - 1)); // 记录有效区域
}
start = -1; // 重置区域标记
}
}
}
// 处理行尾未闭合的区域
if (start != -1 && image.Length - start >= shuLiConfig.MIN_OBJECT_WIDTH)
{
regions.Add((start, image.Length - 1));
}
return regions;
}
///
/// 检测有效物体区域(横向连续黑色像素段)
///
/// 当前行像素数组
/// 有效区域列表(起始/结束位置)
private List<(int Start, int End)> FindValidRegions(IImage image,int RowNo)
{
List<(int Start, int End)> regions = new List<(int Start, int End)>();
int start = -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) // 遇到白色像素且存在进行中的区域
{
// 检查区域宽度是否达标
if (i - start >= shuLiConfig.MIN_OBJECT_WIDTH)
{
regions.Add((start, (i - 1)% (int)image.Width)); // 记录有效区域
}
start = -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) // 遇到白色像素且存在进行中的区域
{
// 检查区域宽度是否达标
if (i - start >= shuLiConfig.MIN_OBJECT_WIDTH)
{
regions.Add((start, (i - 1) % (int)image.Width)); // 记录有效区域
}
start = -1; // 重置区域标记
}
}
}
// 处理行尾未闭合的区域
if (start != -1 && image.Width - start >= shuLiConfig.MIN_OBJECT_WIDTH)
{
regions.Add((start, (int)image.Width - 1));
}
return regions;
}
///
/// 判断区域重叠(与活跃物体的横向坐标重叠检测)
///
/// 活跃物体
/// 当前区域
/// 是否发生重叠
private bool IsOverlapping(ActiveObjectClass obj, (int Start, int End) region)
{
// 判断区域是否不相交的逆条件
return !(region.End < obj.LastSeenLineStartCol || region.Start > obj.LastSeenLineEndCol);
}
///
/// 通道区域判定
///
///
///
private int ActiveChannel(ActiveObjectClass 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;
}
#endregion
#region 线程方法
///
/// 识别图像线程
///
private void IdentifyImageProcess()
{
//Stopwatch stopwatch = Stopwatch.StartNew();
IFrameOut IframeData = null;
while (IsIdentify)
{
//判断队列中是否有数据
if (IFrameDatas.Count() > 0)
{
//stopwatch.Restart();
IFrameDatas.TryDequeue(out IframeData);
//是否成功取得数据
if (IframeData != null)
{
//识别
ProcessImageSequence(IframeData);
}
else
{
Console.WriteLine("识别数据为空");
continue;
}
//输出耗时
//stopwatch.Stop();
///Console.WriteLine("识别线程单次运行耗时:" + stopwatch.Elapsed.ToString());
}
else
{
Thread.Sleep(1);
}
}
}
///
/// 线程方法 - 旧线程方法
///
//private void IdentifyImageProcess()
//{
// //Stopwatch stopwatch = Stopwatch.StartNew();
// byte[] ImageByte = null;
// while (IsIdentify)
// {
// //判断队列中是否有数据
// if (ImageBytes.Count() > 0)
// {
// //stopwatch.Restart();
// ImageBytes.TryDequeue(out ImageByte);
// //是否成功取得数据
// if (ImageByte != null)
// {
// //识别
// ProcessImageSequence(ImageByte, IdentifyImageWidth);
// }
// else
// {
// Console.WriteLine("识别数据为空");
// continue;
// }
// //输出耗时
// //stopwatch.Stop();
// ///Console.WriteLine("识别线程单次运行耗时:" + stopwatch.Elapsed.ToString());
// }
// else
// {
// Thread.Sleep(5);
// }
// }
//}
#endregion
}
}