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();
......
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();
}
}
}
}
......@@ -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