Commit c106755d by liulongfei

NDI视图重构

parent 93e93f78
......@@ -11,34 +11,46 @@ namespace VIZ.H2V.Domain
/// </summary>
public enum NDIViewStatus
{
// --------------------------------------------------------------------
// 启动 & 等待初始化完成
// --------------------------------------------------------------------
/// <summary>
/// 算法停止状态
/// 停止状态
/// </summary>
AlgorithmStop = 0,
Stop,
/// <summary>
/// 等待停止
/// 等待启动
/// </summary>
AlgorithmWaitStop = 1,
WaitSetup,
/// <summary>
/// 算法启动状态
/// 等待初始化完成
/// </summary>
AlgorithmSetup = 2,
WaitCheckOK,
// --------------------------------------------------------------------
// 算法运行状态
// --------------------------------------------------------------------
/// <summary>
/// 算法等待初始化完成
/// 目标检测
/// </summary>
AlgorithmWaitCheckedOk = 3,
Detect,
/// <summary>
/// 算法目标检测
/// 裁切
/// </summary>
AlgorithmDetect = 10,
CropRoi,
// --------------------------------------------------------------------
// 停止
// --------------------------------------------------------------------
/// <summary>
/// 算法裁剪状态
/// 等待结束
/// </summary>
AlgorithmCropRoi = 11,
WaitStop
}
}
......@@ -104,5 +104,8 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Folder Include="Model\NDIView\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</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 @@
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="#ff303d54"></Setter>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.7"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
......
......@@ -104,7 +104,9 @@
</Page>
</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">
<SubType>Code</SubType>
</Compile>
......
......@@ -88,10 +88,6 @@ namespace VIZ.H2V.Module
{
selectedAlgorithmStrategy = value;
this.RaisePropertyChanged(nameof(SelectedAlgorithmStrategy));
if (value != null)
{
this.ViewConfig.StrategyType = (AlgorithmStrategyType)value.ID;
}
}
}
......@@ -205,7 +201,8 @@ namespace VIZ.H2V.Module
/// <returns>是否成功保存</returns>
public bool Save()
{
ApplicationDomainEx.LiteDbContext.ViewConfig.Upsert(this.ViewConfig);
this.ViewConfig.StrategyType = (AlgorithmStrategyType)this.SelectedAlgorithmStrategy.ID;
ApplicationDomainEx.LiteDbContext.ViewConfig.Update(this.ViewConfig);
return true;
}
......@@ -224,7 +221,8 @@ namespace VIZ.H2V.Module
if (strategy != null)
{
// 设置算法显示名称
service.AlgorithmStrategyDisplayName = strategy.DisplayName;
service.StrategyDisplayName = strategy.DisplayName;
service.StrategyType = this.ViewConfig.StrategyType;
}
return true;
......
......@@ -238,7 +238,13 @@ namespace VIZ.H2V.Module
// 如果需要重启算法那么重启算法
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();
......
......@@ -3,196 +3,182 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Common;
using VIZ.Framework.Core;
using VIZ.H2V.Domain;
using VIZ.H2V.Storage;
using log4net;
using VIZ.H2V.Domain;
using VIZ.Framework.Connection;
using VIZ.H2V.Connection;
using System.Diagnostics;
using VIZ.H2V.Connection;
using VIZ.Framework.Common;
using VIZ.Framework.Core;
namespace VIZ.H2V.Module
{
/// <summary>
/// 算法控制器
/// 算法控制器基类
/// </summary>
public class AlgorithmController
public abstract class AlgorithmControllerBase : IAlgorithmController
{
/// <summary>
/// 日志
/// </summary>
private static ILog log = LogManager.GetLogger(typeof(AlgorithmController));
private static ILog log = LogManager.GetLogger(typeof(AlgorithmControllerBase));
/// <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>
/// 客户端UDP端口
/// 算法控制器基类
/// </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>
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>
/// 算法控制器
/// 客户端UDP端口
/// </summary>
/// <param name="support">算法控制器支持</param>
public AlgorithmController(IAlgorithmSupport support)
{
this.Support = support;
}
// ======================================================================================
// === Field ===
// ======================================================================================
protected readonly int CLIENT_PORT = ApplicationDomainEx.IniStorage.GetValue<UdpConfig, int>(p => p.UDP_BINDING_PORT);
/// <summary>
/// 控制器支持
/// 算法支持
/// </summary>
private IAlgorithmSupport Support;
public IAlgorithmSupport Support { get; private set; }
// ======================================================================================
// === Public Function ===
// ======================================================================================
/// <summary>
/// 算法策略
/// </summary>
public AlgorithmStrategyType StrategyType { get; private set; }
/// <summary>
/// 停止算法
/// 重启算法
/// </summary>
public void StopAlgorithm()
public void RestartAlgorithm()
{
// 已经处于停止状态
if (this.Support.ViewStatus == NDIViewStatus.AlgorithmWaitStop)
// 已经处于等待停止状态 那么不处理
if (this.Support.ViewStatus == NDIViewStatus.WaitStop)
return;
this.Support.ViewStatus = NDIViewStatus.AlgorithmWaitStop;
this.ExecuteRestartAlgorithm_StopProcess();
this.Support.ViewStatus = NDIViewStatus.AlgorithmStop;
this.Support.ViewStatus = NDIViewStatus.WaitStop;
Task.Run(() =>
{
try
{
if (!this.ExecuteRestartAlgorithm())
{
this.Support.ViewStatus = NDIViewStatus.Stop;
}
}
catch (Exception ex)
{
log.Error(ex);
this.Support.ViewStatus = NDIViewStatus.Stop;
}
});
}
/// <summary>
/// 切花模式
/// 停止算法
/// </summary>
/// <param name="mode">模式</param>
public void ChangeMode(AlgorithmStrategyMode mode)
public void StopAlgorithm()
{
// 更新缓存
this.Support.ViewConfig.StrategyMode = mode;
ApplicationDomainEx.LiteDbContext.ViewConfig.Update(this.Support.ViewConfig);
// 已经处于等待停止状态 || 处于停止状态 || 进程ID不存在 那么不处理
if (this.Support.ViewStatus == NDIViewStatus.WaitStop || this.Support.ViewStatus == NDIViewStatus.Stop || this.Support.ProcessModel.ProcessID == 0)
return;
// 清理跟踪框 & 裁切框
this.Support.ClearVideoControl();
this.Support.ViewStatus = NDIViewStatus.WaitStop;
// 算法处于停止状态(算法重启之后会自动切换一次当前状态)
if (this.Support.ViewStatus == NDIViewStatus.AlgorithmStop)
{
// 重启算法
this.RestartAlgorithm();
// 停止算法进程
if (!this.ExecuteRestartAlgorithm_StopProcess())
return;
}
// 算法处于 等待启动 或 等待初始化完成 状态,那么不需要处理(算法重启之后会自动切换一次当前状态)
if (this.Support.ViewStatus == NDIViewStatus.AlgorithmSetup || this.Support.ViewStatus == NDIViewStatus.AlgorithmWaitCheckedOk)
{
// 停止UDP
if (!this.ExecuteRestartAlgorithm_StopUDP())
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>
public void ChangeAutoModeTracking(List<int> bbox)
public void ChangeNoMode()
{
this.ChangeAutoMode_Single(AlgorithmAutoModeSingleCmd.tracking, bbox);
this.Support.ViewStatus = NDIViewStatus.AlgorithmCropRoi;
this.Support.ClearVideoControl();
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
if (manager == null)
return;
AlgorithmSender.NoMode(manager, this.Support.ID, this.Support.ViewConfig.IsSendToCrop);
}
/// <summary>
/// 裁切坐标
/// 切换居中模式
/// </summary>
/// <param name="roi">裁切坐标</param>
public void ChangeManualMode(List<int> roi)
public void ChangeCenterMode()
{
this.ChangeMode_manual_mode(roi);
}
UdpEndpointManager manager = ConnectionManager.UdpConnection.GetEndpointManager(this.Support.ViewKey);
if (manager == null)
return;
// ======================================================================================
// === Private Function ===
// ======================================================================================
AlgorithmSender.CenterMode(manager, this.Support.ID, this.Support.ViewConfig.IsSendToCrop);
}
/// <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;
this.Support.ViewStatus = NDIViewStatus.AlgorithmSetup;
List<int> roi = this.Support.GetManulRoi();
Task.Run(() =>
{
try
{
if (!this.ExecuteRestartAlgorithm())
{
this.Support.ViewStatus = NDIViewStatus.AlgorithmStop;
}
}
catch (Exception ex)
{
log.Error(ex);
this.Support.ViewStatus = NDIViewStatus.AlgorithmStop;
}
});
AlgorithmSender.ManualMode(manager, this.Support.ID, this.Support.ViewConfig.IsSendToCrop, roi);
}
/// <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>
/// <returns>是否成功重启</returns>
private bool ExecuteRestartAlgorithm()
{
// 需要先停止
if (this.Support.AlgorithmProcessModel.ProcessID > 0)
if (this.Support.ProcessModel.ProcessID > 0)
{
// 停止算法进程
if (!this.ExecuteRestartAlgorithm_StopProcess())
......@@ -212,7 +198,7 @@ namespace VIZ.H2V.Module
return false;
// 成功启动
this.Support.ViewStatus = NDIViewStatus.AlgorithmWaitCheckedOk;
this.Support.ViewStatus = NDIViewStatus.WaitCheckOK;
// 返回成功
return true;
......@@ -233,7 +219,7 @@ namespace VIZ.H2V.Module
{
try
{
AlgorithmSender.Stop(manager, this.Support.AlgorithmID);
AlgorithmSender.Stop(manager, this.Support.ID);
}
catch
{
......@@ -242,13 +228,13 @@ namespace VIZ.H2V.Module
DateTime beginTime = DateTime.Now;
// 等待停止
while ((DateTime.Now - beginTime).TotalMilliseconds < this.AlgorithmStopTimeout)
while ((DateTime.Now - beginTime).TotalMilliseconds < this.ALGORITHM_STOP_TIMEOUT)
{
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
......@@ -266,9 +252,9 @@ namespace VIZ.H2V.Module
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
......@@ -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)
......@@ -343,11 +329,11 @@ namespace VIZ.H2V.Module
}
// 端口
int port = this.Support.AlgorithmProcessModel.Port;
int port = this.Support.ProcessModel.Port;
// NDI流名称
string ndi_name = this.Support.ViewConfig.StreamName;
// 视图ID
string id = this.Support.AlgorithmID;
string id = this.Support.ID;
// GPU设备号
int device = this.Support.ViewConfig.GPU;
......@@ -369,7 +355,7 @@ namespace VIZ.H2V.Module
proc.StartInfo.WorkingDirectory = dir;
proc.StartInfo.UseShellExecute = true;
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;
if (!proc.Start())
......@@ -380,10 +366,10 @@ namespace VIZ.H2V.Module
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);
return true;
......@@ -405,147 +391,19 @@ namespace VIZ.H2V.Module
return false;
}
lock (UsedPorts)
lock (GlobalUsedPorts)
{
string ip = clientIP;
int port = NetHelper.GetAvailableUdpPort(8200, 9200, UsedPorts);
UsedPorts.Add(port);
int port = NetHelper.GetAvailableUdpPort(8200, 9200, GlobalUsedPorts);
GlobalUsedPorts.Add(port);
ConnectionManager.UdpConnection.AddEndpointManager(new UdpEndpointManager(this.Support.ViewKey, ip, port));
this.Support.AlgorithmProcessModel.IP = ip;
this.Support.AlgorithmProcessModel.Port = port;
this.Support.ProcessModel.IP = ip;
this.Support.ProcessModel.Port = port;
}
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
public interface IAlgorithmSupport
{
/// <summary>
/// 算法进程模型
/// 算法ID
/// </summary>
AlgorithmProcessModel AlgorithmProcessModel { get; }
string ID { get; }
/// <summary>
/// 当前算法模式
/// NDI视图键
/// </summary>
AlgorithmStrategyMode AlgorithmStrategyMode { get; }
string ViewKey { get; }
/// <summary>
/// 视图配置
......@@ -29,34 +29,49 @@ namespace VIZ.H2V.Module
NdiViewConfig ViewConfig { get; }
/// <summary>
/// 算法ID
/// 显示名称
/// </summary>
string AlgorithmID { get; }
string DisplayName { get; }
/// <summary>
/// NDI视图键
/// 算法策略显示名称
/// </summary>
string ViewKey { get; }
string StrategyDisplayName { get; }
/// <summary>
/// NDI视图状态
/// 裁切框X坐标
/// </summary>
NDIViewStatus ViewStatus { get; set; }
double? ClipBoxX { get; }
/// <summary>
/// 检测按钮是否可见
/// 算法模式
/// </summary>
bool IsDetectButtonVisible { get; set; }
AlgorithmStrategyMode StrategyMode { get; set; }
/// <summary>
/// 清理视频控件
/// 算法类型
/// </summary>
void ClearVideoControl();
AlgorithmStrategyType StrategyType { get; set; }
/// <summary>
/// NDI视图状态
/// </summary>
NDIViewStatus ViewStatus { get; set; }
/// <summary>
/// 算法进程模型
/// </summary>
AlgorithmProcessModel ProcessModel { get; }
/// <summary>
/// 获取手动裁切框
/// </summary>
/// <returns>手动裁切框</returns>
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
/// <summary>
/// 算法类型显示名称
/// </summary>
string AlgorithmStrategyDisplayName { get; set; }
string StrategyDisplayName { get; set; }
/// <summary>
/// 算法类型
/// </summary>
AlgorithmStrategyType StrategyType { get; set; }
/// <summary>
/// 视图配置
......@@ -39,9 +44,9 @@ namespace VIZ.H2V.Module
void StopAlgorithm();
/// <summary>
/// 异步更新模式
/// 切换模式
/// </summary>
/// <param name="isRestart">是否需要重启</param>
void UpdateModeAsync(bool isRestart);
/// <param name="context">切换模式上下文</param>
void ChangeStrategyMode(ChangeStrategyContext context);
}
}
......@@ -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/RadioButton/RadioButton_NdiView.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
<resource:NDIViewStatus2BoolConverter x:Key="NDIViewStatus2IsEnabledConverter" TrueListString="AlgorithmDetect,AlgorithmCropRoi"></resource:NDIViewStatus2BoolConverter>
<resource:NDIViewStatus2BoolConverter x:Key="NDIViewStatus2IsEnabledConverter_SettingButton" TrueListString="AlgorithmStop,AlgorithmWaitCheckedOk,AlgorithmDetect,AlgorithmCropRoi"></resource:NDIViewStatus2BoolConverter>
<fcore:Bool2BoolConverter x:Key="Bool2BoolConverter"></fcore:Bool2BoolConverter>
<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>
</UserControl.Resources>
......@@ -71,16 +74,16 @@
<RowDefinition Height="60"></RowDefinition>
</Grid.RowDefinitions>
<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>
<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>
<RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="60"></RowDefinition>
</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}">
</RadioButton>
<RadioButton Content="居中" Grid.Row="1" FontSize="16" Foreground="White"
......@@ -95,8 +98,19 @@
<Button Content="选择目标" Grid.Row="1" VerticalAlignment="Bottom" Style="{StaticResource Button_Setting}"
Height="40" Width="120" HorizontalAlignment="Right" Margin="0,0,10,0"
Command="{Binding Path=DetectCommand}"
Visibility="{Binding Path=IsDetectButtonVisible,Mode=OneWay,Converter={StaticResource Bool2VisibilityConverter}}">
Command="{Binding Path=DetectCommand}">
<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>
<!-- 视频区域 -->
......
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;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Core;
using log4net;
using VIZ.Framework.Common;
using VIZ.Framework.Core;
using VIZ.H2V.Domain;
using SharpDX.Mathematics.Interop;
using VIZ.Framework.Storage;
using System.Windows.Media;
using VIZ.H2V.Storage;
using VIZ.Framework.Connection;
using VIZ.H2V.Connection;
using log4net;
using System.Diagnostics;
namespace VIZ.H2V.Module
{
/// <summary>
/// NDI视图模型
/// </summary>
public class NDIViewModel : ViewModelBase, INDIViewService, IAlgorithmSupport
public partial class NDIViewModel : ViewModelBase, INDIViewService, IAlgorithmSupport
{
/// <summary>
/// 日志
......@@ -44,11 +38,11 @@ namespace VIZ.H2V.Module
// 初始化控制器
this.InitController();
// 注册WPF渲染事件,用于处理3D鼠标
CompositionTarget.Rendering -= CompositionTarget_Rendering;
CompositionTarget.Rendering += CompositionTarget_Rendering;
// 初始化手动模式
this.InitManual();
}
/// <summary>
/// 初始化命令
/// </summary>
......@@ -61,6 +55,16 @@ namespace VIZ.H2V.Module
}
/// <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>
private void InitMessage()
......@@ -84,607 +88,83 @@ namespace VIZ.H2V.Module
}
/// <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>
public bool IsNotNoModeChecked
/// <param name="context">切换模式上下文</param>
public void ChangeStrategyMode(ChangeStrategyContext context)
{
get { return isNotNoModeChecked; }
set
if (!this.AlgorithmControllerDic.TryGetValue(this.StrategyType, out IAlgorithmController controller))
{
isNotNoModeChecked = value;
this.RaisePropertyChanged(nameof(IsNotNoModeChecked));
if (value)
{
// 如果使用非无模式,那么切换为缓存模式
this.AlgorithmStrategyMode = this.ViewConfig.CacheStrategyMode;
}
else
{
// 否则切换为无模式
this.AlgorithmStrategyMode = AlgorithmStrategyMode.no_mode;
}
log.Error($"algorithm strategy [ type: {this.StrategyType} desc: {this.StrategyType.GetDescription()} ] no controller.");
return;
}
}
#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>
/// 自动模式是否选中
/// </summary>
public bool IsAutoModeChecked
{
get { return isAutoModeChecked; }
set
{
isAutoModeChecked = value;
this.RaisePropertyChanged(nameof(IsAutoModeChecked));
if (value)
{
this.AlgorithmStrategyMode = AlgorithmStrategyMode.auto_mode;
}
}
}
#endregion
// ----------------------------------------------------------------------------------------------
// Step 2. 清理界面状态 & 发送手动裁切消息
// ----------------------------------------------------------------------------------------------
#region IsCenterModeChecked -- 居中模式是否选中
// 清理视频控件
this.ClearVideoControl();
private bool isCenterModeChecked;
/// <summary>
/// 居中模式是否选中
/// </summary>
public bool IsCenterModeChecked
{
get { return isCenterModeChecked; }
set
{
isCenterModeChecked = value;
this.RaisePropertyChanged(nameof(IsCenterModeChecked));
if (value)
{
this.AlgorithmStrategyMode = AlgorithmStrategyMode.center_mode;
}
}
}
#endregion
// 发送切换手动消息
AlgorithmStrategyChangedToManualMessage msg = new AlgorithmStrategyChangedToManualMessage();
msg.Source = this;
msg.IsChangedToManual = this.StrategyMode == AlgorithmStrategyMode.manual_mode;
ApplicationDomainEx.MessageManager.Send(msg);
#region IsManualModeChecked -- 手动模式是否选中
// ----------------------------------------------------------------------------------------------
// Step 3. 校验视图状态
// ----------------------------------------------------------------------------------------------
private bool isManualModeChecked;
/// <summary>
/// 手动模式是否选中
/// </summary>
public bool IsManualModeChecked
{
get { return isManualModeChecked; }
set
// 如果当前状态为停止状态,那么重启算法 || 指定需要重启算法
if (this.ViewStatus == NDIViewStatus.Stop || context.IsNeedRestart)
{
isManualModeChecked = value;
this.RaisePropertyChanged(nameof(IsManualModeChecked));
if (value)
{
this.AlgorithmStrategyMode = AlgorithmStrategyMode.manual_mode;
}
controller.RestartAlgorithm();
return;
}
}
#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>
/// 加载命令
/// </summary>
public VCommand LoadedCommand { get; set; }
/// <summary>
/// 加载
/// </summary>
private void Loaded()
{
if (this.IsAlreadyLoaded)
// 1. 当前状态处于等待启动、等待停止、等待初始化完成状态是不需要处理的
// 2. 算法在CheckOK之后会获取最新的设置,所以不需要后续处理
if (this.ViewStatus == NDIViewStatus.WaitSetup || this.ViewStatus == NDIViewStatus.WaitStop || this.ViewStatus == NDIViewStatus.WaitCheckOK)
return;
this.IsAlreadyLoaded = true;
// ----------------------------------------------------------------------------------------------
// Step 4. 执行切换
// ----------------------------------------------------------------------------------------------
NDIView view = this.GetView<NDIView>();
if (view == null)
if (!this.IsUseClip)
{
this.ViewStatus = NDIViewStatus.CropRoi;
controller.ChangeNoMode();
return;
// 视图键
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)
}
else
{
switch (this.ViewConfig.CacheStrategyMode)
switch (context.Mode)
{
case AlgorithmStrategyMode.no_mode:
break;
case AlgorithmStrategyMode.center_mode:
this.isCenterModeChecked = true;
this.RaisePropertyChanged(nameof(IsCenterModeChecked));
this.ViewStatus = NDIViewStatus.CropRoi;
controller.ChangeCenterMode();
break;
case AlgorithmStrategyMode.manual_mode:
this.isManualModeChecked = true;
this.RaisePropertyChanged(nameof(IsManualModeChecked));
this.ViewStatus = NDIViewStatus.CropRoi;
controller.ChangeManualMode();
break;
case AlgorithmStrategyMode.auto_mode:
this.isAutoModeChecked = true;
this.RaisePropertyChanged(nameof(IsAutoModeChecked));
break;
default:
controller.ChangeAutoMode(context);
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>
......@@ -701,331 +181,48 @@ namespace VIZ.H2V.Module
if (renderInfo == null)
return null;
List<int> roi = new List<int> { (int)(this.ClipBoxX ?? 0), 0, (int)((this.ClipBoxX ?? 0) + this.ClipBoxWidth), 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;
return new List<int> { (int)(this.ClipBoxX ?? 0), 0, (int)this.CLIP_BOX_WIDTH, renderInfo.Frame.Height };
}
/// <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>
/// <param name="msg">消息</param>
private void OnAlgorithmMessage__crop_roi(AlgorithmMessage__crop_roi msg)
public void ClearVideoControl()
{
// 算法ID与视图绑定一一对应
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)
WPFHelper.Invoke(() =>
{
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.TrackingBoxBorderWidth;
info.DrawingBorderColor = this.TrackingBoxBorderColor;
NDIView view = this.GetView<NDIView>();
if (view == null)
return;
view.video.UpdateTrackingBox(new List<TrackingBoxInfo> { info });
}
else
{
view.video.ClearTrackingBox();
}
}
else
{
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();
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>
private void ChangeMode()
public void LoadStyle()
{
if (AlgorithmStrategyMode == AlgorithmStrategyMode.manual_mode)
SystemConfig config = ApplicationDomainEx.LiteDbContext.SystemConfig.FindAll().FirstOrDefault();
if (config == null)
{
// 如果切换为手动模式那么需要 重置3D鼠标
this.Reset3DMouse();
config = new SystemConfig();
ApplicationDomainEx.LiteDbContext.SystemConfig.Upsert(config);
}
// 切换模式
this.AlgorithmController.ChangeMode(this.AlgorithmStrategyMode);
// 发送剪切算法切换至手动消息
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);
this.ClipBoxStrokeColor_Normal = SharpDxColorHelper.FromString(config.ClipNormalColor);
this.ClipBoxStrokeColor_Exception = SharpDxColorHelper.FromString(config.ClipExceptionColor);
this.ClipBoxStrokeColor_Manual = SharpDxColorHelper.FromString(config.ClipManualColor);
}
/// <summary>
/// 重置3D鼠标
/// 停止算法
/// </summary>
private void Reset3DMouse()
public void StopAlgorithm()
{
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.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);
this.AlgorithmControllerDic[this.StrategyType].StopAlgorithm();
}
}
}
\ No newline at end of file
}
......@@ -153,8 +153,19 @@
</ItemGroup>
<ItemGroup>
<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\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_InitUDP.cs" />
<Compile Include="SystemSetting\ViewModel\AboutPanelViewModel.cs" />
......@@ -200,7 +211,6 @@
<DependentUpon>NDISettingView.xaml</DependentUpon>
</Compile>
<Compile Include="NDIView\Service\INDIViewService.cs" />
<Compile Include="NDIView\VieweModel\NDIViewModel.cs" />
<Compile Include="NDIView\View\NDIView.xaml.cs">
<DependentUpon>NDIView.xaml</DependentUpon>
</Compile>
......
......@@ -13,24 +13,21 @@ namespace VIZ.H2V.Storage
public enum AlgorithmStrategyMode
{
/// <summary>
/// 模式
/// 算法模式
/// </summary>
[Description("无模式")]
no_mode = 0,
[Description("算法模式")]
auto_mode = 0,
/// <summary>
/// 居中模式
/// </summary>
[Description("居中模式")]
center_mode = 1,
/// <summary>
/// 手动模式
/// </summary>
[Description("手动模式")]
manual_mode = 2,
/// <summary>
/// 算法模式
/// </summary>
[Description("算法模式")]
auto_mode = 3
manual_mode = 2
}
}
......@@ -49,6 +49,11 @@ namespace VIZ.H2V.Storage
public bool IsSendToCrop { get; set; }
/// <summary>
/// 是否使用裁切
/// </summary>
public bool IsUseClip { get; set; } = true;
/// <summary>
/// 算法类型类型
/// </summary>
public AlgorithmStrategyType StrategyType { get; set; } = AlgorithmStrategyType.Single;
......@@ -59,11 +64,6 @@ namespace VIZ.H2V.Storage
public AlgorithmStrategyMode StrategyMode { get; set; } = AlgorithmStrategyMode.auto_mode;
/// <summary>
/// 缓存裁切模式,如果当前裁切模式未no_mode那么该值保存了在切换为no_mode之前的模式
/// </summary>
public AlgorithmStrategyMode CacheStrategyMode { get; set; } = AlgorithmStrategyMode.auto_mode;
/// <summary>
/// 算法进程ID
/// </summary>
public int ProcessID { get; set; }
......
......@@ -11,7 +11,7 @@ APPLICATION_IS_DEBUG=true
;视频是否显示FPS
VIDEO_IS_SHOW_FPS=false
;视频渲染等待(单位:毫秒)
VIDEO_RENDER_WAIT=2
VIDEO_RENDER_WAIT=10
;视频背景颜色
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