Commit c106755d by liulongfei

NDI视图重构

parent 93e93f78
...@@ -11,34 +11,46 @@ namespace VIZ.H2V.Domain ...@@ -11,34 +11,46 @@ namespace VIZ.H2V.Domain
/// </summary> /// </summary>
public enum NDIViewStatus public enum NDIViewStatus
{ {
// --------------------------------------------------------------------
// 启动 & 等待初始化完成
// --------------------------------------------------------------------
/// <summary> /// <summary>
/// 算法停止状态 /// 停止状态
/// </summary> /// </summary>
AlgorithmStop = 0, Stop,
/// <summary> /// <summary>
/// 等待停止 /// 等待启动
/// </summary> /// </summary>
AlgorithmWaitStop = 1, WaitSetup,
/// <summary> /// <summary>
/// 算法启动状态 /// 等待初始化完成
/// </summary> /// </summary>
AlgorithmSetup = 2, WaitCheckOK,
// --------------------------------------------------------------------
// 算法运行状态
// --------------------------------------------------------------------
/// <summary> /// <summary>
/// 算法等待初始化完成 /// 目标检测
/// </summary> /// </summary>
AlgorithmWaitCheckedOk = 3, Detect,
/// <summary> /// <summary>
/// 算法目标检测 /// 裁切
/// </summary> /// </summary>
AlgorithmDetect = 10, CropRoi,
// --------------------------------------------------------------------
// 停止
// --------------------------------------------------------------------
/// <summary> /// <summary>
/// 算法裁剪状态 /// 等待结束
/// </summary> /// </summary>
AlgorithmCropRoi = 11, WaitStop
} }
} }
...@@ -104,5 +104,8 @@ ...@@ -104,5 +104,8 @@
<ItemGroup> <ItemGroup>
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Model\NDIView\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project> </Project>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using VIZ.H2V.Domain;
using VIZ.H2V.Storage;
namespace VIZ.H2V.Module.Resource
{
/// <summary>
/// NDI视图状态 -> 面板是否可用转化器
/// </summary>
public class NDIViewStatusAndMode2BoolConverter : IMultiValueConverter
{
#region TrueListString -- True的值
private string trueListStringmyVar;
/// <summary>
/// 为True的值
/// </summary>
public string TrueListString
{
get { return trueListStringmyVar; }
set
{
trueListStringmyVar = value;
string[] items = value.Split(',');
List<NDIViewStatus> list = new List<NDIViewStatus>();
foreach (string item in items)
{
NDIViewStatus status = (NDIViewStatus)Enum.Parse(typeof(NDIViewStatus), item.Trim());
list.Add(status);
}
this.trueList = list;
}
}
private List<NDIViewStatus> trueList = new List<NDIViewStatus>();
#endregion
#region Mode -- 算法模式
/// <summary>
/// 算法模式
/// </summary>
public AlgorithmStrategyMode Mode { get; set; }
#endregion
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null || values.Length < 2 || !(values[0] is AlgorithmStrategyMode) || !(values[1] is NDIViewStatus))
return false;
AlgorithmStrategyMode mode = (AlgorithmStrategyMode)values[0];
NDIViewStatus status = (NDIViewStatus)values[1];
return this.Mode == mode && this.trueList.Contains(status);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using VIZ.H2V.Domain;
using VIZ.H2V.Storage;
using System.Windows;
namespace VIZ.H2V.Module.Resource
{
/// <summary>
/// NDI视图状态 -> 面板可见性转化器
/// </summary>
public class NDIViewStatusAndMode2VisibilityConverter : IMultiValueConverter
{
#region TrueVisibility -- 为真时的返回值
/// <summary>
/// 为真时的返回值
/// </summary>
public Visibility TrueVisibility { get; set; } = Visibility.Visible;
#endregion
#region FalseVisibility -- 为假时的返回值
/// <summary>
/// 为假时的返回值
/// </summary>
public Visibility FalseVisibility { get; set; } = Visibility.Hidden;
#endregion
#region TrueListString -- True的值
private string trueListStringmyVar;
/// <summary>
/// 为True的值
/// </summary>
public string TrueListString
{
get { return trueListStringmyVar; }
set
{
trueListStringmyVar = value;
string[] items = value.Split(',');
List<NDIViewStatus> list = new List<NDIViewStatus>();
foreach (string item in items)
{
NDIViewStatus status = (NDIViewStatus)Enum.Parse(typeof(NDIViewStatus), item.Trim());
list.Add(status);
}
this.trueList = list;
}
}
private List<NDIViewStatus> trueList = new List<NDIViewStatus>();
#endregion
#region Mode -- 算法模式
/// <summary>
/// 算法模式
/// </summary>
public AlgorithmStrategyMode Mode { get; set; }
#endregion
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null || values.Length < 2 || !(values[0] is AlgorithmStrategyMode) || !(values[1] is NDIViewStatus))
return false;
AlgorithmStrategyMode mode = (AlgorithmStrategyMode)values[0];
NDIViewStatus status = (NDIViewStatus)values[1];
return (this.Mode == mode && this.trueList.Contains(status)) ? this.TrueVisibility : this.FalseVisibility;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
\ No newline at end of file
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
<Trigger Property="IsMouseOver" Value="True"> <Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="#ff303d54"></Setter> <Setter TargetName="border" Property="Background" Value="#ff303d54"></Setter>
</Trigger> </Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.7"></Setter>
</Trigger>
</ControlTemplate.Triggers> </ControlTemplate.Triggers>
</ControlTemplate> </ControlTemplate>
</Setter.Value> </Setter.Value>
......
...@@ -104,7 +104,9 @@ ...@@ -104,7 +104,9 @@
</Page> </Page>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Converter\NDIViewProperty2BoolConverter.cs" /> <Compile Include="Converter\NDIViewStatusAndMode2VisibilityConverter.cs" />
<Compile Include="Converter\NDIViewStatusAndMode2BoolConverter.cs" />
<Compile Include="Converter\NDIViewStatus2BoolConverter.cs" />
<Compile Include="Properties\AssemblyInfo.cs"> <Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
......
...@@ -88,10 +88,6 @@ namespace VIZ.H2V.Module ...@@ -88,10 +88,6 @@ namespace VIZ.H2V.Module
{ {
selectedAlgorithmStrategy = value; selectedAlgorithmStrategy = value;
this.RaisePropertyChanged(nameof(SelectedAlgorithmStrategy)); this.RaisePropertyChanged(nameof(SelectedAlgorithmStrategy));
if (value != null)
{
this.ViewConfig.StrategyType = (AlgorithmStrategyType)value.ID;
}
} }
} }
...@@ -205,7 +201,8 @@ namespace VIZ.H2V.Module ...@@ -205,7 +201,8 @@ namespace VIZ.H2V.Module
/// <returns>是否成功保存</returns> /// <returns>是否成功保存</returns>
public bool Save() public bool Save()
{ {
ApplicationDomainEx.LiteDbContext.ViewConfig.Upsert(this.ViewConfig); this.ViewConfig.StrategyType = (AlgorithmStrategyType)this.SelectedAlgorithmStrategy.ID;
ApplicationDomainEx.LiteDbContext.ViewConfig.Update(this.ViewConfig);
return true; return true;
} }
...@@ -224,7 +221,8 @@ namespace VIZ.H2V.Module ...@@ -224,7 +221,8 @@ namespace VIZ.H2V.Module
if (strategy != null) if (strategy != null)
{ {
// 设置算法显示名称 // 设置算法显示名称
service.AlgorithmStrategyDisplayName = strategy.DisplayName; service.StrategyDisplayName = strategy.DisplayName;
service.StrategyType = this.ViewConfig.StrategyType;
} }
return true; return true;
......
...@@ -238,7 +238,13 @@ namespace VIZ.H2V.Module ...@@ -238,7 +238,13 @@ namespace VIZ.H2V.Module
// 如果需要重启算法那么重启算法 // 如果需要重启算法那么重启算法
INDIViewService service = ApplicationDomainEx.ServiceManager.GetService<INDIViewService>(this.ViewKey); INDIViewService service = ApplicationDomainEx.ServiceManager.GetService<INDIViewService>(this.ViewKey);
service.UpdateModeAsync(isNeedRestart);
ChangeStrategyContext context = new ChangeStrategyContext();
context.Mode = service.ViewConfig.StrategyMode;
context.IsNeedRestart = isNeedRestart;
context.TriggerScene = NDIViewScene.SettingPanel;
service.ChangeStrategyMode(context);
// 关闭窗口 // 关闭窗口
this.GetWindow().Close(); this.GetWindow().Close();
......
...@@ -3,196 +3,182 @@ using System.Collections.Generic; ...@@ -3,196 +3,182 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using VIZ.Framework.Common;
using VIZ.Framework.Core;
using VIZ.H2V.Domain;
using VIZ.H2V.Storage; using VIZ.H2V.Storage;
using log4net; using log4net;
using VIZ.H2V.Domain;
using VIZ.Framework.Connection; using VIZ.Framework.Connection;
using VIZ.H2V.Connection;
using System.Diagnostics; using System.Diagnostics;
using VIZ.H2V.Connection;
using VIZ.Framework.Common;
using VIZ.Framework.Core;
namespace VIZ.H2V.Module namespace VIZ.H2V.Module
{ {
/// <summary> /// <summary>
/// 算法控制器 /// 算法控制器基类
/// </summary> /// </summary>
public class AlgorithmController public abstract class AlgorithmControllerBase : IAlgorithmController
{ {
/// <summary> /// <summary>
/// 日志 /// 日志
/// </summary> /// </summary>
private static ILog log = LogManager.GetLogger(typeof(AlgorithmController)); private static ILog log = LogManager.GetLogger(typeof(AlgorithmControllerBase));
/// <summary> /// <summary>
/// 算法停止超时时间 /// 已经使用过了的端口
/// </summary> /// </summary>
private readonly int AlgorithmStopTimeout = ApplicationDomainEx.IniStorage.GetValue<AlgorithmConfig, int>(p => p.ALGORITHM_STOP_TIMEOUT); private static readonly List<int> GlobalUsedPorts = new List<int>();
/// <summary> /// <summary>
/// 客户端UDP端口 /// 算法控制器基类
/// </summary> /// </summary>
private readonly int ClientPort = ApplicationDomainEx.IniStorage.GetValue<UdpConfig, int>(p => p.UDP_BINDING_PORT); /// <param name="support">算法支持</param>
/// <param name="strategyType">算法策略</param>
public AlgorithmControllerBase(IAlgorithmSupport support, AlgorithmStrategyType strategyType)
{
this.Support = support;
this.StrategyType = strategyType;
}
/// <summary> /// <summary>
/// 已经使用过了的端口 /// 算法停止超时时间
/// </summary> /// </summary>
private static readonly List<int> UsedPorts = new List<int>(); protected readonly int ALGORITHM_STOP_TIMEOUT = ApplicationDomainEx.IniStorage.GetValue<AlgorithmConfig, int>(p => p.ALGORITHM_STOP_TIMEOUT);
/// <summary> /// <summary>
/// 算法控制器 /// 客户端UDP端口
/// </summary> /// </summary>
/// <param name="support">算法控制器支持</param> protected readonly int CLIENT_PORT = ApplicationDomainEx.IniStorage.GetValue<UdpConfig, int>(p => p.UDP_BINDING_PORT);
public AlgorithmController(IAlgorithmSupport support)
{
this.Support = support;
}
// ======================================================================================
// === Field ===
// ======================================================================================
/// <summary> /// <summary>
/// 控制器支持 /// 算法支持
/// </summary> /// </summary>
private IAlgorithmSupport Support; public IAlgorithmSupport Support { get; private set; }
// ====================================================================================== /// <summary>
// === Public Function === /// 算法策略
// ====================================================================================== /// </summary>
public AlgorithmStrategyType StrategyType { get; private set; }
/// <summary> /// <summary>
/// 停止算法 /// 重启算法
/// </summary> /// </summary>
public void StopAlgorithm() public void RestartAlgorithm()
{ {
// 已经处于停止状态 // 已经处于等待停止状态 那么不处理
if (this.Support.ViewStatus == NDIViewStatus.AlgorithmWaitStop) if (this.Support.ViewStatus == NDIViewStatus.WaitStop)
return; return;
this.Support.ViewStatus = NDIViewStatus.AlgorithmWaitStop; this.Support.ViewStatus = NDIViewStatus.WaitStop;
this.ExecuteRestartAlgorithm_StopProcess();
this.Support.ViewStatus = NDIViewStatus.AlgorithmStop; Task.Run(() =>
{
try
{
if (!this.ExecuteRestartAlgorithm())
{
this.Support.ViewStatus = NDIViewStatus.Stop;
}
}
catch (Exception ex)
{
log.Error(ex);
this.Support.ViewStatus = NDIViewStatus.Stop;
}
});
} }
/// <summary> /// <summary>
/// 切花模式 /// 停止算法
/// </summary> /// </summary>
/// <param name="mode">模式</param> public void StopAlgorithm()
public void ChangeMode(AlgorithmStrategyMode mode)
{ {
// 更新缓存 // 已经处于等待停止状态 || 处于停止状态 || 进程ID不存在 那么不处理
this.Support.ViewConfig.StrategyMode = mode; if (this.Support.ViewStatus == NDIViewStatus.WaitStop || this.Support.ViewStatus == NDIViewStatus.Stop || this.Support.ProcessModel.ProcessID == 0)
ApplicationDomainEx.LiteDbContext.ViewConfig.Update(this.Support.ViewConfig); return;
// 清理跟踪框 & 裁切框 this.Support.ViewStatus = NDIViewStatus.WaitStop;
this.Support.ClearVideoControl();
// 算法处于停止状态(算法重启之后会自动切换一次当前状态) // 停止算法进程
if (this.Support.ViewStatus == NDIViewStatus.AlgorithmStop) if (!this.ExecuteRestartAlgorithm_StopProcess())
{
// 重启算法
this.RestartAlgorithm();
return; return;
}
// 算法处于 等待启动 或 等待初始化完成 状态,那么不需要处理(算法重启之后会自动切换一次当前状态) // 停止UDP
if (this.Support.ViewStatus == NDIViewStatus.AlgorithmSetup || this.Support.ViewStatus == NDIViewStatus.AlgorithmWaitCheckedOk) if (!this.ExecuteRestartAlgorithm_StopUDP())
{
return; return;
}
// 其他状态需要
switch (mode)
{
case AlgorithmStrategyMode.no_mode:
this.ChangeMode_no_mode();
break;
case AlgorithmStrategyMode.center_mode:
this.ChangeMode_center_mode();
break;
case AlgorithmStrategyMode.manual_mode:
this.ChangeMode_manual_mode(this.Support.GetManulRoi());
break;
case AlgorithmStrategyMode.auto_mode:
this.ChangeMode_auto_mode();
break;
default:
break;
}
// 当前模式为自动模式,且场景为单人机位 ==> 目标检测
if (this.Support.ViewConfig.StrategyMode == AlgorithmStrategyMode.auto_mode && this.Support.ViewConfig.StrategyType == AlgorithmStrategyType.Single)
{
this.Support.ViewStatus = NDIViewStatus.AlgorithmDetect;
this.Support.IsDetectButtonVisible = true;
}
//其他机位 ==> 裁切框接收
else
{
this.Support.ViewStatus = NDIViewStatus.AlgorithmCropRoi;
this.Support.IsDetectButtonVisible = false;
}
} }
/// <summary> /// <summary>
/// 切换至自动模式下的跟踪 /// 切换至无模式
/// </summary> /// </summary>
public void ChangeAutoModeTracking(List<int> bbox) public void ChangeNoMode()
{ {
this.ChangeAutoMode_Single(AlgorithmAutoModeSingleCmd.tracking, bbox); UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
this.Support.ViewStatus = NDIViewStatus.AlgorithmCropRoi; if (manager == null)
this.Support.ClearVideoControl(); return;
AlgorithmSender.NoMode(manager, this.Support.ID, this.Support.ViewConfig.IsSendToCrop);
} }
/// <summary> /// <summary>
/// 裁切坐标 /// 切换居中模式
/// </summary> /// </summary>
/// <param name="roi">裁切坐标</param> public void ChangeCenterMode()
public void ChangeManualMode(List<int> roi)
{ {
this.ChangeMode_manual_mode(roi); UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
} if (manager == null)
return;
// ====================================================================================== AlgorithmSender.CenterMode(manager, this.Support.ID, this.Support.ViewConfig.IsSendToCrop);
// === Private Function === }
// ======================================================================================
/// <summary> /// <summary>
/// 重启算法 /// 切换手动模式
/// </summary> /// </summary>
private void RestartAlgorithm() public void ChangeManualMode()
{ {
if (this.Support.ViewStatus == NDIViewStatus.AlgorithmSetup) // 重置3D鼠标
this.Support.Reset3DMouse();
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
if (manager == null)
return; return;
this.Support.ViewStatus = NDIViewStatus.AlgorithmSetup; List<int> roi = this.Support.GetManulRoi();
Task.Run(() => AlgorithmSender.ManualMode(manager, this.Support.ID, this.Support.ViewConfig.IsSendToCrop, roi);
{
try
{
if (!this.ExecuteRestartAlgorithm())
{
this.Support.ViewStatus = NDIViewStatus.AlgorithmStop;
}
}
catch (Exception ex)
{
log.Error(ex);
this.Support.ViewStatus = NDIViewStatus.AlgorithmStop;
}
});
} }
/// <summary> /// <summary>
/// 切换至自动模式
/// </summary>
/// <param name="context">切换模式上下文</param>
public abstract void ChangeAutoMode(ChangeStrategyContext context);
/// <summary>
/// 初始化完成
/// </summary>
public abstract void CheckOk();
/// <summary>
/// 检测
/// </summary>
public abstract void Detect();
/// <summary>
/// 跟踪
/// </summary>
/// <param name="box">跟踪框</param>
public abstract void Tracking(TrackingBoxInfo box);
/// <summary>
/// 执行重启算法 /// 执行重启算法
/// </summary> /// </summary>
/// <returns>是否成功重启</returns> /// <returns>是否成功重启</returns>
private bool ExecuteRestartAlgorithm() private bool ExecuteRestartAlgorithm()
{ {
// 需要先停止 // 需要先停止
if (this.Support.AlgorithmProcessModel.ProcessID > 0) if (this.Support.ProcessModel.ProcessID > 0)
{ {
// 停止算法进程 // 停止算法进程
if (!this.ExecuteRestartAlgorithm_StopProcess()) if (!this.ExecuteRestartAlgorithm_StopProcess())
...@@ -212,7 +198,7 @@ namespace VIZ.H2V.Module ...@@ -212,7 +198,7 @@ namespace VIZ.H2V.Module
return false; return false;
// 成功启动 // 成功启动
this.Support.ViewStatus = NDIViewStatus.AlgorithmWaitCheckedOk; this.Support.ViewStatus = NDIViewStatus.WaitCheckOK;
// 返回成功 // 返回成功
return true; return true;
...@@ -233,7 +219,7 @@ namespace VIZ.H2V.Module ...@@ -233,7 +219,7 @@ namespace VIZ.H2V.Module
{ {
try try
{ {
AlgorithmSender.Stop(manager, this.Support.AlgorithmID); AlgorithmSender.Stop(manager, this.Support.ID);
} }
catch catch
{ {
...@@ -242,13 +228,13 @@ namespace VIZ.H2V.Module ...@@ -242,13 +228,13 @@ namespace VIZ.H2V.Module
DateTime beginTime = DateTime.Now; DateTime beginTime = DateTime.Now;
// 等待停止 // 等待停止
while ((DateTime.Now - beginTime).TotalMilliseconds < this.AlgorithmStopTimeout) while ((DateTime.Now - beginTime).TotalMilliseconds < this.ALGORITHM_STOP_TIMEOUT)
{ {
try try
{ {
if (this.Support.AlgorithmProcessModel.ProcessID > 0) if (this.Support.ProcessModel.ProcessID > 0)
{ {
process = Process.GetProcessById(this.Support.AlgorithmProcessModel.ProcessID); process = Process.GetProcessById(this.Support.ProcessModel.ProcessID);
} }
} }
catch catch
...@@ -266,9 +252,9 @@ namespace VIZ.H2V.Module ...@@ -266,9 +252,9 @@ namespace VIZ.H2V.Module
try try
{ {
if (this.Support.AlgorithmProcessModel.ProcessID > 0) if (this.Support.ProcessModel.ProcessID > 0)
{ {
process = Process.GetProcessById(this.Support.AlgorithmProcessModel.ProcessID); process = Process.GetProcessById(this.Support.ProcessModel.ProcessID);
} }
} }
catch catch
...@@ -290,12 +276,12 @@ namespace VIZ.H2V.Module ...@@ -290,12 +276,12 @@ namespace VIZ.H2V.Module
} }
// 移除占用的端口标志 // 移除占用的端口标志
lock (UsedPorts) lock (GlobalUsedPorts)
{ {
UsedPorts.Remove(this.Support.AlgorithmProcessModel.Port); GlobalUsedPorts.Remove(this.Support.ProcessModel.Port);
} }
this.Support.AlgorithmProcessModel.ProcessID = 0; this.Support.ProcessModel.ProcessID = 0;
// 如果缓存已经被释放,那么不处理更新缓存 // 如果缓存已经被释放,那么不处理更新缓存
if (ApplicationDomainEx.LiteDbContext == null) if (ApplicationDomainEx.LiteDbContext == null)
...@@ -343,11 +329,11 @@ namespace VIZ.H2V.Module ...@@ -343,11 +329,11 @@ namespace VIZ.H2V.Module
} }
// 端口 // 端口
int port = this.Support.AlgorithmProcessModel.Port; int port = this.Support.ProcessModel.Port;
// NDI流名称 // NDI流名称
string ndi_name = this.Support.ViewConfig.StreamName; string ndi_name = this.Support.ViewConfig.StreamName;
// 视图ID // 视图ID
string id = this.Support.AlgorithmID; string id = this.Support.ID;
// GPU设备号 // GPU设备号
int device = this.Support.ViewConfig.GPU; int device = this.Support.ViewConfig.GPU;
...@@ -369,7 +355,7 @@ namespace VIZ.H2V.Module ...@@ -369,7 +355,7 @@ namespace VIZ.H2V.Module
proc.StartInfo.WorkingDirectory = dir; proc.StartInfo.WorkingDirectory = dir;
proc.StartInfo.UseShellExecute = true; proc.StartInfo.UseShellExecute = true;
proc.StartInfo.FileName = fileName; proc.StartInfo.FileName = fileName;
proc.StartInfo.Arguments = $"--port=\"{port}\" --ndi_name=\"{ndi_name}\" --id=\"{id}\" --device=\"{device}\" --vis_port=\"{ClientPort}\""; proc.StartInfo.Arguments = $"--port=\"{port}\" --ndi_name=\"{ndi_name}\" --id=\"{id}\" --device=\"{device}\" --vis_port=\"{CLIENT_PORT}\"";
proc.StartInfo.WindowStyle = ProcessWindowStyle.Normal; proc.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
if (!proc.Start()) if (!proc.Start())
...@@ -380,10 +366,10 @@ namespace VIZ.H2V.Module ...@@ -380,10 +366,10 @@ namespace VIZ.H2V.Module
return false; return false;
} }
this.Support.AlgorithmProcessModel.ProcessID = proc.Id; this.Support.ProcessModel.ProcessID = proc.Id;
// 更新缓存 // 更新缓存
this.Support.ViewConfig.ProcessID = this.Support.AlgorithmProcessModel.ProcessID; this.Support.ViewConfig.ProcessID = this.Support.ProcessModel.ProcessID;
ApplicationDomainEx.LiteDbContext.ViewConfig.Update(this.Support.ViewConfig); ApplicationDomainEx.LiteDbContext.ViewConfig.Update(this.Support.ViewConfig);
return true; return true;
...@@ -405,147 +391,19 @@ namespace VIZ.H2V.Module ...@@ -405,147 +391,19 @@ namespace VIZ.H2V.Module
return false; return false;
} }
lock (UsedPorts) lock (GlobalUsedPorts)
{ {
string ip = clientIP; string ip = clientIP;
int port = NetHelper.GetAvailableUdpPort(8200, 9200, UsedPorts); int port = NetHelper.GetAvailableUdpPort(8200, 9200, GlobalUsedPorts);
UsedPorts.Add(port); GlobalUsedPorts.Add(port);
ConnectionManager.UdpConnection.AddEndpointManager(new UdpEndpointManager(this.Support.ViewKey, ip, port)); ConnectionManager.UdpConnection.AddEndpointManager(new UdpEndpointManager(this.Support.ViewKey, ip, port));
this.Support.AlgorithmProcessModel.IP = ip; this.Support.ProcessModel.IP = ip;
this.Support.AlgorithmProcessModel.Port = port; this.Support.ProcessModel.Port = port;
} }
return true; return true;
} }
/// <summary>
/// 设置参数 -- 单人机位
/// </summary>
/// <param name="cmd">命令</param>
/// <param name="bbox">跟踪坐标</param>
private void ChangeAutoMode_Single(string cmd, List<int> bbox)
{
AlgorithmSingle config = ApplicationDomainEx.LiteDbContext.AlgorithmSingle.FindOne(p => p.ViewKey == this.Support.ViewKey);
if (config == null)
return;
AlgorithmPackage__auto_mode_Single package = new AlgorithmPackage__auto_mode_Single();
package.cmd = cmd;
package.smooth = config.SmoothCoeff;
package.max_fixed_frames = config.KeepPrevFrame;
package.bbox = bbox;
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
AlgorithmSender.AutoMode(manager, package, this.Support.AlgorithmID, this.Support.ViewConfig.IsSendToCrop);
}
/// <summary>
/// 设置参数 -- 近景机位
/// </summary>
private void ChangeAutoMode_Near()
{
AlgorithmNear config = ApplicationDomainEx.LiteDbContext.AlgorithmNear.FindOne(p => p.ViewKey == this.Support.ViewKey);
if (config == null)
return;
AlgorithmPackage__auto_mode_Near package = new AlgorithmPackage__auto_mode_Near();
package.smooth = config.SmoothCoeff;
package.max_fixed_frames = config.KeepPrevFrame;
package.min_human_area = config.PersonAreaProportion / 100d;
package.weight_area = config.PersonAreaProportionWeight / 100d;
package.min_conf = config.Confidence / 100d;
package.weight_conf = config.ConfidenceWeight / 100d;
package.weight_distance = config.PositionToCenterWeight / 100d;
package.auto_follow_human = config.NoBallAutoChangeToPerson ? 1 : 0;
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
AlgorithmSender.AutoMode(manager, package, this.Support.AlgorithmID, this.Support.ViewConfig.IsSendToCrop);
}
/// <summary>
/// 设置参数 -- 16米机位
/// </summary>
private void ChangeAutoMode_Sixteen()
{
AlgorithmSixteen config = ApplicationDomainEx.LiteDbContext.AlgorithmSixteen.FindOne(p => p.ViewKey == this.Support.ViewKey);
if (config == null)
return;
AlgorithmPackage__auto_mode_Sixteen package = new AlgorithmPackage__auto_mode_Sixteen();
package.smooth = config.SmoothCoeff;
package.max_fixed_frames = config.KeepPrevFrame;
package.min_human_area = config.PersonAreaProportion / 100d;
package.weight_area = config.PersonAreaProportionWeight / 100d;
package.min_conf = config.Confidence / 100d;
package.weight_conf = config.ConfidenceWeight / 100d;
package.weight_distance = config.PositionToCenterWeight / 100d;
package.auto_follow_human = config.NoBallAutoChangeToPerson ? 1 : 0;
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
AlgorithmSender.AutoMode(manager, package, this.Support.AlgorithmID, this.Support.ViewConfig.IsSendToCrop);
}
/// <summary>
/// 切换无模式
/// </summary>
private void ChangeMode_no_mode()
{
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
if (manager == null)
return;
AlgorithmSender.NoMode(manager, this.Support.AlgorithmID, this.Support.ViewConfig.IsSendToCrop);
}
/// <summary>
/// 切换居中模式
/// </summary>
private void ChangeMode_center_mode()
{
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
if (manager == null)
return;
AlgorithmSender.CenterMode(manager, this.Support.AlgorithmID, this.Support.ViewConfig.IsSendToCrop);
}
/// <summary>
/// 切换手动模式
/// </summary>
/// <param name="roi">裁切坐标</param>
private void ChangeMode_manual_mode(List<int> roi)
{
if (roi == null)
return;
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
if (manager == null)
return;
AlgorithmSender.ManualMode(manager, this.Support.AlgorithmID, this.Support.ViewConfig.IsSendToCrop, roi);
}
/// <summary>
/// 切换算法模式
/// </summary>
private void ChangeMode_auto_mode()
{
switch (this.Support.ViewConfig.StrategyType)
{
case AlgorithmStrategyType.Single:
this.ChangeAutoMode_Single(AlgorithmAutoModeSingleCmd.detect, null);
return;
case AlgorithmStrategyType.Near:
this.ChangeAutoMode_Near();
return;
case AlgorithmStrategyType.Sixteen:
this.ChangeAutoMode_Sixteen();
return;
default:
return;
}
}
} }
} }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Common;
using VIZ.H2V.Storage;
namespace VIZ.H2V.Module
{
/// <summary>
/// 算法控制器
/// </summary>
public interface IAlgorithmController
{
/// <summary>
/// 算法支持
/// </summary>
IAlgorithmSupport Support { get; }
/// <summary>
/// 算法策略
/// </summary>
AlgorithmStrategyType StrategyType { get; }
/// <summary>
/// 重启算法
/// </summary>
void RestartAlgorithm();
/// <summary>
/// 停止算法
/// </summary>
void StopAlgorithm();
/// <summary>
/// 初始化完成
/// </summary>
void CheckOk();
/// <summary>
/// 检测
/// </summary>
void Detect();
/// <summary>
/// 跟踪
/// </summary>
/// <param name="box">跟踪框</param>
void Tracking(TrackingBoxInfo box);
/// <summary>
/// 切换至无模式
/// </summary>
void ChangeNoMode();
/// <summary>
/// 切换居中模式
/// </summary>
void ChangeCenterMode();
/// <summary>
/// 切换手动模式
/// </summary>
void ChangeManualMode();
/// <summary>
/// 切换至自动模式
/// </summary>
/// <param name="context">切换模式上下文</param>
void ChangeAutoMode(ChangeStrategyContext context);
}
}
...@@ -14,14 +14,14 @@ namespace VIZ.H2V.Module ...@@ -14,14 +14,14 @@ namespace VIZ.H2V.Module
public interface IAlgorithmSupport public interface IAlgorithmSupport
{ {
/// <summary> /// <summary>
/// 算法进程模型 /// 算法ID
/// </summary> /// </summary>
AlgorithmProcessModel AlgorithmProcessModel { get; } string ID { get; }
/// <summary> /// <summary>
/// 当前算法模式 /// NDI视图键
/// </summary> /// </summary>
AlgorithmStrategyMode AlgorithmStrategyMode { get; } string ViewKey { get; }
/// <summary> /// <summary>
/// 视图配置 /// 视图配置
...@@ -29,34 +29,49 @@ namespace VIZ.H2V.Module ...@@ -29,34 +29,49 @@ namespace VIZ.H2V.Module
NdiViewConfig ViewConfig { get; } NdiViewConfig ViewConfig { get; }
/// <summary> /// <summary>
/// 算法ID /// 显示名称
/// </summary> /// </summary>
string AlgorithmID { get; } string DisplayName { get; }
/// <summary> /// <summary>
/// NDI视图键 /// 算法策略显示名称
/// </summary> /// </summary>
string ViewKey { get; } string StrategyDisplayName { get; }
/// <summary> /// <summary>
/// NDI视图状态 /// 裁切框X坐标
/// </summary> /// </summary>
NDIViewStatus ViewStatus { get; set; } double? ClipBoxX { get; }
/// <summary> /// <summary>
/// 检测按钮是否可见 /// 算法模式
/// </summary> /// </summary>
bool IsDetectButtonVisible { get; set; } AlgorithmStrategyMode StrategyMode { get; set; }
/// <summary> /// <summary>
/// 清理视频控件 /// 算法类型
/// </summary> /// </summary>
void ClearVideoControl(); AlgorithmStrategyType StrategyType { get; set; }
/// <summary>
/// NDI视图状态
/// </summary>
NDIViewStatus ViewStatus { get; set; }
/// <summary>
/// 算法进程模型
/// </summary>
AlgorithmProcessModel ProcessModel { get; }
/// <summary> /// <summary>
/// 获取手动裁切框 /// 获取手动裁切框
/// </summary> /// </summary>
/// <returns>手动裁切框</returns> /// <returns>手动裁切框</returns>
List<int> GetManulRoi(); List<int> GetManulRoi();
/// <summary>
/// 重置3D鼠标
/// </summary>
void Reset3DMouse();
} }
} }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Common;
using VIZ.Framework.Connection;
using VIZ.H2V.Connection;
using VIZ.H2V.Domain;
using VIZ.H2V.Storage;
namespace VIZ.H2V.Module
{
/// <summary>
/// 算法控制器 -- 近景机位
/// </summary>
public class AlgorithmController_Near : AlgorithmControllerBase
{
/// <summary>
/// 算法控制器 -- 近景机位
/// </summary>
/// <param name="support">算法支持</param>
public AlgorithmController_Near(IAlgorithmSupport support) : base(support, AlgorithmStrategyType.Near)
{ }
/// <summary>
/// 切换至自动模式
/// </summary>
/// <param name="context">切换模式上下文</param>
public override void ChangeAutoMode(ChangeStrategyContext context)
{
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
AlgorithmSender.AutoMode(manager, this.BuildPackage(), this.Support.ID, this.Support.ViewConfig.IsSendToCrop);
}
/// <summary>
/// 初始化完成
/// </summary>
public override void CheckOk()
{
this.Support.ViewStatus = NDIViewStatus.CropRoi;
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
AlgorithmSender.AutoMode(manager, this.BuildPackage(), this.Support.ID, this.Support.ViewConfig.IsSendToCrop);
}
/// <summary>
/// 检测
/// </summary>
public override void Detect()
{
}
/// <summary>
/// 跟踪
/// </summary>
/// <param name="box">跟踪框</param>
public override void Tracking(TrackingBoxInfo box)
{
}
/// <summary>
/// 构建数据包
/// </summary>
/// <returns>数据包</returns>
private AlgorithmPackage__auto_mode_Near BuildPackage()
{
AlgorithmNear config = ApplicationDomainEx.LiteDbContext.AlgorithmNear.FindOne(p => p.ViewKey == this.Support.ViewKey);
if (config == null)
return null;
AlgorithmPackage__auto_mode_Near package = new AlgorithmPackage__auto_mode_Near();
package.smooth = config.SmoothCoeff;
package.max_fixed_frames = config.KeepPrevFrame;
package.min_human_area = config.PersonAreaProportion / 100d;
package.weight_area = config.PersonAreaProportionWeight / 100d;
package.min_conf = config.Confidence / 100d;
package.weight_conf = config.ConfidenceWeight / 100d;
package.weight_distance = config.PositionToCenterWeight / 100d;
package.auto_follow_human = config.NoBallAutoChangeToPerson ? 1 : 0;
return package;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Common;
using VIZ.Framework.Connection;
using VIZ.H2V.Connection;
using VIZ.H2V.Domain;
using VIZ.H2V.Storage;
namespace VIZ.H2V.Module
{
/// <summary>
/// 算法控制器 -- 单人机位
/// </summary>
public class AlgorithmController_Single : AlgorithmControllerBase
{
/// <summary>
/// 算法控制器 -- 单人机位
/// </summary>
/// <param name="support">算法支持</param>
public AlgorithmController_Single(IAlgorithmSupport support) : base(support, AlgorithmStrategyType.Single)
{ }
/// <summary>
/// 切换至自动模式
/// </summary>
/// <param name="context">切换模式上下文</param>
public override void ChangeAutoMode(ChangeStrategyContext context)
{
// 视频面板触发需要进入检测状态
if (context.TriggerScene == NDIViewScene.VideoPanel)
{
this.Detect();
return;
}
// 设置面板触发则根据当前状态确定
if (this.Support.ViewStatus == NDIViewStatus.Detect)
{
this.Detect();
return;
}
// 单人机位跟踪命令可以不设置跟踪框
if (this.Support.ViewStatus == NDIViewStatus.CropRoi)
{
this.Tracking(null);
}
}
/// <summary>
/// 初始化完成
/// </summary>
public override void CheckOk()
{
this.Detect();
}
/// <summary>
/// 检测
/// </summary>
public override void Detect()
{
this.Support.ViewStatus = NDIViewStatus.Detect;
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
AlgorithmSender.AutoMode(manager, this.BuildPackage(AlgorithmAutoModeSingleCmd.detect, null), this.Support.ID, this.Support.ViewConfig.IsSendToCrop);
}
/// <summary>
/// 跟踪
/// </summary>
/// <param name="box">跟踪框</param>
public override void Tracking(TrackingBoxInfo box)
{
this.Support.ViewStatus = NDIViewStatus.CropRoi;
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
AlgorithmSender.AutoMode(manager, this.BuildPackage(AlgorithmAutoModeSingleCmd.tracking, box), this.Support.ID, this.Support.ViewConfig.IsSendToCrop);
}
/// <summary>
/// 构建数据包
/// </summary>
/// <param name="cmd">命令</param>
/// <param name="box">跟踪框</param>
/// <returns>数据包</returns>
public AlgorithmPackage__auto_mode_Single BuildPackage(string cmd, TrackingBoxInfo box)
{
AlgorithmSingle config = ApplicationDomainEx.LiteDbContext.AlgorithmSingle.FindOne(p => p.ViewKey == this.Support.ViewKey);
if (config == null)
return null;
AlgorithmPackage__auto_mode_Single package = new AlgorithmPackage__auto_mode_Single();
package.cmd = cmd;
package.smooth = config.SmoothCoeff;
package.max_fixed_frames = config.KeepPrevFrame;
package.bbox = box == null ? null : new List<int> { (int)box.SrcRect.Left, (int)box.SrcRect.Top, (int)box.SrcRect.Right, (int)box.SrcRect.Bottom };
return package;
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Common;
using VIZ.Framework.Connection;
using VIZ.H2V.Connection;
using VIZ.H2V.Domain;
using VIZ.H2V.Storage;
namespace VIZ.H2V.Module
{
/// <summary>
/// 算法控制器 -- 16米机位
/// </summary>
public class AlgorithmController_Sixteen : AlgorithmControllerBase
{
/// <summary>
/// 算法控制器 -- 16米机位
/// </summary>
/// <param name="support">算法支持</param>
public AlgorithmController_Sixteen(IAlgorithmSupport support) : base(support, AlgorithmStrategyType.Sixteen)
{ }
/// <summary>
/// 切换至自动模式
/// </summary>
/// <param name="context">切换模式上下文</param>
public override void ChangeAutoMode(ChangeStrategyContext context)
{
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
AlgorithmSender.AutoMode(manager, this.BuildPackage(), this.Support.ID, this.Support.ViewConfig.IsSendToCrop);
}
/// <summary>
/// 初始化完成
/// </summary>
public override void CheckOk()
{
this.Support.ViewStatus = NDIViewStatus.CropRoi;
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
AlgorithmSender.AutoMode(manager, this.BuildPackage(), this.Support.ID, this.Support.ViewConfig.IsSendToCrop);
}
/// <summary>
/// 检测
/// </summary>
public override void Detect()
{
}
/// <summary>
/// 跟踪
/// </summary>
/// <param name="box">跟踪框</param>
public override void Tracking(TrackingBoxInfo box)
{
}
/// <summary>
/// 构建数据包
/// </summary>
/// <returns>数据包</returns>
public AlgorithmPackage__auto_mode_Sixteen BuildPackage()
{
AlgorithmSixteen config = ApplicationDomainEx.LiteDbContext.AlgorithmSixteen.FindOne(p => p.ViewKey == this.Support.ViewKey);
if (config == null)
return null;
AlgorithmPackage__auto_mode_Sixteen package = new AlgorithmPackage__auto_mode_Sixteen();
package.smooth = config.SmoothCoeff;
package.max_fixed_frames = config.KeepPrevFrame;
package.min_human_area = config.PersonAreaProportion / 100d;
package.weight_area = config.PersonAreaProportionWeight / 100d;
package.min_conf = config.Confidence / 100d;
package.weight_conf = config.ConfidenceWeight / 100d;
package.weight_distance = config.PositionToCenterWeight / 100d;
package.auto_follow_human = config.NoBallAutoChangeToPerson ? 1 : 0;
return package;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VIZ.H2V.Module
{
/// <summary>
/// 视图场景
/// </summary>
public enum NDIViewScene
{
/// <summary>
/// 视频面板
/// </summary>
VideoPanel,
/// <summary>
/// 设置面板
/// </summary>
SettingPanel
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.H2V.Storage;
namespace VIZ.H2V.Module
{
/// <summary>
/// 切换算法上下文
/// </summary>
public class ChangeStrategyContext
{
/// <summary>
/// 是否使用裁切
/// </summary>
public bool IsUseClip { get; set; }
/// <summary>
/// 算法模式
/// </summary>
public AlgorithmStrategyMode Mode { get; set; }
/// <summary>
/// 算法是否需要重启
/// </summary>
public bool IsNeedRestart { get; set; }
/// <summary>
/// 触发场景
/// </summary>
public NDIViewScene TriggerScene { get; set; }
}
}
...@@ -21,7 +21,12 @@ namespace VIZ.H2V.Module ...@@ -21,7 +21,12 @@ namespace VIZ.H2V.Module
/// <summary> /// <summary>
/// 算法类型显示名称 /// 算法类型显示名称
/// </summary> /// </summary>
string AlgorithmStrategyDisplayName { get; set; } string StrategyDisplayName { get; set; }
/// <summary>
/// 算法类型
/// </summary>
AlgorithmStrategyType StrategyType { get; set; }
/// <summary> /// <summary>
/// 视图配置 /// 视图配置
...@@ -39,9 +44,9 @@ namespace VIZ.H2V.Module ...@@ -39,9 +44,9 @@ namespace VIZ.H2V.Module
void StopAlgorithm(); void StopAlgorithm();
/// <summary> /// <summary>
/// 异步更新模式 /// 切换模式
/// </summary> /// </summary>
/// <param name="isRestart">是否需要重启</param> /// <param name="context">切换模式上下文</param>
void UpdateModeAsync(bool isRestart); void ChangeStrategyMode(ChangeStrategyContext context);
} }
} }
...@@ -21,8 +21,11 @@ ...@@ -21,8 +21,11 @@
<ResourceDictionary Source="/VIZ.H2V.Module.Resource;component/Style/CheckBox/CheckBox_NdiView.xaml"></ResourceDictionary> <ResourceDictionary Source="/VIZ.H2V.Module.Resource;component/Style/CheckBox/CheckBox_NdiView.xaml"></ResourceDictionary>
<ResourceDictionary Source="/VIZ.H2V.Module.Resource;component/Style/RadioButton/RadioButton_NdiView.xaml"></ResourceDictionary> <ResourceDictionary Source="/VIZ.H2V.Module.Resource;component/Style/RadioButton/RadioButton_NdiView.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
<resource:NDIViewStatus2BoolConverter x:Key="NDIViewStatus2IsEnabledConverter" TrueListString="AlgorithmDetect,AlgorithmCropRoi"></resource:NDIViewStatus2BoolConverter> <fcore:Bool2BoolConverter x:Key="Bool2BoolConverter"></fcore:Bool2BoolConverter>
<resource:NDIViewStatus2BoolConverter x:Key="NDIViewStatus2IsEnabledConverter_SettingButton" TrueListString="AlgorithmStop,AlgorithmWaitCheckedOk,AlgorithmDetect,AlgorithmCropRoi"></resource:NDIViewStatus2BoolConverter> <resource:NDIViewStatus2BoolConverter x:Key="NDIViewStatus2IsEnabledConverter" TrueListString="Detect,CropRoi"></resource:NDIViewStatus2BoolConverter>
<resource:NDIViewStatus2BoolConverter x:Key="NDIViewStatus2IsEnabledConverter_SettingButton" TrueListString="Stop,Detect,CropRoi"></resource:NDIViewStatus2BoolConverter>
<resource:NDIViewStatusAndMode2VisibilityConverter x:Key="NDIViewStatusAndMode2VisibilityConverter_DetectButton" TrueListString="Detect,CropRoi" Mode="auto_mode"></resource:NDIViewStatusAndMode2VisibilityConverter>
<resource:NDIViewStatusAndMode2BoolConverter x:Key="NDIViewStatusAndMode2BoolConverter_DetectButton" TrueListString="CropRoi" Mode="auto_mode"></resource:NDIViewStatusAndMode2BoolConverter>
</ResourceDictionary> </ResourceDictionary>
</UserControl.Resources> </UserControl.Resources>
...@@ -71,16 +74,16 @@ ...@@ -71,16 +74,16 @@
<RowDefinition Height="60"></RowDefinition> <RowDefinition Height="60"></RowDefinition>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<CheckBox FontSize="16" Content="裁切策略:" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" <CheckBox FontSize="16" Content="裁切策略:" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center"
IsChecked="{Binding Path=IsNotNoModeChecked,Mode=TwoWay}" IsChecked="{Binding Path=IsUseClip,Mode=TwoWay}"
Style="{StaticResource CheckBox_NdiView}"></CheckBox> Style="{StaticResource CheckBox_NdiView}"></CheckBox>
<Rectangle Grid.Row="1" Grid.RowSpan="10" Fill="#ff181d2b"></Rectangle> <Rectangle Grid.Row="1" Grid.RowSpan="10" Fill="#ff181d2b"></Rectangle>
<Grid Grid.Row="1" IsEnabled="{Binding IsNotNoModeChecked,Mode=OneWay}"> <Grid Grid.Row="1" IsEnabled="{Binding IsUseClip,Mode=OneWay}">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition> <RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="60"></RowDefinition> <RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="60"></RowDefinition> <RowDefinition Height="60"></RowDefinition>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<RadioButton Content="{Binding Path=AlgorithmStrategyDisplayName,Mode=OneWay}" Grid.Row="0" FontSize="16" Foreground="White" <RadioButton Content="{Binding Path=StrategyDisplayName,Mode=OneWay}" Grid.Row="0" FontSize="16" Foreground="White"
Style="{StaticResource RadioButton_NdiView}" IsChecked="{Binding IsAutoModeChecked,Mode=TwoWay}"> Style="{StaticResource RadioButton_NdiView}" IsChecked="{Binding IsAutoModeChecked,Mode=TwoWay}">
</RadioButton> </RadioButton>
<RadioButton Content="居中" Grid.Row="1" FontSize="16" Foreground="White" <RadioButton Content="居中" Grid.Row="1" FontSize="16" Foreground="White"
...@@ -95,8 +98,19 @@ ...@@ -95,8 +98,19 @@
<Button Content="选择目标" Grid.Row="1" VerticalAlignment="Bottom" Style="{StaticResource Button_Setting}" <Button Content="选择目标" Grid.Row="1" VerticalAlignment="Bottom" Style="{StaticResource Button_Setting}"
Height="40" Width="120" HorizontalAlignment="Right" Margin="0,0,10,0" Height="40" Width="120" HorizontalAlignment="Right" Margin="0,0,10,0"
Command="{Binding Path=DetectCommand}" Command="{Binding Path=DetectCommand}">
Visibility="{Binding Path=IsDetectButtonVisible,Mode=OneWay,Converter={StaticResource Bool2VisibilityConverter}}"> <Button.IsEnabled>
<MultiBinding Converter="{StaticResource NDIViewStatusAndMode2BoolConverter_DetectButton}">
<Binding Path="StrategyMode"></Binding>
<Binding Path="ViewStatus"></Binding>
</MultiBinding>
</Button.IsEnabled>
<Button.Visibility>
<MultiBinding Converter="{StaticResource NDIViewStatusAndMode2VisibilityConverter_DetectButton}">
<Binding Path="StrategyMode"></Binding>
<Binding Path="ViewStatus"></Binding>
</MultiBinding>
</Button.Visibility>
</Button> </Button>
<!-- 视频区域 --> <!-- 视频区域 -->
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using log4net;
using SharpDX.Mathematics.Interop;
using VIZ.Framework.Common;
using VIZ.Framework.Connection;
using VIZ.Framework.Core;
using VIZ.H2V.Connection;
using VIZ.H2V.Domain;
using VIZ.H2V.Storage;
namespace VIZ.H2V.Module
{
/// <summary>
/// NDI视图模型 -- 命令部分
/// </summary>
public partial class NDIViewModel
{
#region LoadedCommand -- 加载命令
/// <summary>
/// 加载命令
/// </summary>
public VCommand LoadedCommand { get; set; }
/// <summary>
/// 加载
/// </summary>
private void Loaded()
{
if (this.IsAlreadyLoaded)
return;
this.IsAlreadyLoaded = true;
NDIView view = this.GetView<NDIView>();
if (view == null)
return;
// 视图键
this.ViewKey = view.NDIKey;
// 初始化视图配置
this.Loaded_ViewConfig();
// 初始化属性
this.Loaded_Property();
// 初始化模式切换
this.Loaded_InitModeChecked();
// 初始化视频控件
this.Loaded_VideoControl(view);
// 初始化NDI
this.LoadedNDI();
// 加载样式
this.LoadStyle();
// 注册服务
ApplicationDomainEx.ServiceManager.AddService(this.ViewKey, this);
}
/// <summary>
/// 初始化视图配置
/// </summary>
private void Loaded_ViewConfig()
{
NdiViewConfig viewConfig = ApplicationDomainEx.LiteDbContext.ViewConfig.FindOne(p => p.ViewKey == this.ViewKey);
this.ViewConfig = viewConfig;
}
/// <summary>
/// 加载 -- 初始化属性
/// </summary>
private void Loaded_Property()
{
AlgorithmStrategy strategy = ApplicationDomainEx.ExcelContext.AlgorithmStrategys.FirstOrDefault(p => p.ID == (int)this.ViewConfig.StrategyType);
// 算法ID
this.ID = $"{NetHelper.GetMacAddress()}__{this.ViewKey}";
// 显示名称
this.DisplayName = this.ViewConfig.DisplayName ?? this.viewKey;
// 算法名称
this.StrategyDisplayName = strategy == null ? this.ViewConfig.StrategyType.GetDescription() : strategy.DisplayName;
// 算法类型
this.StrategyType = this.ViewConfig.StrategyType;
// 裁切模式
this.StrategyMode = this.ViewConfig.StrategyMode;
}
/// <summary>
/// 加载 -- 初始化视频控件
/// </summary>
/// <param name="view">视图</param>
private void Loaded_VideoControl(NDIView view)
{
// 注册视频控件插件
TrackingBoxPlugin trackingBoxPlugin = new TrackingBoxPlugin(view.video);
trackingBoxPlugin.TrackingBoxClick += TrackingBoxPlugin_TrackingBoxClick;
ClipBoxPlugin clipBoxPlugin = new ClipBoxPlugin(view.video);
view.video.AttachPlugin(trackingBoxPlugin);
view.video.AttachPlugin(clipBoxPlugin);
}
/// <summary>
/// 加载 -- 初始化模式切换
/// </summary>
private void Loaded_InitModeChecked()
{
// 更新是否使用裁切
this.isUseClip = this.ViewConfig.IsUseClip;
this.RaisePropertyChanged(nameof(IsUseClip));
// 更新当前模式
switch (this.ViewConfig.StrategyMode)
{
case AlgorithmStrategyMode.center_mode:
this.isCenterModeChecked = true;
this.RaisePropertyChanged(nameof(IsCenterModeChecked));
break;
case AlgorithmStrategyMode.manual_mode:
this.isManualModeChecked = true;
this.RaisePropertyChanged(nameof(IsManualModeChecked));
break;
case AlgorithmStrategyMode.auto_mode:
this.isAutoModeChecked = true;
this.RaisePropertyChanged(nameof(IsAutoModeChecked));
break;
default:
this.isAutoModeChecked = true;
this.RaisePropertyChanged(nameof(IsAutoModeChecked));
break;
}
// 重启算法
this.AlgorithmControllerDic[this.StrategyType].RestartAlgorithm();
}
/// <summary>
/// 视频控件跟踪框点击事件
/// </summary>
private void TrackingBoxPlugin_TrackingBoxClick(object sender, TrackingBoxClickEventArgs e)
{
TrackingBoxInfo box = e.HitTrackingBoxInfos.FirstOrDefault();
if (box == null)
return;
this.AlgorithmControllerDic[this.StrategyType].Tracking(box);
}
#endregion
#region SettingCommand -- 设置命令
/// <summary>
/// 设置命令
/// </summary>
public VCommand<string> SettingCommand { get; set; }
/// <summary>
/// 设置
/// </summary>
/// <param name="key">服务键</param>
private void Setting(string key)
{
NDISettingView view = new NDISettingView(key, this.ID);
NoneWindow window = new NoneWindow(1200, 900, view);
window.Owner = this.GetWindow();
window.ShowDialog();
}
#endregion
#region DetectCommand -- 检测命令
/// <summary>
/// 检测命令
/// </summary>
public VCommand DetectCommand { get; set; }
/// <summary>
/// 检测
/// </summary>
public void Detect()
{
// 只有单人机位下的自动模式可以发送检测指令
if (this.StrategyMode != AlgorithmStrategyMode.auto_mode && this.ViewConfig.StrategyType != AlgorithmStrategyType.Single)
return;
// 清理视频控件
this.ClearVideoControl();
// 切换自动模式
ChangeStrategyContext context = new ChangeStrategyContext();
context.Mode = AlgorithmStrategyMode.auto_mode;
context.IsNeedRestart = false;
context.TriggerScene = NDIViewScene.VideoPanel;
this.AlgorithmControllerDic[this.StrategyType].ChangeAutoMode(context);
}
#endregion
#region RestartCommand -- 算法重启命令
/// <summary>
/// 算法重启命令
/// </summary>
public VCommand RestartCommand { get; set; }
/// <summary>
/// 算法重启
/// </summary>
private void Restart()
{
// 清理视频控件
this.ClearVideoControl();
// 算法重启
this.AlgorithmControllerDic[this.StrategyType].RestartAlgorithm();
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using log4net;
using SharpDX.Mathematics.Interop;
using VIZ.Framework.Common;
using VIZ.Framework.Connection;
using VIZ.Framework.Core;
using VIZ.H2V.Connection;
using VIZ.H2V.Domain;
using VIZ.H2V.Storage;
namespace VIZ.H2V.Module
{
/// <summary>
/// NDI视图模型 -- 手动逻辑 & NDI逻辑
/// </summary>
public partial class NDIViewModel
{
/// <summary>
/// 重置3D鼠标
/// </summary>
public void Reset3DMouse()
{
NDIView view = this.GetView<NDIView>();
if (view == null)
return;
VideoRenderInfo renderInfo = view.video.GetRenderInfo();
if (renderInfo == null)
{
view.video.ClearClipBox();
return;
}
if (this.ClipBoxX == null)
{
this.ClipBoxX = renderInfo.Frame.Width / 2d - this.CLIP_BOX_WIDTH / 2d;
}
double p = (renderInfo.Frame.Width - this.CLIP_BOX_WIDTH) / (2 * Navigation3DManager.Navigation3DModel.MaxX);
double x = this.ClipBoxX.Value / p - Navigation3DManager.Navigation3DModel.MaxX;
Navigation3DManager.Navigation3DModel.Reset(x);
}
/// <summary>
/// 初始化手动模式
/// </summary>
private void InitManual()
{
// 注册WPF渲染事件,用于处理3D鼠标
CompositionTarget.Rendering -= CompositionTarget_Rendering;
CompositionTarget.Rendering += CompositionTarget_Rendering;
}
/// <summary>
/// 加载 -- 初始化NDI
/// </summary>
private void LoadedNDI()
{
this.NDIStream = VideoStreamManager.Get<NDIStream>(this.ViewKey);
this.NDIStream.ExecuteVideoFrame -= NDIStream_ExecuteVideoFrame;
this.NDIStream.ExecuteVideoFrame += NDIStream_ExecuteVideoFrame;
this.NDIStream.Start();
}
/// <summary>
/// WPF渲染事件
/// </summary>
private void CompositionTarget_Rendering(object sender, EventArgs e)
{
// 仅手动模式下处理 且 需要进行裁切时才处理
if (this.StrategyMode != AlgorithmStrategyMode.manual_mode || !this.IsUseClip)
return;
this.UpdateClipBoxWithManual();
}
/// <summary>
/// 手动模式更新裁切框
/// </summary>
private void UpdateClipBoxWithManual()
{
NDIView view = this.GetView<NDIView>();
if (view == null)
return;
VideoRenderInfo renderInfo = view.video.GetRenderInfo();
if (renderInfo == null || this.StrategyMode != AlgorithmStrategyMode.manual_mode || !this.IsUseClip)
{
view.video.ClearClipBox();
return;
}
double p = (renderInfo.Frame.Width - this.CLIP_BOX_WIDTH) / (2 * Navigation3DManager.Navigation3DModel.MaxX);
Navigation3DManager.Navigation3DModel.UpdateSmooth();
if (this.ClipBoxX == null)
{
this.ClipBoxX = renderInfo.Frame.Width / 2d - this.CLIP_BOX_WIDTH / 2d;
}
this.ClipBoxX = (Navigation3DManager.Navigation3DModel.SmoothCamera.Position.X + Navigation3DManager.Navigation3DModel.MaxX) * p;
ClipBoxInfo clipBox = new ClipBoxInfo();
clipBox.DrawingBorderWidth = this.CLIP_BOX_BORDER_WIDTH;
clipBox.SrcRect = new RawRectangleF((float)(this.ClipBoxX ?? 0), 0, (float)(this.ClipBoxX ?? 0) + (float)this.CLIP_BOX_WIDTH, renderInfo.Frame.Height);
clipBox.DrawingBorderColor = this.StrategyMode == AlgorithmStrategyMode.manual_mode ? this.ClipBoxStrokeColor_Manual : this.ClipBoxStrokeColor_Normal;
clipBox.MaskColor = this.CLIP_BOX_MASK_COLOR;
view.video.UpdateClipBox(clipBox);
}
/// <summary>
/// 处理NDI流帧
/// </summary>
private void NDIStream_ExecuteVideoFrame(object sender, VideoFrameEventArgs e)
{
NDIView view = this.GetView<NDIView>();
if (view == null)
return;
view.video.UpdateVideoFrame(e.Frame);
// 如果当前模式为手动模式且处于接收裁切信号状态,并且需要进行裁切,那么发送手动裁切信号
if (e.Frame != null && this.ViewConfig.StrategyMode == AlgorithmStrategyMode.manual_mode && this.ViewStatus == NDIViewStatus.CropRoi && this.IsUseClip)
{
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.ViewKey);
if (manager == null)
return;
AlgorithmSender.ManualMode(manager, this.ID, this.ViewConfig.IsSendToCrop, this.GetManulRoi());
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using SharpDX.Mathematics.Interop;
using VIZ.Framework.Common;
using VIZ.Framework.Core;
using VIZ.Framework.Storage;
using VIZ.H2V.Domain;
using VIZ.H2V.Storage;
namespace VIZ.H2V.Module
{
/// <summary>
/// NDI视图模型 -- 消息部分
/// </summary>
public partial class NDIViewModel
{
/// <summary>
/// 处理算法切换至手动消息
/// </summary>
/// <param name="msg">消息</param>
private void OnAlgorithmStrategyChangedToManualMessage(AlgorithmStrategyChangedToManualMessage msg)
{
if (msg.Source == this)
return;
this.IsManualModeEnabled = !msg.IsChangedToManual;
}
/// <summary>
/// 处理算法初始化完成消息
/// </summary>
/// <param name="msg">消息</param>
private void OnAlgorithmMessage__checked_ok(AlgorithmMessage__checked_ok msg)
{
// 算法ID与视图绑定一一对应
if (msg.AlgorithmID != this.ID)
return;
// 执行初始化完成
if (!this.AlgorithmControllerDic.TryGetValue(this.StrategyType, out IAlgorithmController controller))
return;
if (!this.IsUseClip)
{
this.ViewStatus = NDIViewStatus.CropRoi;
controller.ChangeNoMode();
}
else
{
// 根据当前模式处理
switch (this.StrategyMode)
{
case AlgorithmStrategyMode.center_mode:
this.ViewStatus = NDIViewStatus.CropRoi;
controller.ChangeCenterMode();
break;
case AlgorithmStrategyMode.manual_mode:
this.ViewStatus = NDIViewStatus.CropRoi;
controller.ChangeManualMode();
break;
case AlgorithmStrategyMode.auto_mode:
controller.CheckOk();
break;
}
}
// 校验当前手动模式选项是否可用
List<INDIViewService> services = ApplicationDomainEx.ServiceManager.GetServiceList<INDIViewService>();
INDIViewService service = services.FirstOrDefault(p => p.ViewConfig.StrategyMode == AlgorithmStrategyMode.manual_mode);
this.IsManualModeEnabled = service == null || service == this;
}
/// <summary>
/// 处理算法跟踪消息
/// </summary>
/// <param name="msg">消息</param>
private void OnAlgorithmMessage__detect(AlgorithmMessage__detect msg)
{
// 算法ID与视图绑定一一对应
if (msg.AlgorithmID != this.ID)
return;
// 如果当前视图状态不处于目标检测状态,那么不处理目标检测消息
if (this.ViewConfig.StrategyMode != AlgorithmStrategyMode.auto_mode || this.ViewStatus != NDIViewStatus.Detect)
return;
NDIView view = this.GetView<NDIView>();
if (view == null)
return;
VideoRenderInfo renderInfo = view.video.GetRenderInfo();
if (renderInfo == null)
return;
// 刷新跟踪框
List<TrackingBoxInfo> infos = new List<TrackingBoxInfo>();
if (msg.bboxes != null)
{
foreach (RawRectangleF item in msg.bboxes)
{
RawRectangleF rect = RawRectangleFExpand.ClipInVideoFrame(item, 0, 0, renderInfo.Frame.Width, renderInfo.Frame.Height);
if (!RawRectangleFExpand.IsEffective(rect))
continue;
TrackingBoxInfo info = new TrackingBoxInfo();
info.SrcRect = rect;
info.DrawingBorderWidth = this.TRACKING_BOX_BORDER_WIDTH;
info.DrawingBorderColor = this.TRACKING_BOX_BORDER_COLOR;
infos.Add(info);
}
}
view.video.UpdateTrackingBox(infos);
}
/// <summary>
/// 处理算法裁剪消息
/// </summary>
/// <param name="msg">消息</param>
private void OnAlgorithmMessage__crop_roi(AlgorithmMessage__crop_roi msg)
{
// 算法ID与视图绑定一一对应
if (msg.AlgorithmID != this.ID)
return;
// 如果当前视图状态不处于裁切状态,那么不处理裁切消息
if (!this.ViewConfig.IsUseClip || this.ViewConfig.StrategyMode == AlgorithmStrategyMode.manual_mode || this.ViewStatus != NDIViewStatus.CropRoi)
return;
NDIView view = this.GetView<NDIView>();
if (view == null)
return;
VideoRenderInfo renderInfo = view.video.GetRenderInfo();
if (renderInfo == null)
return;
// 更新裁切框
if (msg.roi != null)
{
RawRectangleF rect = RawRectangleFExpand.ClipInVideoFrame(msg.roi.Value, 0, 0, renderInfo.Frame.Width, renderInfo.Frame.Height);
if (RawRectangleFExpand.IsEffective(rect))
{
ClipBoxInfo info = new ClipBoxInfo();
info.SrcRect = rect;
info.DrawingBorderWidth = (float)this.CLIP_BOX_BORDER_WIDTH;
info.DrawingBorderColor = this.StrategyMode == AlgorithmStrategyMode.manual_mode ? this.ClipBoxStrokeColor_Manual : this.ClipBoxStrokeColor_Normal;
info.MaskColor = this.CLIP_BOX_MASK_COLOR;
this.ClipBoxX = rect.Left;
view.video.UpdateClipBox(info);
}
else
{
view.video.ClearClipBox();
}
}
else
{
view.video.ClearClipBox();
}
// 更新跟踪框
if (msg.target_bbox != null)
{
RawRectangleF rect = RawRectangleFExpand.ClipInVideoFrame(msg.target_bbox.Value, 0, 0, renderInfo.Frame.Width, renderInfo.Frame.Height);
if (RawRectangleFExpand.IsEffective(rect))
{
TrackingBoxInfo info = new TrackingBoxInfo();
info.SrcRect = msg.target_bbox.Value;
info.DrawingBorderWidth = this.TRACKING_BOX_BORDER_WIDTH;
info.DrawingBorderColor = this.TRACKING_BOX_BORDER_COLOR;
view.video.UpdateTrackingBox(new List<TrackingBoxInfo> { info });
}
else
{
view.video.ClearTrackingBox();
}
}
else
{
view.video.ClearTrackingBox();
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using SharpDX.Mathematics.Interop;
using VIZ.Framework.Common;
using VIZ.Framework.Storage;
using VIZ.H2V.Domain;
using VIZ.H2V.Storage;
namespace VIZ.H2V.Module
{
/// <summary>
/// NDI视图模型
/// </summary>
public partial class NDIViewModel
{
// ======================================================================================
// === Field ===
// ======================================================================================
/// <summary>
/// NDI流
/// </summary>
private NDIStream NDIStream;
/// <summary>
/// 剪切框宽度
/// </summary>
private readonly double CLIP_BOX_WIDTH = ApplicationDomainEx.IniStorage.GetValue<VideoConfig, double>(p => p.VIDEO_CLIP_BOX_WIDTH);
/// <summary>
/// 剪切框宽度
/// </summary>
private readonly int CLIP_BOX_BORDER_WIDTH = ApplicationDomainEx.IniStorage.GetValue<VideoConfig, int>(p => p.VIDEO_CLIP_BOX_BORDER_WIDTH);
/// <summary>
/// 剪切框掩码颜色
/// </summary>
private readonly RawColor4 CLIP_BOX_MASK_COLOR = ApplicationDomainEx.IniStorage.GetValue<VideoConfig, RawColor4>(p => p.VIDEO_CLIP_BOX_MASK_COLOR);
/// <summary>
/// 追踪框颜色
/// </summary>
private readonly RawColor4 TRACKING_BOX_BORDER_COLOR = ApplicationDomainEx.IniStorage.GetValue<VideoConfig, RawColor4>(p => p.VIDEO_TRACKING_BOX_BORDER_COLOR);
/// <summary>
/// 追踪框宽度
/// </summary>
private readonly int TRACKING_BOX_BORDER_WIDTH = ApplicationDomainEx.IniStorage.GetValue<VideoConfig, int>(p => p.VIDEO_TRACKING_BOX_BORDER_WIDTH);
/// <summary>
/// 剪切框颜色 -- 正常
/// </summary>
private RawColor4 ClipBoxStrokeColor_Normal;
/// <summary>
/// 剪切框颜色 -- 异常
/// </summary>
private RawColor4 ClipBoxStrokeColor_Exception;
/// <summary>
/// 剪切框颜色 -- 手动
/// </summary>
private RawColor4 ClipBoxStrokeColor_Manual;
// ======================================================================================
// === Controller ===
// ======================================================================================
/// <summary>
/// 算法控制器集合
/// </summary>
private readonly Dictionary<AlgorithmStrategyType, IAlgorithmController> AlgorithmControllerDic = new Dictionary<AlgorithmStrategyType, IAlgorithmController>();
// ======================================================================================
// === Property ===
// ======================================================================================
#region ID -- ID
private string id;
/// <summary>
/// 算法ID
/// </summary>
public string ID
{
get { return id; }
set { id = value; this.RaisePropertyChanged(nameof(ID)); }
}
#endregion
#region ViewKey -- NDI视图键
private string viewKey;
/// <summary>
/// NDI视图键
/// </summary>
public string ViewKey
{
get { return viewKey; }
set { viewKey = value; this.RaisePropertyChanged(nameof(ViewKey)); }
}
#endregion
#region ViewConfig -- 视图配置
private NdiViewConfig viewConfig;
/// <summary>
/// 视图配置
/// </summary>
public NdiViewConfig ViewConfig
{
get { return viewConfig; }
set { viewConfig = value; this.RaisePropertyChanged(nameof(ViewConfig)); }
}
#endregion
#region DisplayName -- 显示名称
private string displayName;
/// <summary>
/// 显示名称
/// </summary>
public string DisplayName
{
get { return displayName; }
set { displayName = value; this.RaisePropertyChanged(nameof(DisplayName)); }
}
#endregion
#region StrategyDisplayName -- 算法策略显示名称
private string strategyDisplayName;
/// <summary>
/// 算法策略显示名称
/// </summary>
public string StrategyDisplayName
{
get { return strategyDisplayName; }
set { strategyDisplayName = value; this.RaisePropertyChanged(nameof(StrategyDisplayName)); }
}
#endregion
#region StrategyMode -- 算法模式
private AlgorithmStrategyMode strategyMode;
/// <summary>
/// 剪切策略
/// </summary>
public AlgorithmStrategyMode StrategyMode
{
get { return strategyMode; }
set { strategyMode = value; this.RaisePropertyChanged(nameof(StrategyMode)); }
}
#endregion
#region StrategyType -- 算法类型
private AlgorithmStrategyType strategyType = AlgorithmStrategyType.Single;
/// <summary>
/// 算法类型
/// </summary>
public AlgorithmStrategyType StrategyType
{
get { return strategyType; }
set { strategyType = value; this.RaisePropertyChanged(nameof(StrategyType)); }
}
#endregion
#region ViewStatus -- NDI视图状态
private NDIViewStatus viewStatus = NDIViewStatus.Stop;
/// <summary>
/// NDI视图状态
/// </summary>
public NDIViewStatus ViewStatus
{
get { return viewStatus; }
set { viewStatus = value; this.RaisePropertyChanged(nameof(ViewStatus)); }
}
#endregion
#region ProcessModel -- 算法进程模型
private AlgorithmProcessModel processModel = new AlgorithmProcessModel();
/// <summary>
/// 算法进程模型
/// </summary>
public AlgorithmProcessModel ProcessModel
{
get { return processModel; }
set { processModel = value; this.RaisePropertyChanged(nameof(ProcessModel)); }
}
#endregion
#region ClipBoxX -- 裁切框X坐标
private double? clipBoxX;
/// <summary>
/// 裁切框X坐标
/// </summary>
public double? ClipBoxX
{
get { return clipBoxX; }
set { clipBoxX = value; this.RaisePropertyChanged(nameof(ClipBoxX)); }
}
#endregion
// --------------------------------------------------------------------------------------
#region IsUseClip -- 是否使用裁切
private bool isUseClip;
/// <summary>
/// 是否使用裁切
/// </summary>
public bool IsUseClip
{
get { return isUseClip; }
set
{
isUseClip = value;
this.RaisePropertyChanged(nameof(IsUseClip));
ChangeStrategyContext context = new ChangeStrategyContext();
context.IsUseClip = value;
context.Mode = this.StrategyMode;
context.IsNeedRestart = false;
context.TriggerScene = NDIViewScene.VideoPanel;
this.ChangeStrategyMode(context);
}
}
#endregion
#region IsAutoModeChecked -- 自动模式是否选中
private bool isAutoModeChecked;
/// <summary>
/// 自动模式是否选中
/// </summary>
public bool IsAutoModeChecked
{
get { return isAutoModeChecked; }
set
{
isAutoModeChecked = value;
this.RaisePropertyChanged(nameof(IsAutoModeChecked));
if (!value)
return;
ChangeStrategyContext context = new ChangeStrategyContext();
context.IsUseClip = this.IsUseClip;
context.Mode = AlgorithmStrategyMode.auto_mode;
context.IsNeedRestart = false;
context.TriggerScene = NDIViewScene.VideoPanel;
this.ChangeStrategyMode(context);
}
}
#endregion
#region IsCenterModeChecked -- 居中模式是否选中
private bool isCenterModeChecked;
/// <summary>
/// 居中模式是否选中
/// </summary>
public bool IsCenterModeChecked
{
get { return isCenterModeChecked; }
set
{
isCenterModeChecked = value;
this.RaisePropertyChanged(nameof(IsCenterModeChecked));
if (!value)
return;
ChangeStrategyContext context = new ChangeStrategyContext();
context.IsUseClip = this.IsUseClip;
context.Mode = AlgorithmStrategyMode.center_mode;
context.IsNeedRestart = false;
context.TriggerScene = NDIViewScene.VideoPanel;
this.ChangeStrategyMode(context);
}
}
#endregion
#region IsManualModeChecked -- 手动模式是否选中
private bool isManualModeChecked;
/// <summary>
/// 手动模式是否选中
/// </summary>
public bool IsManualModeChecked
{
get { return isManualModeChecked; }
set
{
isManualModeChecked = value;
this.RaisePropertyChanged(nameof(IsManualModeChecked));
if (!value)
return;
ChangeStrategyContext context = new ChangeStrategyContext();
context.IsUseClip = this.IsUseClip;
context.Mode = AlgorithmStrategyMode.manual_mode;
context.IsNeedRestart = false;
context.TriggerScene = NDIViewScene.VideoPanel;
this.ChangeStrategyMode(context);
}
}
#endregion
#region IsManualModeEnabled -- 手动模式是否可用
private bool isManualModeEnabled = true;
/// <summary>
/// 手动模式是否可用
/// </summary>
public bool IsManualModeEnabled
{
get { return isManualModeEnabled; }
set { isManualModeEnabled = value; this.RaisePropertyChanged(nameof(IsManualModeEnabled)); }
}
#endregion
}
}
...@@ -3,24 +3,18 @@ using System.Collections.Generic; ...@@ -3,24 +3,18 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using VIZ.Framework.Core; using log4net;
using VIZ.Framework.Common; using VIZ.Framework.Common;
using VIZ.Framework.Core;
using VIZ.H2V.Domain; using VIZ.H2V.Domain;
using SharpDX.Mathematics.Interop;
using VIZ.Framework.Storage;
using System.Windows.Media;
using VIZ.H2V.Storage; using VIZ.H2V.Storage;
using VIZ.Framework.Connection;
using VIZ.H2V.Connection;
using log4net;
using System.Diagnostics;
namespace VIZ.H2V.Module namespace VIZ.H2V.Module
{ {
/// <summary> /// <summary>
/// NDI视图模型 /// NDI视图模型
/// </summary> /// </summary>
public class NDIViewModel : ViewModelBase, INDIViewService, IAlgorithmSupport public partial class NDIViewModel : ViewModelBase, INDIViewService, IAlgorithmSupport
{ {
/// <summary> /// <summary>
/// 日志 /// 日志
...@@ -44,11 +38,11 @@ namespace VIZ.H2V.Module ...@@ -44,11 +38,11 @@ namespace VIZ.H2V.Module
// 初始化控制器 // 初始化控制器
this.InitController(); this.InitController();
// 注册WPF渲染事件,用于处理3D鼠标 // 初始化手动模式
CompositionTarget.Rendering -= CompositionTarget_Rendering; this.InitManual();
CompositionTarget.Rendering += CompositionTarget_Rendering;
} }
/// <summary> /// <summary>
/// 初始化命令 /// 初始化命令
/// </summary> /// </summary>
...@@ -61,6 +55,16 @@ namespace VIZ.H2V.Module ...@@ -61,6 +55,16 @@ namespace VIZ.H2V.Module
} }
/// <summary> /// <summary>
/// 初始化控制器
/// </summary>
private void InitController()
{
this.AlgorithmControllerDic.Add(AlgorithmStrategyType.Single, new AlgorithmController_Single(this));
this.AlgorithmControllerDic.Add(AlgorithmStrategyType.Near, new AlgorithmController_Near(this));
this.AlgorithmControllerDic.Add(AlgorithmStrategyType.Sixteen, new AlgorithmController_Sixteen(this));
}
/// <summary>
/// 初始化消息 /// 初始化消息
/// </summary> /// </summary>
private void InitMessage() private void InitMessage()
...@@ -84,607 +88,83 @@ namespace VIZ.H2V.Module ...@@ -84,607 +88,83 @@ namespace VIZ.H2V.Module
} }
/// <summary> /// <summary>
/// 初始化控制器 /// 切换模式
/// </summary>
private void InitController()
{
this.AlgorithmController = new AlgorithmController(this);
}
// ======================================================================================
// === Field ===
// ======================================================================================
/// <summary>
/// NDI流
/// </summary>
private NDIStream NDIStream;
/// <summary>
/// 剪切框X坐标
/// </summary>
private double? ClipBoxX;
/// <summary>
/// 剪切框宽度
/// </summary>
private readonly double ClipBoxWidth = ApplicationDomainEx.IniStorage.GetValue<VideoConfig, double>(p => p.VIDEO_CLIP_BOX_WIDTH);
/// <summary>
/// 剪切框宽度
/// </summary>
private readonly int ClipBoxBorderWidth = ApplicationDomainEx.IniStorage.GetValue<VideoConfig, int>(p => p.VIDEO_CLIP_BOX_BORDER_WIDTH);
/// <summary>
/// 剪切框掩码颜色
/// </summary>
private readonly RawColor4 ClipBoxMaskColor = ApplicationDomainEx.IniStorage.GetValue<VideoConfig, RawColor4>(p => p.VIDEO_CLIP_BOX_MASK_COLOR);
/// <summary>
/// 追踪框颜色
/// </summary>
private readonly RawColor4 TrackingBoxBorderColor = ApplicationDomainEx.IniStorage.GetValue<VideoConfig, RawColor4>(p => p.VIDEO_TRACKING_BOX_BORDER_COLOR);
/// <summary>
/// 追踪框宽度
/// </summary>
private readonly int TrackingBoxBorderWidth = ApplicationDomainEx.IniStorage.GetValue<VideoConfig, int>(p => p.VIDEO_TRACKING_BOX_BORDER_WIDTH);
/// <summary>
/// 剪切框颜色 -- 正常
/// </summary>
private RawColor4 ClipBoxStrokeColor_Normal;
/// <summary>
/// 剪切框颜色 -- 异常
/// </summary>
private RawColor4 ClipBoxStrokeColor_Exception;
/// <summary>
/// 剪切框颜色 -- 手动
/// </summary>
private RawColor4 ClipBoxStrokeColor_Manual;
// ======================================================================================
// === Controller ===
// ======================================================================================
/// <summary>
/// 算法控制器
/// </summary>
private AlgorithmController AlgorithmController;
// ======================================================================================
// === Property ===
// ======================================================================================
#region AlgorithmID -- 算法ID
private string algorithmID;
/// <summary>
/// 算法ID
/// </summary>
public string AlgorithmID
{
get { return algorithmID; }
set { algorithmID = value; this.RaisePropertyChanged(nameof(AlgorithmID)); }
}
#endregion
#region ViewKey -- NDI视图键
private string viewKey;
/// <summary>
/// NDI视图键
/// </summary>
public string ViewKey
{
get { return viewKey; }
set { viewKey = value; this.RaisePropertyChanged(nameof(ViewKey)); }
}
#endregion
#region ViewConfig -- 视图配置
private NdiViewConfig viewConfig;
/// <summary>
/// 视图配置
/// </summary>
public NdiViewConfig ViewConfig
{
get { return viewConfig; }
set { viewConfig = value; this.RaisePropertyChanged(nameof(ViewConfig)); }
}
#endregion
#region DisplayName -- 显示名称
private string displayName;
/// <summary>
/// 显示名称
/// </summary>
public string DisplayName
{
get { return displayName; }
set { displayName = value; this.RaisePropertyChanged(nameof(DisplayName)); }
}
#endregion
#region AlgorithmStrategyDisplayName -- 算法策略显示名称
private string algorithmStrategyDisplayName;
/// <summary>
/// 算法策略显示名称
/// </summary>
public string AlgorithmStrategyDisplayName
{
get { return algorithmStrategyDisplayName; }
set { algorithmStrategyDisplayName = value; this.RaisePropertyChanged(nameof(AlgorithmStrategyDisplayName)); }
}
#endregion
#region AlgorithmStrategyMode -- 算法模式
private AlgorithmStrategyMode algorithmStrategyMode;
/// <summary>
/// 剪切策略
/// </summary>
public AlgorithmStrategyMode AlgorithmStrategyMode
{
get { return algorithmStrategyMode; }
set
{
// 如果将要切换为无模式,那么缓存之前的值(之前值不应该是无模式)
if (value == AlgorithmStrategyMode.no_mode && this.algorithmStrategyMode != AlgorithmStrategyMode.no_mode)
{
this.ViewConfig.CacheStrategyMode = this.algorithmStrategyMode;
ApplicationDomainEx.LiteDbContext.ViewConfig.Update(this.ViewConfig);
}
algorithmStrategyMode = value;
this.RaisePropertyChanged(nameof(AlgorithmStrategyMode));
this.ChangeMode();
}
}
#endregion
#region ViewStatus -- NDI视图状态
private NDIViewStatus viewStatus = NDIViewStatus.AlgorithmStop;
/// <summary>
/// NDI视图状态
/// </summary>
public NDIViewStatus ViewStatus
{
get { return viewStatus; }
set { viewStatus = value; this.RaisePropertyChanged(nameof(ViewStatus)); }
}
#endregion
#region AlgorithmProcessModel -- 算法进程模型
private AlgorithmProcessModel algorithmProcessModel = new AlgorithmProcessModel();
/// <summary>
/// 算法进程模型
/// </summary>
public AlgorithmProcessModel AlgorithmProcessModel
{
get { return algorithmProcessModel; }
set { algorithmProcessModel = value; this.RaisePropertyChanged(nameof(AlgorithmProcessModel)); }
}
#endregion
#region IsDetectButtonVisible -- 检测按钮是否可见
private bool isDetectButtonVisible;
/// <summary>
/// 检测按钮是否可见
/// </summary>
public bool IsDetectButtonVisible
{
get { return isDetectButtonVisible; }
set { isDetectButtonVisible = value; this.RaisePropertyChanged(nameof(IsDetectButtonVisible)); }
}
#endregion
// --------------------------------------------------------------------------------------
#region IsNotNoModeChecked -- 非无模式是否选中
private bool isNotNoModeChecked = true;
/// <summary>
/// 非无模式是否选中
/// </summary> /// </summary>
public bool IsNotNoModeChecked /// <param name="context">切换模式上下文</param>
public void ChangeStrategyMode(ChangeStrategyContext context)
{ {
get { return isNotNoModeChecked; } if (!this.AlgorithmControllerDic.TryGetValue(this.StrategyType, out IAlgorithmController controller))
set
{ {
isNotNoModeChecked = value; log.Error($"algorithm strategy [ type: {this.StrategyType} desc: {this.StrategyType.GetDescription()} ] no controller.");
this.RaisePropertyChanged(nameof(IsNotNoModeChecked)); return;
if (value)
{
// 如果使用非无模式,那么切换为缓存模式
this.AlgorithmStrategyMode = this.ViewConfig.CacheStrategyMode;
}
else
{
// 否则切换为无模式
this.AlgorithmStrategyMode = AlgorithmStrategyMode.no_mode;
}
} }
}
#endregion // ----------------------------------------------------------------------------------------------
// Step 1. 更新属性 & 缓存
// ----------------------------------------------------------------------------------------------
#region IsAutoModeChecked -- 自动模式是否选中 // 设置当前模式
this.StrategyMode = context.Mode;
this.ViewConfig.StrategyMode = context.Mode;
this.ViewConfig.IsUseClip = this.IsUseClip;
ApplicationDomainEx.LiteDbContext.ViewConfig.Update(this.ViewConfig);
private bool isAutoModeChecked; // ----------------------------------------------------------------------------------------------
/// <summary> // Step 2. 清理界面状态 & 发送手动裁切消息
/// 自动模式是否选中 // ----------------------------------------------------------------------------------------------
/// </summary>
public bool IsAutoModeChecked
{
get { return isAutoModeChecked; }
set
{
isAutoModeChecked = value;
this.RaisePropertyChanged(nameof(IsAutoModeChecked));
if (value)
{
this.AlgorithmStrategyMode = AlgorithmStrategyMode.auto_mode;
}
}
}
#endregion
#region IsCenterModeChecked -- 居中模式是否选中 // 清理视频控件
this.ClearVideoControl();
private bool isCenterModeChecked; // 发送切换手动消息
/// <summary> AlgorithmStrategyChangedToManualMessage msg = new AlgorithmStrategyChangedToManualMessage();
/// 居中模式是否选中 msg.Source = this;
/// </summary> msg.IsChangedToManual = this.StrategyMode == AlgorithmStrategyMode.manual_mode;
public bool IsCenterModeChecked ApplicationDomainEx.MessageManager.Send(msg);
{
get { return isCenterModeChecked; }
set
{
isCenterModeChecked = value;
this.RaisePropertyChanged(nameof(IsCenterModeChecked));
if (value)
{
this.AlgorithmStrategyMode = AlgorithmStrategyMode.center_mode;
}
}
}
#endregion
#region IsManualModeChecked -- 手动模式是否选中 // ----------------------------------------------------------------------------------------------
// Step 3. 校验视图状态
// ----------------------------------------------------------------------------------------------
private bool isManualModeChecked; // 如果当前状态为停止状态,那么重启算法 || 指定需要重启算法
/// <summary> if (this.ViewStatus == NDIViewStatus.Stop || context.IsNeedRestart)
/// 手动模式是否选中
/// </summary>
public bool IsManualModeChecked
{
get { return isManualModeChecked; }
set
{ {
isManualModeChecked = value; controller.RestartAlgorithm();
this.RaisePropertyChanged(nameof(IsManualModeChecked)); return;
if (value)
{
this.AlgorithmStrategyMode = AlgorithmStrategyMode.manual_mode;
}
} }
}
#endregion
#region IsManualModeEnabled -- 手动模式是否可用
private bool isManualModeEnabled = true;
/// <summary>
/// 手动模式是否可用
/// </summary>
public bool IsManualModeEnabled
{
get { return isManualModeEnabled; }
set { isManualModeEnabled = value; this.RaisePropertyChanged(nameof(IsManualModeEnabled)); }
}
#endregion
// ======================================================================================
// === Command ===
// ======================================================================================
#region LoadedCommand -- 加载命令
/// <summary> // 1. 当前状态处于等待启动、等待停止、等待初始化完成状态是不需要处理的
/// 加载命令 // 2. 算法在CheckOK之后会获取最新的设置,所以不需要后续处理
/// </summary> if (this.ViewStatus == NDIViewStatus.WaitSetup || this.ViewStatus == NDIViewStatus.WaitStop || this.ViewStatus == NDIViewStatus.WaitCheckOK)
public VCommand LoadedCommand { get; set; }
/// <summary>
/// 加载
/// </summary>
private void Loaded()
{
if (this.IsAlreadyLoaded)
return; return;
this.IsAlreadyLoaded = true; // ----------------------------------------------------------------------------------------------
// Step 4. 执行切换
// ----------------------------------------------------------------------------------------------
NDIView view = this.GetView<NDIView>(); if (!this.IsUseClip)
if (view == null) {
this.ViewStatus = NDIViewStatus.CropRoi;
controller.ChangeNoMode();
return; return;
}
// 视图键 else
this.ViewKey = view.NDIKey;
// 初始化视图配置
this.Loaded_ViewConfig();
// 初始化属性
this.Loaded_Property();
// 初始化模式切换
this.Loaded_InitModeChecked();
// 初始化视频控件
this.Loaded_VideoControl(view);
// 初始化NDI
this.Loaded_NDI();
// 加载样式
this.LoadStyle();
// 注册服务
ApplicationDomainEx.ServiceManager.AddService(this.ViewKey, this);
}
/// <summary>
/// 初始化视图配置
/// </summary>
private void Loaded_ViewConfig()
{
NdiViewConfig viewConfig = ApplicationDomainEx.LiteDbContext.ViewConfig.FindOne(p => p.ViewKey == this.ViewKey);
this.ViewConfig = viewConfig;
}
/// <summary>
/// 加载 -- 初始化NDI
/// </summary>
private void Loaded_NDI()
{
this.NDIStream = VideoStreamManager.Get<NDIStream>(this.ViewKey);
this.NDIStream.ExecuteVideoFrame -= NDIStream_ExecuteVideoFrame;
this.NDIStream.ExecuteVideoFrame += NDIStream_ExecuteVideoFrame;
this.NDIStream.Start();
}
/// <summary>
/// 加载 -- 初始化属性
/// </summary>
private void Loaded_Property()
{
AlgorithmStrategy strategy = ApplicationDomainEx.ExcelContext.AlgorithmStrategys.FirstOrDefault(p => p.ID == (int)this.ViewConfig.StrategyType);
// 算法ID
this.AlgorithmID = $"{NetHelper.GetMacAddress()}__{this.ViewKey}";
// 显示名称
this.DisplayName = this.ViewConfig.DisplayName ?? this.viewKey;
// 算法名称
this.AlgorithmStrategyDisplayName = strategy == null ? this.ViewConfig.StrategyType.GetDescription() : strategy.DisplayName;
}
/// <summary>
/// 加载 -- 初始化视频控件
/// </summary>
/// <param name="view">视图</param>
private void Loaded_VideoControl(NDIView view)
{
// 注册视频控件插件
TrackingBoxPlugin trackingBoxPlugin = new TrackingBoxPlugin(view.video);
trackingBoxPlugin.TrackingBoxClick += TrackingBoxPlugin_TrackingBoxClick;
ClipBoxPlugin clipBoxPlugin = new ClipBoxPlugin(view.video);
view.video.AttachPlugin(trackingBoxPlugin);
view.video.AttachPlugin(clipBoxPlugin);
}
/// <summary>
/// 加载 -- 初始化模式切换
/// </summary>
private void Loaded_InitModeChecked()
{
// 如果当前的模式未无模式,那么更新UI界面的之前的模式选择情况
if (viewConfig.StrategyMode == AlgorithmStrategyMode.no_mode)
{ {
switch (this.ViewConfig.CacheStrategyMode) switch (context.Mode)
{ {
case AlgorithmStrategyMode.no_mode:
break;
case AlgorithmStrategyMode.center_mode: case AlgorithmStrategyMode.center_mode:
this.isCenterModeChecked = true; this.ViewStatus = NDIViewStatus.CropRoi;
this.RaisePropertyChanged(nameof(IsCenterModeChecked)); controller.ChangeCenterMode();
break; break;
case AlgorithmStrategyMode.manual_mode: case AlgorithmStrategyMode.manual_mode:
this.isManualModeChecked = true; this.ViewStatus = NDIViewStatus.CropRoi;
this.RaisePropertyChanged(nameof(IsManualModeChecked)); controller.ChangeManualMode();
break; break;
case AlgorithmStrategyMode.auto_mode: case AlgorithmStrategyMode.auto_mode:
this.isAutoModeChecked = true; controller.ChangeAutoMode(context);
this.RaisePropertyChanged(nameof(IsAutoModeChecked));
break;
default:
break; break;
} }
} }
switch (this.ViewConfig.StrategyMode)
{
case AlgorithmStrategyMode.no_mode:
this.IsNotNoModeChecked = false;
break;
case AlgorithmStrategyMode.center_mode:
this.IsCenterModeChecked = true;
break;
case AlgorithmStrategyMode.manual_mode:
this.IsManualModeChecked = true;
break;
case AlgorithmStrategyMode.auto_mode:
this.IsAutoModeChecked = true;
break;
default:
break;
}
}
#endregion
#region SettingCommand -- 设置命令
/// <summary>
/// 设置命令
/// </summary>
public VCommand<string> SettingCommand { get; set; }
/// <summary>
/// 设置
/// </summary>
/// <param name="key">服务键</param>
private void Setting(string key)
{
NDISettingView view = new NDISettingView(key, this.AlgorithmID);
NoneWindow window = new NoneWindow(1200, 900, view);
window.Owner = this.GetWindow();
window.ShowDialog();
}
#endregion
#region DetectCommand -- 检测命令
/// <summary>
/// 检测命令
/// </summary>
public VCommand DetectCommand { get; set; }
/// <summary>
/// 检测
/// </summary>
public void Detect()
{
// 只有单人机位下的自动模式可以发送检测指令
if (this.AlgorithmStrategyMode != AlgorithmStrategyMode.auto_mode && this.ViewConfig.StrategyType != AlgorithmStrategyType.Single)
return;
this.AlgorithmStrategyMode = AlgorithmStrategyMode.auto_mode;
}
#endregion
#region RestartCommand -- 算法重启命令
/// <summary>
/// 算法重启命令
/// </summary>
public VCommand RestartCommand { get; set; }
/// <summary>
/// 算法重启
/// </summary>
private void Restart()
{
this.UpdateModeAsync(true);
}
#endregion
// ======================================================================================
// === Service ===
// ======================================================================================
/// <summary>
/// 加载样式
/// </summary>
public void LoadStyle()
{
SystemConfig config = ApplicationDomainEx.LiteDbContext.SystemConfig.FindAll().FirstOrDefault();
if (config == null)
{
config = new SystemConfig();
ApplicationDomainEx.LiteDbContext.SystemConfig.Upsert(config);
}
this.ClipBoxStrokeColor_Normal = SharpDxColorHelper.FromString(config.ClipNormalColor);
this.ClipBoxStrokeColor_Exception = SharpDxColorHelper.FromString(config.ClipExceptionColor);
this.ClipBoxStrokeColor_Manual = SharpDxColorHelper.FromString(config.ClipManualColor);
}
/// <summary>
/// 停止算法
/// </summary>
public void StopAlgorithm()
{
this.AlgorithmController.StopAlgorithm();
}
/// <summary>
/// 异步更新模式
/// </summary>
/// <param name="isRestart">是否需要重启</param>
public void UpdateModeAsync(bool isRestart)
{
Task.Run(() =>
{
try
{
if (isRestart)
{
// 如果需要重启那么先停止算法进程
this.AlgorithmController.StopAlgorithm();
}
this.AlgorithmController.ChangeMode(this.AlgorithmStrategyMode);
}
catch (Exception ex)
{
log.Error(ex);
}
});
}
/// <summary>
/// 清理视频控件
/// </summary>
public void ClearVideoControl()
{
WPFHelper.Invoke(() =>
{
NDIView view = this.GetView<NDIView>();
if (view == null)
return;
view.video.ClearTrackingBox();
view.video.ClearClipBox();
});
} }
/// <summary> /// <summary>
...@@ -701,331 +181,48 @@ namespace VIZ.H2V.Module ...@@ -701,331 +181,48 @@ namespace VIZ.H2V.Module
if (renderInfo == null) if (renderInfo == null)
return null; return null;
List<int> roi = new List<int> { (int)(this.ClipBoxX ?? 0), 0, (int)((this.ClipBoxX ?? 0) + this.ClipBoxWidth), renderInfo.Frame.Height }; return new List<int> { (int)(this.ClipBoxX ?? 0), 0, (int)this.CLIP_BOX_WIDTH, renderInfo.Frame.Height };
return roi;
}
// ======================================================================================
// === Message ===
// ======================================================================================
/// <summary>
/// 处理算法切换至手动消息
/// </summary>
/// <param name="msg">消息</param>
private void OnAlgorithmStrategyChangedToManualMessage(AlgorithmStrategyChangedToManualMessage msg)
{
if (msg.Source == this)
return;
this.IsManualModeEnabled = !msg.IsChangedToManual;
} }
/// <summary> /// <summary>
/// 处理算法初始化完成消息 /// 清理视频控件
/// </summary>
/// <param name="msg">消息</param>
private void OnAlgorithmMessage__checked_ok(AlgorithmMessage__checked_ok msg)
{
// 算法ID与视图绑定一一对应
if (msg.AlgorithmID != this.AlgorithmID)
return;
// 当前模式为自动模式,且场景为单人机位需要目标检测,其他机位不需要
if (this.AlgorithmStrategyMode == AlgorithmStrategyMode.auto_mode && this.ViewConfig.StrategyType == AlgorithmStrategyType.Single)
{
this.ViewStatus = NDIViewStatus.AlgorithmDetect;
}
else
{
this.ViewStatus = NDIViewStatus.AlgorithmCropRoi;
}
// 算法初始化完成之后自动切换一次模式
this.AlgorithmController.ChangeMode(this.AlgorithmStrategyMode);
// 校验当前手动模式选项是否可用
List<INDIViewService> services = ApplicationDomainEx.ServiceManager.GetServiceList<INDIViewService>();
INDIViewService service = services.FirstOrDefault(p => p.ViewConfig.StrategyMode == AlgorithmStrategyMode.manual_mode);
this.IsManualModeEnabled = service == null || service == this;
}
/// <summary>
/// 处理算法跟踪消息
/// </summary>
/// <param name="msg">消息</param>
private void OnAlgorithmMessage__detect(AlgorithmMessage__detect msg)
{
// 算法ID与视图绑定一一对应
if (msg.AlgorithmID != this.AlgorithmID)
return;
// 如果当前视图状态不处于目标检测状态,那么不处理目标检测消息
if (this.ViewConfig.StrategyMode != AlgorithmStrategyMode.auto_mode || this.ViewStatus != NDIViewStatus.AlgorithmDetect)
return;
NDIView view = this.GetView<NDIView>();
if (view == null)
return;
VideoRenderInfo renderInfo = view.video.GetRenderInfo();
if (renderInfo == null)
return;
// 刷新跟踪框
List<TrackingBoxInfo> infos = new List<TrackingBoxInfo>();
if (msg.bboxes != null)
{
foreach (RawRectangleF item in msg.bboxes)
{
RawRectangleF rect = RawRectangleFExpand.ClipInVideoFrame(item, 0, 0, renderInfo.Frame.Width, renderInfo.Frame.Height);
if (!RawRectangleFExpand.IsEffective(rect))
continue;
TrackingBoxInfo info = new TrackingBoxInfo();
info.SrcRect = rect;
info.DrawingBorderWidth = this.TrackingBoxBorderWidth;
info.DrawingBorderColor = this.TrackingBoxBorderColor;
infos.Add(info);
}
}
view.video.UpdateTrackingBox(infos);
}
/// <summary>
/// 处理算法裁剪消息
/// </summary> /// </summary>
/// <param name="msg">消息</param> public void ClearVideoControl()
private void OnAlgorithmMessage__crop_roi(AlgorithmMessage__crop_roi msg)
{ {
// 算法ID与视图绑定一一对应 WPFHelper.Invoke(() =>
if (msg.AlgorithmID != this.AlgorithmID)
return;
// 如果当前视图状态不处于裁切状态,那么不处理裁切消息
if (this.ViewConfig.StrategyMode == AlgorithmStrategyMode.no_mode
|| this.ViewConfig.StrategyMode == AlgorithmStrategyMode.manual_mode
|| this.ViewStatus != NDIViewStatus.AlgorithmCropRoi)
return;
NDIView view = this.GetView<NDIView>();
if (view == null)
return;
VideoRenderInfo renderInfo = view.video.GetRenderInfo();
if (renderInfo == null)
return;
// 更新裁切框
if (msg.roi != null)
{
RawRectangleF rect = RawRectangleFExpand.ClipInVideoFrame(msg.roi.Value, 0, 0, renderInfo.Frame.Width, renderInfo.Frame.Height);
if (RawRectangleFExpand.IsEffective(rect))
{
ClipBoxInfo info = new ClipBoxInfo();
info.SrcRect = rect;
info.DrawingBorderWidth = (float)this.ClipBoxBorderWidth;
info.DrawingBorderColor = this.AlgorithmStrategyMode == AlgorithmStrategyMode.manual_mode ? this.ClipBoxStrokeColor_Manual : this.ClipBoxStrokeColor_Normal;
info.MaskColor = this.ClipBoxMaskColor;
this.ClipBoxX = rect.Left;
view.video.UpdateClipBox(info);
}
else
{
view.video.ClearClipBox();
}
}
else
{
view.video.ClearClipBox();
}
// 更新跟踪框
if (msg.target_bbox != null)
{ {
RawRectangleF rect = RawRectangleFExpand.ClipInVideoFrame(msg.target_bbox.Value, 0, 0, renderInfo.Frame.Width, renderInfo.Frame.Height); NDIView view = this.GetView<NDIView>();
if (view == null)
if (RawRectangleFExpand.IsEffective(rect)) return;
{
TrackingBoxInfo info = new TrackingBoxInfo();
info.SrcRect = msg.target_bbox.Value;
info.DrawingBorderWidth = this.TrackingBoxBorderWidth;
info.DrawingBorderColor = this.TrackingBoxBorderColor;
view.video.UpdateTrackingBox(new List<TrackingBoxInfo> { info });
}
else
{
view.video.ClearTrackingBox();
}
}
else
{
view.video.ClearTrackingBox(); view.video.ClearTrackingBox();
}
}
// ======================================================================================
// === Private Function ===
// ======================================================================================
/// <summary>
/// 处理NDI流帧
/// </summary>
private void NDIStream_ExecuteVideoFrame(object sender, VideoFrameEventArgs e)
{
NDIView view = this.GetView<NDIView>();
if (view == null)
return;
view.video.UpdateVideoFrame(e.Frame);
// 如果当前模式为手动模式且处于接收裁切信号状态,那么发送手动裁切信号
if (e.Frame != null && this.ViewConfig.StrategyMode == AlgorithmStrategyMode.manual_mode && this.ViewStatus == NDIViewStatus.AlgorithmCropRoi)
{
this.SendManualModeSignal(e.Frame);
}
}
/// <summary>
/// WPF渲染事件
/// </summary>
private void CompositionTarget_Rendering(object sender, EventArgs e)
{
// 仅手动模式下处理
if (this.AlgorithmStrategyMode != AlgorithmStrategyMode.manual_mode)
return;
this.UpdateClipBoxWithManual();
}
/// <summary>
/// 手动模式更新裁切框
/// </summary>
private void UpdateClipBoxWithManual()
{
NDIView view = this.GetView<NDIView>();
if (view == null)
return;
VideoRenderInfo renderInfo = view.video.GetRenderInfo();
if (renderInfo == null || this.AlgorithmStrategyMode != AlgorithmStrategyMode.manual_mode)
{
view.video.ClearClipBox(); view.video.ClearClipBox();
return; });
}
double p = (renderInfo.Frame.Width - this.ClipBoxWidth) / (2 * Navigation3DManager.Navigation3DModel.MaxX);
Navigation3DManager.Navigation3DModel.UpdateSmooth();
if (this.ClipBoxX == null)
{
this.ClipBoxX = renderInfo.Frame.Width / 2d - this.ClipBoxWidth / 2d;
}
this.ClipBoxX = (Navigation3DManager.Navigation3DModel.SmoothCamera.Position.X + Navigation3DManager.Navigation3DModel.MaxX) * p;
ClipBoxInfo clipBox = new ClipBoxInfo();
clipBox.DrawingBorderWidth = this.ClipBoxBorderWidth;
clipBox.SrcRect = new RawRectangleF((float)(this.ClipBoxX ?? 0), 0, (float)(this.ClipBoxX ?? 0) + (float)this.ClipBoxWidth, renderInfo.Frame.Height);
clipBox.DrawingBorderColor = this.AlgorithmStrategyMode == AlgorithmStrategyMode.manual_mode ? this.ClipBoxStrokeColor_Manual : this.ClipBoxStrokeColor_Normal;
clipBox.MaskColor = this.ClipBoxMaskColor;
view.video.UpdateClipBox(clipBox);
}
/// <summary>
/// 发送剪切算法切换至手动消息
/// </summary>
private void SendAlgorithmStrategyChangedToManualMessage()
{
AlgorithmStrategyChangedToManualMessage msg = new AlgorithmStrategyChangedToManualMessage();
msg.Source = this;
msg.IsChangedToManual = this.AlgorithmStrategyMode == AlgorithmStrategyMode.manual_mode;
ApplicationDomainEx.MessageManager.Send(msg);
} }
/// <summary> /// <summary>
/// 切换模 /// 加载样
/// </summary> /// </summary>
private void ChangeMode() public void LoadStyle()
{ {
if (AlgorithmStrategyMode == AlgorithmStrategyMode.manual_mode) SystemConfig config = ApplicationDomainEx.LiteDbContext.SystemConfig.FindAll().FirstOrDefault();
if (config == null)
{ {
// 如果切换为手动模式那么需要 重置3D鼠标 config = new SystemConfig();
this.Reset3DMouse(); ApplicationDomainEx.LiteDbContext.SystemConfig.Upsert(config);
} }
// 切换模式 this.ClipBoxStrokeColor_Normal = SharpDxColorHelper.FromString(config.ClipNormalColor);
this.AlgorithmController.ChangeMode(this.AlgorithmStrategyMode); this.ClipBoxStrokeColor_Exception = SharpDxColorHelper.FromString(config.ClipExceptionColor);
this.ClipBoxStrokeColor_Manual = SharpDxColorHelper.FromString(config.ClipManualColor);
// 发送剪切算法切换至手动消息
this.SendAlgorithmStrategyChangedToManualMessage();
// 更新剪切框
this.UpdateClipBoxWithManual();
}
/// <summary>
/// 视频控件跟踪框点击事件
/// </summary>
private void TrackingBoxPlugin_TrackingBoxClick(object sender, TrackingBoxClickEventArgs e)
{
TrackingBoxInfo box = e.HitTrackingBoxInfos.FirstOrDefault();
if (box == null)
return;
// 只有在自动模式的单人机位策略下才可以使用目标点击跟踪功能
if (this.ViewConfig.StrategyMode != AlgorithmStrategyMode.auto_mode || this.ViewConfig.StrategyType != AlgorithmStrategyType.Single)
return;
List<int> bbox = new List<int> { (int)box.SrcRect.Left, (int)box.SrcRect.Top, (int)box.SrcRect.Right, (int)box.SrcRect.Bottom };
this.AlgorithmController.ChangeAutoModeTracking(bbox);
}
/// <summary>
/// 发送手动裁切信号
/// </summary>
private void SendManualModeSignal(IVideoFrame frame)
{
List<int> roi = new List<int> { (int)(this.ClipBoxX ?? 0), 0, (int)((this.ClipBoxX ?? 0) + this.ClipBoxWidth), frame.Height };
this.AlgorithmController.ChangeManualMode(roi);
} }
/// <summary> /// <summary>
/// 重置3D鼠标 /// 停止算法
/// </summary> /// </summary>
private void Reset3DMouse() public void StopAlgorithm()
{ {
NDIView view = this.GetView<NDIView>(); this.AlgorithmControllerDic[this.StrategyType].StopAlgorithm();
if (view == null)
return;
VideoRenderInfo renderInfo = view.video.GetRenderInfo();
if (renderInfo == null)
{
view.video.ClearClipBox();
return;
}
if (this.ClipBoxX == null)
{
this.ClipBoxX = renderInfo.Frame.Width / 2d - this.ClipBoxWidth / 2d;
}
double p = (renderInfo.Frame.Width - this.ClipBoxWidth) / (2 * Navigation3DManager.Navigation3DModel.MaxX);
double x = this.ClipBoxX.Value / p - Navigation3DManager.Navigation3DModel.MaxX;
Navigation3DManager.Navigation3DModel.Reset(x);
} }
} }
} }
\ No newline at end of file
...@@ -153,8 +153,19 @@ ...@@ -153,8 +153,19 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="NDISettingView\ViewModel\INDISetting.cs" /> <Compile Include="NDISettingView\ViewModel\INDISetting.cs" />
<Compile Include="NDIView\Controller\Algorithm\AlgorithmController.cs" /> <Compile Include="NDIView\Controller\Algorithm\AlgorithmControllerBase.cs" />
<Compile Include="NDIView\Controller\Algorithm\IAlgorithmController.cs" />
<Compile Include="NDIView\Controller\Algorithm\IAlgorithmSupport.cs" /> <Compile Include="NDIView\Controller\Algorithm\IAlgorithmSupport.cs" />
<Compile Include="NDIView\Controller\Algorithm\Strategy\AlgorithmController_Sixteen.cs" />
<Compile Include="NDIView\Controller\Algorithm\Strategy\AlgorithmController_Near.cs" />
<Compile Include="NDIView\Controller\Algorithm\Strategy\AlgorithmController_Single.cs" />
<Compile Include="NDIView\Enum\NDIViewScene.cs" />
<Compile Include="NDIView\Info\ChangeStrategyContext.cs" />
<Compile Include="NDIView\VieweModel\NDIViewModel.Command.cs" />
<Compile Include="NDIView\VieweModel\NDIViewModel.Manual_NDI.cs" />
<Compile Include="NDIView\VieweModel\NDIViewModel.Message.cs" />
<Compile Include="NDIView\VieweModel\NDIViewModel.Property.cs" />
<Compile Include="NDIView\VieweModel\NDIViewModel.cs" />
<Compile Include="Setup\Provider\AppSetup_StopAlgorithm.cs" /> <Compile Include="Setup\Provider\AppSetup_StopAlgorithm.cs" />
<Compile Include="Setup\Provider\AppSetup_InitUDP.cs" /> <Compile Include="Setup\Provider\AppSetup_InitUDP.cs" />
<Compile Include="SystemSetting\ViewModel\AboutPanelViewModel.cs" /> <Compile Include="SystemSetting\ViewModel\AboutPanelViewModel.cs" />
...@@ -200,7 +211,6 @@ ...@@ -200,7 +211,6 @@
<DependentUpon>NDISettingView.xaml</DependentUpon> <DependentUpon>NDISettingView.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="NDIView\Service\INDIViewService.cs" /> <Compile Include="NDIView\Service\INDIViewService.cs" />
<Compile Include="NDIView\VieweModel\NDIViewModel.cs" />
<Compile Include="NDIView\View\NDIView.xaml.cs"> <Compile Include="NDIView\View\NDIView.xaml.cs">
<DependentUpon>NDIView.xaml</DependentUpon> <DependentUpon>NDIView.xaml</DependentUpon>
</Compile> </Compile>
......
...@@ -13,24 +13,21 @@ namespace VIZ.H2V.Storage ...@@ -13,24 +13,21 @@ namespace VIZ.H2V.Storage
public enum AlgorithmStrategyMode public enum AlgorithmStrategyMode
{ {
/// <summary> /// <summary>
/// 模式 /// 算法模式
/// </summary> /// </summary>
[Description("无模式")] [Description("算法模式")]
no_mode = 0, auto_mode = 0,
/// <summary> /// <summary>
/// 居中模式 /// 居中模式
/// </summary> /// </summary>
[Description("居中模式")] [Description("居中模式")]
center_mode = 1, center_mode = 1,
/// <summary> /// <summary>
/// 手动模式 /// 手动模式
/// </summary> /// </summary>
[Description("手动模式")] [Description("手动模式")]
manual_mode = 2, manual_mode = 2
/// <summary>
/// 算法模式
/// </summary>
[Description("算法模式")]
auto_mode = 3
} }
} }
...@@ -49,6 +49,11 @@ namespace VIZ.H2V.Storage ...@@ -49,6 +49,11 @@ namespace VIZ.H2V.Storage
public bool IsSendToCrop { get; set; } public bool IsSendToCrop { get; set; }
/// <summary> /// <summary>
/// 是否使用裁切
/// </summary>
public bool IsUseClip { get; set; } = true;
/// <summary>
/// 算法类型类型 /// 算法类型类型
/// </summary> /// </summary>
public AlgorithmStrategyType StrategyType { get; set; } = AlgorithmStrategyType.Single; public AlgorithmStrategyType StrategyType { get; set; } = AlgorithmStrategyType.Single;
...@@ -59,11 +64,6 @@ namespace VIZ.H2V.Storage ...@@ -59,11 +64,6 @@ namespace VIZ.H2V.Storage
public AlgorithmStrategyMode StrategyMode { get; set; } = AlgorithmStrategyMode.auto_mode; public AlgorithmStrategyMode StrategyMode { get; set; } = AlgorithmStrategyMode.auto_mode;
/// <summary> /// <summary>
/// 缓存裁切模式,如果当前裁切模式未no_mode那么该值保存了在切换为no_mode之前的模式
/// </summary>
public AlgorithmStrategyMode CacheStrategyMode { get; set; } = AlgorithmStrategyMode.auto_mode;
/// <summary>
/// 算法进程ID /// 算法进程ID
/// </summary> /// </summary>
public int ProcessID { get; set; } public int ProcessID { get; set; }
......
...@@ -11,7 +11,7 @@ APPLICATION_IS_DEBUG=true ...@@ -11,7 +11,7 @@ APPLICATION_IS_DEBUG=true
;视频是否显示FPS ;视频是否显示FPS
VIDEO_IS_SHOW_FPS=false VIDEO_IS_SHOW_FPS=false
;视频渲染等待(单位:毫秒) ;视频渲染等待(单位:毫秒)
VIDEO_RENDER_WAIT=2 VIDEO_RENDER_WAIT=10
;视频背景颜色 ;视频背景颜色
VIDEO_BACKGROUND_COLOR=#FF172532 VIDEO_BACKGROUND_COLOR=#FF172532
;视频框边框宽度(单位:像素) ;视频框边框宽度(单位:像素)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment