新增音频提示,重构检测框架

This commit is contained in:
terric 2023-11-26 03:37:35 +08:00
parent 1d195397e5
commit 7bb50a7c69
86 changed files with 419172 additions and 79143 deletions

View File

@ -20,7 +20,7 @@ AnimatorState:
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: fbbcd834b80a2244bbaa565e2a9304d4, type: 2}
m_Motion: {fileID: 7400000, guid: 2330ce5a2b71b8d4db5c7df4af072842, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
@ -46,7 +46,7 @@ AnimatorState:
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: e4c96b9f3a1a22c49a497567bc481aec, type: 2}
m_Motion: {fileID: 7400000, guid: b2a523a35f9151e40b0e241fe8e84f7e, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
@ -98,7 +98,7 @@ AnimatorState:
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 09ad66896a7e8f44e962f6b8f64766b4, type: 2}
m_Motion: {fileID: 7400000, guid: 28be8f1dc7bdd7a4fa96c8fade49e1cd, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 09ad66896a7e8f44e962f6b8f64766b4
guid: 28be8f1dc7bdd7a4fa96c8fade49e1cd
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: e4c96b9f3a1a22c49a497567bc481aec
guid: b2a523a35f9151e40b0e241fe8e84f7e
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2330ce5a2b71b8d4db5c7df4af072842
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

8
Assets/Resources/CV.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3c029c0c127b54c4e8eaa2ad235d7fcc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 4b4a8ad049c2a224fb4269921025b50d
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: ff29f998f0ac1b049a223b9cade96694
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/Resources/CV/End.wav Normal file

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 083081e15f166bc46900bc62e2cb48ad
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: c5bcfca71e29c9841904a1a57d069503
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: af7471fe6f7b47b418fe924c8e7f4ade
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: b7d87eb6f8485c54889532ad8bf8654a
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: a093b68a258b85340aa6d9439a43d293
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 070632ea6d72e8440b33a27aa2bbcdf4
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 1de7cc4d3d825b94983bd9feb615de7a
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 0bf7ca5206e4bbf47a43b2dd696a0c50
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: f2cd08ba964bd254baacc42a4f9ecc06
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 55ce4f400c910cb4ea049bb92072e156
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 054cbb4e011bd2b47bc009ae5117b06c
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 1bf92fda1f9cc884f88cddd7903dcfeb
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 2d2fddb355f1a834ca9380dff0c9b5ff
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: a4da9169c401d3b4782567d97149483d
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3a430a62884487049974b441d5e734f2
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -581,7 +581,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!224 &406787417813524232
RectTransform:
m_ObjectHideFlags: 0
@ -2051,7 +2051,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
m_IsActive: 1
--- !u!224 &3096906925272982799
RectTransform:
m_ObjectHideFlags: 0

View File

@ -1,5 +1,139 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &170197589121739078
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 16449236695946632}
- component: {fileID: 4171271539229961150}
- component: {fileID: 438424692819617648}
m_Layer: 5
m_Name: Text (TMP)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &16449236695946632
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 170197589121739078}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8472159739644250972}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4171271539229961150
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 170197589121739078}
m_CullTransparentMesh: 1
--- !u!114 &438424692819617648
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 170197589121739078}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: driver pos
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4281479730
m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 24
m_fontSizeBase: 24
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 2
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_enableWordWrapping: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!1 &1810736599091027815
GameObject:
m_ObjectHideFlags: 0
@ -83,7 +217,6 @@ GameObject:
- component: {fileID: 5082957450278584826}
- component: {fileID: 3665669893236807636}
- component: {fileID: 4535446944362228418}
- component: {fileID: 6831284828825100389}
m_Layer: 5
m_Name: InfoMation
m_TagString: Untagged
@ -207,18 +340,6 @@ MonoBehaviour:
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!114 &6831284828825100389
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3596812701211911403}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5980b31cfe3b85c4291bf1e4de4ed8f5, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &3916216323484811938
GameObject:
m_ObjectHideFlags: 0
@ -269,6 +390,12 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
TargetDisplayer: {fileID: 1609086109949441296}
FlipHorizontal: 1
d1: -0.01
d2: 0.09
d3: 0
d4: 0
d5: -0.19
--- !u!114 &9125160410290116513
MonoBehaviour:
m_ObjectHideFlags: 0
@ -515,6 +642,7 @@ RectTransform:
- {fileID: 8241937279858049995}
- {fileID: 5082957450278584826}
- {fileID: 6157776119431030229}
- {fileID: 8472159739644250972}
m_Father: {fileID: 5269051166812510682}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
@ -522,3 +650,136 @@ RectTransform:
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &9153195279384769951
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8472159739644250972}
- component: {fileID: 1973911125795704139}
- component: {fileID: 216806967156518302}
- component: {fileID: 578193548592654182}
m_Layer: 5
m_Name: Position
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &8472159739644250972
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9153195279384769951}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 16449236695946632}
m_Father: {fileID: 1888392902869825718}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 797, y: 411}
m_SizeDelta: {x: 160, y: 30}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &1973911125795704139
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9153195279384769951}
m_CullTransparentMesh: 1
--- !u!114 &216806967156518302
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9153195279384769951}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &578193548592654182
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9153195279384769951}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 216806967156518302}
m_OnClick:
m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 6077628302202676596}
m_TargetAssemblyTypeName: TestUI, Assembly-CSharp
m_MethodName: OnPosBtnClick
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2

View File

@ -188,123 +188,6 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &383216727
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 1078817699}
m_Modifications:
- target: {fileID: 3238779271317125947, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: TargetDisplayer
value:
objectReference: {fileID: 889634585}
- target: {fileID: 4975108645149662689, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_Name
value: TestUI
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_AnchorMax.x
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_AnchorMin.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_LocalRotation.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
--- !u!224 &383216728 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 5269051166812510682, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
m_PrefabInstance: {fileID: 383216727}
m_PrefabAsset: {fileID: 0}
--- !u!114 &889634585 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 1609086109949441296, guid: 3f17c228d0af15046af0b6f6a638c2fc, type: 3}
m_PrefabInstance: {fileID: 383216727}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &1078817695
GameObject:
m_ObjectHideFlags: 0
@ -317,6 +200,7 @@ GameObject:
- component: {fileID: 1078817698}
- component: {fileID: 1078817697}
- component: {fileID: 1078817696}
- component: {fileID: 1078817700}
m_Layer: 5
m_Name: UICanvas
m_TagString: UI
@ -398,8 +282,7 @@ RectTransform:
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 383216728}
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
@ -407,6 +290,18 @@ RectTransform:
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 0}
--- !u!114 &1078817700
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1078817695}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5980b31cfe3b85c4291bf1e4de4ed8f5, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &1501258256
GameObject:
m_ObjectHideFlags: 0

View File

@ -1,22 +0,0 @@
using OpenCVForUnity.CoreModule;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BodyBendLeft : PoseBase
{
public override bool CheckPose(List<Point> points)
{
if (!"LHip".IsValid(points) &&
!"LKnee".IsValid(points))
return false;
//左弯腰检测
if (points[YogaConfig.BODY_PARTS["LHip"]].y > points[YogaConfig.BODY_PARTS["LKnee"]].y)
{
return true;
}
return false;
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 87e5c9a13e47dc9458e15df5bb410642
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,21 +0,0 @@
using OpenCVForUnity.CoreModule;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BodyBendRight : PoseBase
{
public override bool CheckPose(List<Point> points)
{
if (!"RHip".IsValid(points) &&
!"RKnee".IsValid(points))
return false;
//右弯腰检测
if (points[YogaConfig.BODY_PARTS["RHip"]].y > points[YogaConfig.BODY_PARTS["RKnee"]].y)
{
return true;
}
return false;
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 40fa83b49b5a8104fa8ea944835b1e3f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,22 +0,0 @@
using OpenCVForUnity.CoreModule;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BodyTurnLeft : PoseBase
{
public override bool CheckPose(List<Point> points)
{
if (!"LShoulder".IsValid(points) &&
!"RHip".IsValid(points))
return false;
//左转身检测
if (points[YogaConfig.BODY_PARTS["LShoulder"]].x < points[YogaConfig.BODY_PARTS["RHip"]].x)
{
return true;
}
return false;
}
}

View File

@ -1,22 +0,0 @@
using OpenCVForUnity.CoreModule;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BodyTurnRight : PoseBase
{
public override bool CheckPose(List<Point> points)
{
if (!"RShoulder".IsValid(points) &&
!"LHip".IsValid(points))
return false;
//右转身检测
if (points[YogaConfig.BODY_PARTS["RShoulder"]].x > points[YogaConfig.BODY_PARTS["LHip"]].x)
{
return true;
}
return false;
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 2dccb5177a6427c45aae4f5cf9c73f42
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -32,7 +32,7 @@ public class CVEstimator : Singleton<CVEstimator>
}
//加载模型
switch (YogaManager.Instance.Action.ModelType)
switch (YogaManager.Instance.LevelData.ModelType)
{
case ModelType.OpenPose:
YogaManager.Instance.CurrentEstimator = new OpenPoseEsimater();
@ -114,7 +114,7 @@ public class CVEstimator : Singleton<CVEstimator>
}
//更新关键点位检测结果
YogaManager.Instance.CurrPersonPoints = points;
YogaManager.Instance.AddCurrEstimateKeyPoints(points);
//等待到下一个更新周期
if (DateTime.Now - startTime > _refreshRate)

View File

@ -112,7 +112,7 @@ public class OpenPoseEsimater : Estimator
*/
voloResultBox = new List<float[]>();
float[] box = new float[4];
float shift = bgrMat.width() / 2 * YogaManager.Instance.Action.RectCutRate;
float shift = bgrMat.width() / 2 * YogaManager.Instance.LevelData.RectCutRate;
if (GlobalData.Instance.Position == PositionType.CoDriver)
{

View File

@ -1,10 +1,65 @@
using OpenCVForUnity.CoreModule;
using System;
using System.Collections.Generic;
using UnityEngine;
public class HandsHold : PoseBase
{
public override bool CheckPose(List<Point> points)
public override Vector2 GetBasicVectorDirection(List<Point> startPoint, List<Point> endPoint)
{
return false;
//必要点位 "RShoulder", "LShoulder", "RElbow", "LElbow"
//计算肩膀到手肘矢量,右手
Vector2 rightHandVector = GetAverageVector(startPoint, endPoint, "RElbow");
Vector2 leftHandVector = GetAverageVector(startPoint, endPoint, "LElbow");
//平均矢量
Vector2 averageVector = (rightHandVector + leftHandVector) / 2;
//如果左右手肘矢量差小于两者平均值的0.3倍且左右手矢量夹角小于30度返回左右手矢量平均值
if ((rightHandVector - leftHandVector).magnitude < averageVector.magnitude * 0.3f
&& Vector2.Angle(rightHandVector, leftHandVector) < 30)
{
return averageVector;
}
return Vector2.zero;
}
protected override bool IsMovePoint(string tagName)
{
return "RWrist".Equals(tagName) ||
"LWrist".Equals(tagName);
}
public override void ValidationMovement(Vector2 distance, TimeSpan totalTimeSpan, int level)
{
var angle = Vector2.SignedAngle(Vector2.down, distance);
LogPrint.Log($"Angle:{angle}", PrintLevel.Normal);
if (MathF.Abs(angle) < 10)
EventManager.Instance.Dispatch(YogaEventType.Action_Success); //方向不能偏移超过10°
else
EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
if (level < 1)
return;
LogPrint.Log($"distance x:{distance.x}, y:{distance.y}, magnitude:{distance.magnitude}", PrintLevel.Normal);
if (distance.magnitude > 5f || distance.magnitude < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceNotAccurate);
else
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceExactly);
if (level < 2)
return;
var speed = distance.magnitude / totalTimeSpan.TotalSeconds;
LogPrint.Log($"speed:{speed}", PrintLevel.Normal);
if (speed > 0.5f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooFast); //速度语音提示
else if (speed < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooSlow); //速度语音提示
}
public override void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan)
{
throw new NotImplementedException();
}
}

View File

@ -5,31 +5,62 @@ using UnityEngine;
public class HandsUp : PoseBase
{
public override bool CheckPose(List<Point> points)
public override Vector2 GetBasicVectorDirection(List<Point> startPoint, List<Point> endPoint)
{
// 必须包含 "Nose", "RShoulder", "LShoulder", "RElbow", "LElbow" 点位
if (!YogaManager.Instance.ActionCheckPoints(points))
return false;
//必要点位 "RShoulder", "LShoulder", "RElbow", "LElbow"
//计算肩膀到手肘矢量,右手
Vector2 rightHandVector = GetAverageVector(startPoint, endPoint, "RElbow");
Vector2 leftHandVector = GetAverageVector(startPoint, endPoint, "LElbow");
//平均矢量
Vector2 averageVector = (rightHandVector + leftHandVector) / 2;
var basePoint = YogaManager.Instance.Points;
if (!YogaManager.Instance.ActionCheckPoints(basePoint))
return false;
//如果左右手肘矢量差小于两者平均值的0.3倍且左右手矢量夹角小于30度返回左右手矢量平均值
if ((rightHandVector - leftHandVector).magnitude < averageVector.magnitude * 0.3f
&& Vector2.Angle(rightHandVector, leftHandVector) < 30)
{
return averageVector;
}
return Vector2.zero;
}
protected override bool IsMovePoint(string tagName)
{
return "RWrist".Equals(tagName) ||
"LWrist".Equals(tagName);
}
var rArmVector = ("RElbow".vector(points) - "RShoulder".vector(points)).normalized;
var lArmVector = ("LElbow".vector(points) - "LShoulder".vector(points)).normalized;
public override void ValidationMovement(Vector2 distance, TimeSpan totalTimeSpan, int level)
{
var angle = Vector2.SignedAngle(Vector2.up, distance);
LogPrint.Log($"Angle:{angle}", PrintLevel.Normal);
if (MathF.Abs(angle) < 10)
EventManager.Instance.Dispatch(YogaEventType.Action_Success); //方向不能偏移超过10°
else
EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
var rArmBaseVector = ("RElbow".vector(basePoint) - "RShoulder".vector(basePoint)).normalized;
var lArmBaseVector = ("LElbow".vector(basePoint) - "LShoulder".vector(basePoint)).normalized;
if (level < 1)
return;
var angleR = Vector3.Angle(rArmVector, rArmBaseVector);
var angleL = Vector3.Angle(lArmVector, lArmBaseVector);
LogPrint.Log($"distance x:{distance.x}, y:{distance.y}, magnitude:{distance.magnitude}", PrintLevel.Normal);
if (distance.magnitude > 5f || distance.magnitude < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceNotAccurate);
else
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceExactly);
LogPrint.Warning("angleR:" + angleR + " angleL:" + angleL);
if (level < 2)
return;
if (angleR < 10 || angleL < 10)
return false;
var speed = distance.magnitude / totalTimeSpan.TotalSeconds;
LogPrint.Log($"speed:{speed}", PrintLevel.Normal);
if (speed > 0.5f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooFast); //速度语音提示
else if (speed < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooSlow); //速度语音提示
}
return true;
public override void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan)
{
throw new NotImplementedException();
}
}

View File

@ -1,24 +1,54 @@
using OpenCVForUnity.CoreModule;
using System;
using System.Collections.Generic;
using UnityEngine;
public class HeadTurnDown : PoseBase
{
public override bool CheckPose(List<Point> points)
public override Vector2 GetBasicVectorDirection(List<Point> startPoint, List<Point> endPoint)
{
// 必须包含 Nose 和 LEar 和 Neck 的点位
if (!YogaManager.Instance.ActionCheckPoints(points))
return false;
List<Vector2> vectors = new List<Vector2>();
//必要点位 Nose Neck
//计算鼻子到头颈矢量
return GetAverageVector(startPoint, endPoint, "Nose");
}
var basePoint = YogaManager.Instance.Points;
if (!YogaManager.Instance.ActionCheckPoints(basePoint))
return false;
protected override bool IsMovePoint(string tagName)
{
return "Nose" == tagName || "REye" == tagName || "LEye" == tagName || "REar" == tagName || "LEar" == tagName;
}
var noseMagnitude = ("Nose".vector(points) - "Neck".vector(points)).magnitude;
var noseBaseMagnitude = ("Nose".vector(basePoint) - "Neck".vector(basePoint)).magnitude;
public override void ValidationMovement(Vector2 distance, TimeSpan totalTimeSpan, int level)
{
var angle = Vector2.SignedAngle(Vector2.down, distance);
LogPrint.Log($"Angle:{angle}", PrintLevel.Normal);
if (MathF.Abs(angle) < 10)
EventManager.Instance.Dispatch(YogaEventType.Action_Success); //方向不能偏移超过10°
else
EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
if (noseBaseMagnitude > noseMagnitude * 1.1f)
return true;
if (level < 1)
return;
return false;
LogPrint.Log($"distance x:{distance.x}, y:{distance.y}, magnitude:{distance.magnitude}", PrintLevel.Normal);
if (distance.magnitude > 5f || distance.magnitude < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceNotAccurate);
else
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceExactly);
if (level < 2)
return;
var speed = distance.magnitude / totalTimeSpan.TotalSeconds;
LogPrint.Log($"speed:{speed}", PrintLevel.Normal);
if (speed > 0.5f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooFast); //速度语音提示
else if (speed < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooSlow); //速度语音提示
}
public override void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan)
{
throw new NotImplementedException();
}
}

View File

@ -6,32 +6,50 @@ using UnityEngine;
public class HeadTurnLeft : PoseBase
{
public override bool CheckPose(List<Point> points)
public override Vector2 GetBasicVectorDirection(List<Point> startPoint, List<Point> endPoint)
{
// 必须包含 Nose 和 LEar 和 Neck 的点位
if (!YogaManager.Instance.ActionCheckPoints(points))
return false;
List<Vector2> vectors = new List<Vector2>();
//必要点位 Nose Neck
//计算鼻子到头颈矢量
return GetAverageVector(startPoint, endPoint, "Nose");
}
var basePoint = YogaManager.Instance.Points;
if (!YogaManager.Instance.ActionCheckPoints(basePoint))
return false;
protected override bool IsMovePoint(string tagName)
{
return "Nose" == tagName || "REye" == tagName || "LEye" == tagName || "REar" == tagName || "LEar" == tagName;
}
//左转头检测
if (!"REye".IsValid(points))
return false;
public override void ValidationMovement(Vector2 distance, TimeSpan totalTimeSpan, int level)
{
var angle = Vector2.SignedAngle(Vector2.left, distance);
LogPrint.Log($"Angle:{angle}", PrintLevel.Normal);
if (MathF.Abs(angle) < 10)
EventManager.Instance.Dispatch(YogaEventType.Action_Success); //方向不能偏移超过10°
else
EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
if (!"LEye".IsValid(points))
return true;
if (level < 1)
return;
var headVector = ("REye".vector(points) - "LEye".vector(points)).normalized;
var headBaseVector = ("RElbow".vector(basePoint) - "LElbow".vector(basePoint)).normalized;
LogPrint.Log($"distance x:{distance.x}, y:{distance.y}, magnitude:{distance.magnitude}", PrintLevel.Normal);
if (distance.magnitude > 5f || distance.magnitude < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceNotAccurate);
else
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceExactly);
var noseVector = ("Nose".vector(points) - "Neck".vector(points)).normalized;
var noseBaseVector = ("Nose".vector(basePoint) - "Neck".vector(basePoint)).normalized;
if (level < 2)
return;
if (Vector2.Dot(headVector, noseVector) > Vector2.Dot(headBaseVector, noseBaseVector) + 0.1f)
return true;
return false;
var speed = distance.magnitude / totalTimeSpan.TotalSeconds;
LogPrint.Log($"speed:{speed}", PrintLevel.Normal);
if (speed > 0.5f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooFast); //速度语音提示
else if (speed < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooSlow); //速度语音提示
}
public override void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan)
{
throw new NotImplementedException();
}
}

View File

@ -6,32 +6,50 @@ using UnityEngine;
public class HeadTurnRight : PoseBase
{
public override bool CheckPose(List<Point> points)
public override Vector2 GetBasicVectorDirection(List<Point> startPoint, List<Point> endPoint)
{
// 必须包含 Nose 和 LEar 和 Neck 的点位
if (!YogaManager.Instance.ActionCheckPoints(points))
return false;
List<Vector2> vectors = new List<Vector2>();
//必要点位 Nose Neck
//计算鼻子到头颈矢量
return GetAverageVector(startPoint, endPoint, "Nose");
}
var basePoint = YogaManager.Instance.Points;
if (!YogaManager.Instance.ActionCheckPoints(basePoint))
return false;
protected override bool IsMovePoint(string tagName)
{
return "Nose" == tagName || "REye" == tagName || "LEye" == tagName || "REar" == tagName || "LEar" == tagName;
}
//右转头检测
if (!"LEye".IsValid(points))
return false;
public override void ValidationMovement(Vector2 distance, TimeSpan totalTimeSpan, int level)
{
var angle = Vector2.SignedAngle(Vector2.right, distance);
LogPrint.Log($"Angle:{angle}", PrintLevel.Normal);
if (MathF.Abs(angle) < 10)
EventManager.Instance.Dispatch(YogaEventType.Action_Success); //方向不能偏移超过10°
else
EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
if (!"REye".IsValid(points))
return true;
if (level < 1)
return;
var headVector = ("REye".vector(points) - "LEye".vector(points)).normalized;
var headBaseVector = ("REye".vector(basePoint) - "LEye".vector(basePoint)).normalized;
LogPrint.Log($"distance x:{distance.x}, y:{distance.y}, magnitude:{distance.magnitude}", PrintLevel.Normal);
if (distance.magnitude > 5f || distance.magnitude < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceNotAccurate);
else
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceExactly);
var noseVector = ("Nose".vector(points) - "Neck".vector(points)).normalized;
var noseBaseVector = ("Nose".vector(basePoint) - "Neck".vector(basePoint)).normalized;
if (level < 2)
return;
if (Vector2.Dot(headVector, noseVector) < Vector2.Dot(headBaseVector, noseBaseVector) - 0.1f)
return true;
var speed = distance.magnitude / totalTimeSpan.TotalSeconds;
LogPrint.Log($"speed:{speed}", PrintLevel.Normal);
if (speed > 0.5f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooFast); //速度语音提示
else if (speed < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooSlow); //速度语音提示
}
return false;
public override void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan)
{
throw new NotImplementedException();
}
}

View File

@ -1,24 +1,54 @@
using OpenCVForUnity.CoreModule;
using System;
using System.Collections.Generic;
using UnityEngine;
public class HeadTurnUp : PoseBase
{
public override bool CheckPose(List<Point> points)
public override Vector2 GetBasicVectorDirection(List<Point> startPoint, List<Point> endPoint)
{
// 必须包含 Nose 和 LEar 和 Neck 的点位
if (!YogaManager.Instance.ActionCheckPoints(points))
return false;
List<Vector2> vectors = new List<Vector2>();
//必要点位 Nose Neck
//计算鼻子到头颈矢量
return GetAverageVector(startPoint, endPoint, "Nose");
}
var basePoint = YogaManager.Instance.Points;
if (!YogaManager.Instance.ActionCheckPoints(basePoint))
return false;
protected override bool IsMovePoint(string tagName)
{
return "Nose" == tagName || "REye" == tagName || "LEye" == tagName || "REar" == tagName || "LEar" == tagName;
}
var noseMagnitude = ("Nose".vector(points) - "Neck".vector(points)).magnitude;
var noseBaseMagnitude = ("Nose".vector(basePoint) - "Neck".vector(basePoint)).magnitude;
public override void ValidationMovement(Vector2 distance, TimeSpan totalTimeSpan, int level)
{
var angle = Vector2.SignedAngle(Vector2.up, distance);
LogPrint.Log($"Angle:{angle}", PrintLevel.Normal);
if (MathF.Abs(angle) < 10)
EventManager.Instance.Dispatch(YogaEventType.Action_Success); //方向不能偏移超过10°
else
EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
if (noseBaseMagnitude * 1.1f < noseMagnitude)
return true;
if (level < 1)
return;
return false;
LogPrint.Log($"distance x:{distance.x}, y:{distance.y}, magnitude:{distance.magnitude}", PrintLevel.Normal);
if (distance.magnitude > 5f || distance.magnitude < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceNotAccurate);
else
EventManager.Instance.Dispatch(YogaEventType.Action_MoveDistanceExactly);
if (level < 2)
return;
var speed = distance.magnitude / totalTimeSpan.TotalSeconds;
LogPrint.Log($"speed:{speed}", PrintLevel.Normal);
if (speed > 0.5f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooFast); //速度语音提示
else if (speed < 0.1f)
EventManager.Instance.Dispatch(YogaEventType.Action_SpeedTooSlow); //速度语音提示
}
public override void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan)
{
throw new NotImplementedException();
}
}

View File

@ -1,13 +1,10 @@
using OpenCVForUnity.CoreModule;
using OpenCVForUnity.ImgprocModule;
using System;
using System.Collections.Generic;
using UnityEngine;
public abstract class PoseBase
{
public abstract bool CheckPose(List<Point> points);
public Dictionary<string, Point> GetVaildPoints(List<Point> points, List<string> pointName)
{
var retVal = new Dictionary<string, Point>();
@ -21,4 +18,85 @@ public abstract class PoseBase
}
return retVal;
}
public abstract Vector2 GetBasicVectorDirection(List<Point> startPoint, List<Point> endPoint);
//public abstract void SpeedCheck(double v);
public abstract void ValidationMovement(Vector2 distance, TimeSpan totalTimeSpan, int level);
public abstract void ExcellenceEstimate(List<(TimeSpan, Vector2)> frameData, Vector2 distance, TimeSpan totalTimeSpan);
protected Vector2 GetAverageVector(List<Point> startPoint, List<Point> endPoint, string movePoint)
{
List<Vector2> vectors = new List<Vector2>();
for (int i = 0; i < endPoint.Count; i++)
{
string tagName = i.tagName();
//自身不计算
if (movePoint.Equals(tagName) || movePoint.Equals(tagName))
continue;
//动点位不计算
if (IsMovePoint(tagName))
continue;
if (!tagName.IsValid(startPoint) || !tagName.IsValid(endPoint))
continue;
//动点-静点
Vector2 startEyeV = new Vector2((float)movePoint.p(startPoint).x - (float)tagName.p(startPoint).x, (float)movePoint.p(startPoint).y - (float)tagName.p(startPoint).y);
Vector2 endEyeV = new Vector2((float)movePoint.p(endPoint).x - (float)tagName.p(endPoint).x, (float)movePoint.p(endPoint).y - (float)tagName.p(endPoint).y);
vectors.Add(endEyeV - startEyeV);
}
//计算平均矢量
Vector2 averageV = new Vector2(0, 0);
foreach (var v in vectors)
{
averageV += v;
}
averageV /= vectors.Count;
return averageV;
}
/// <summary>
/// 确定该点位是否为运动时会跟着动的点位
/// 内部重写,写明该动作的所有动点
/// </summary>
/// <param name="tagName">点位名称</param>
/// <returns>是否为动点</returns>
protected abstract bool IsMovePoint(string tagName);
/// <summary>
/// 动作检测
/// </summary>
/// <param name="points"></param>
/// <param name="isDataReGather"></param>
public virtual void AnalyzingAction(List<(DateTime, List<Point>)> points, bool isDataReGather = false)
{
if (points.Count < 2) // 0级实现逻辑 不做操作
return;
var distance = Vector2.zero;
var totalTimeSpan = TimeSpan.Zero;
for (int i = 0; i < points.Count - 1; i++)
{
var p1 = points[i].Item2;
var p2 = points[i + 1].Item2;
TimeSpan timeSpan = points[i + 1].Item1 - points[i].Item1;
var vector = GetAverageVector(p1, p2, "Nose"); //关键点Nose
distance += vector;
totalTimeSpan += timeSpan;
}
LogPrint.Log($"distance: {distance}, totalTimeSpan: {totalTimeSpan}", PrintLevel.Normal);
int level = 0;
if (points.Count > 3 && !isDataReGather) //1级实现逻辑
{
level = 1;
}
if (points.Count > 10 && !isDataReGather) //2级实现逻辑
{
level = 2;
}
//动作方位是否正确
ValidationMovement(distance, totalTimeSpan, level);
}
}

View File

@ -0,0 +1,112 @@
using SRF;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
//声音管理器
public class AudioManager : MonoSingleton<AudioManager>
{
private Queue<string> _CVFiles = new Queue<string>();
private AudioSource _cvSouce;
private readonly float _cvCDTime = 0.2f;
private float _cvCDTimer = 0;
//音乐音量
private float _musicVolume;
public float MusicVolume
{
get => _musicVolume;
set => _musicVolume = value;
}
private float _seVolume;
public float SEVolume
{
get => _seVolume;
set => _seVolume = value;
}
private float _cvVolume;
private Queue<AudioSource> _cacheAudioSource;
public float CVVolume
{
get => _cvVolume;
set => _cvVolume = value;
}
public override void Init()
{
_cvSouce = gameObject.GetComponentOrAdd<AudioSource>();
_cvSouce.name = "CVSource";
}
//播放音乐
public void PlayMusic(string name)
{
}
public void PlaySE(string name)
{
}
public void PlayCV(string name)
{
}
public void PlayCVInQueue(string name)
{
_CVFiles.Enqueue(name);
}
private void Update()
{
//播放队列中音频
if (_CVFiles.Count > 0)
{
//正在播放
if (_cvSouce.isPlaying)
{
return;
}
//播放完成后等待0.5秒
if (_cvCDTimer < _cvCDTime)
{
_cvCDTimer += Time.deltaTime;
return;
}
_cvCDTimer = 0;
var name = _CVFiles.Dequeue();
var clip = GetAudioClip("CV", name);
_cvSouce.clip = clip;
_cvSouce.Play();
}
}
public void StopMusic()
{
}
public void StopSE()
{
}
public void StopCV()
{
}
private AudioClip GetAudioClip(string type, string path)
{
var retVal = Resources.Load<AudioClip>($"{type}/{path}");
return retVal;
}
}

View File

@ -74,15 +74,22 @@ public enum YogaEventType
{
StartMotionCapture,
StopMotionCapture,
EstimateAction,
ScoreUpdate,
GetActionBasePoint,
Action_End,
UI_ScoreUpdate,
Action_Start,
PoseEstimate,
ActionSuccess,
ActionFailed,
Action_Success,
Action_Fail,
PlayAnimation,
UpdateProgress,
ShowHint,
ShowMessage,
ChangeCaptureCameraDevice,
PlayCastVoice,
DEBUG_CONSOLE_ChangeCamMode,
Action_MoveDistanceExactly,
Action_SpeedTooFast,
Action_SpeedTooSlow,
Action_MoveDistanceNotAccurate,
UI_LevelFinished,
}

View File

@ -1,11 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SoundManager : MonoSingleton<SoundManager>
{
public void PlayMusic(string name, float volume = 1)
{
}
}

View File

@ -15,7 +15,7 @@ using Yoga;
public class YogaManager : MonoSingleton<YogaManager>
{
private List<Point> _points = new List<Point>();
private List<Point> _baseKeyPoints = new List<Point>();
private Mat _rgbaMat;
public Mat RgbaMat
{
@ -27,12 +27,30 @@ public class YogaManager : MonoSingleton<YogaManager>
set => _rgbaMat = value;
}
private List<Point> _currPersonPoints = new List<Point>();
public List<Point> CurrPersonPoints { get => _currPersonPoints; set => _currPersonPoints = value; }
protected bool _isCorrectAction = false;
private Queue<(DateTime, List<Point>)> _estimateKeyPointsCache = new Queue<(DateTime, List<Point>)>();
public Queue<(DateTime, List<Point>)> EstimateKeyPointsCache
{
get => _estimateKeyPointsCache;
}
private List<Point> _currEstimateKeyPoints;
public List<Point> CurrEstimateKeyPoints { get => _currEstimateKeyPoints; set => _currEstimateKeyPoints = value; }
public void AddCurrEstimateKeyPoints(List<Point> points)
{
_currEstimateKeyPoints = points;
_estimateKeyPointsCache.Enqueue((DateTime.Now, points));
if (_estimateKeyPointsCache.Count > YogaConfig.CurrEstimateKeyPointsMaxCount)
{
_estimateKeyPointsCache.Dequeue();
}
}
private List<float[]> _personRectResult = new List<float[]>();
public List<float[]> PersonRectResult { get => _personRectResult; set => _personRectResult = value; }
public List<Point> Points { get => _points; set => _points = value; }
public List<Point> BaseKeyPoints { get => _baseKeyPoints; set => _baseKeyPoints = value; }
private int _currentActionCount; //当前动作计数
public int CurrentActionCount { get => _currentActionCount; }
@ -40,34 +58,36 @@ public class YogaManager : MonoSingleton<YogaManager>
private int _currentSuccessActionCount; //当前成功动作计数
public int CurrentSuccessActionCount { get => _currentSuccessActionCount; }
public int MaxActionCount => Action.MaxActionCount;
public int MaxActionCount => LevelData.MaxActionCount;
private int _actionIndex = -1; //用户选择界面选择的动作索引
public int ActionIndex { get => _actionIndex; internal set => _actionIndex = value; }
private Dictionary<AvatarAction, PoseBase> _actions = new Dictionary<AvatarAction, PoseBase>();
private bool _isActionRunning = false;
public YogaData Action
public YogaData LevelData
{
get
{
if (_actions == null)
if (_levelData == null)
{
LogPrint.Warning("Action Not Load!", PrintLevel.Normal);
InitData();
}
return _action;
return _levelData;
}
set => _action = value;
set => _levelData = value;
}
public Estimator CurrentEstimator { get => currentEstimator; internal set => currentEstimator = value; }
private YogaData _action = null;
private Estimator currentEstimator;
private Estimator _currentEstimator;
public Estimator CurrentEstimator { get => _currentEstimator; internal set => _currentEstimator = value; }
private YogaData _levelData = null;
public DateTime ActionStartTime { get; set; }
public void InitData()
{
_actions[AvatarAction.HeadTurnLeft] = new HeadTurnLeft();
@ -75,73 +95,259 @@ public class YogaManager : MonoSingleton<YogaManager>
_actions[AvatarAction.HeadTurnUp] = new HeadTurnUp();
_actions[AvatarAction.HeadTurnDown] = new HeadTurnDown();
_actions[AvatarAction.HandsUp] = new HandsUp();
_actions[AvatarAction.HandsHold] = new HandsHold();
_actions[AvatarAction.HandsDown] = new HandsHold();
_currentActionCount = 0;
_currentSuccessActionCount = 0;
//根据用户选择的动作索引,获取相应的资源
Action = YogaDataLoader.LoadData(ActionIndex);
LevelData = YogaDataLoader.LoadData(ActionIndex);
EventManager.Instance.Dispatch(YogaEventType.UpdateProgress, CurrentSuccessActionCount, CurrentActionCount);
}
private void OnEnable()
{
EventManager.Instance.AddEventListener(YogaEventType.ActionSuccess, OnActionSuccess);
EventManager.Instance.AddEventListener(YogaEventType.ActionFailed, OnActionFailed);
EventManager.Instance.AddEventListener(YogaEventType.UI_ScoreUpdate, ScoreUpdate);
EventManager.Instance.AddEventListener(YogaEventType.UI_LevelFinished, ClearingSettlement);
EventManager.Instance.AddEventListener(YogaEventType.Action_Success, OnActionSuccess);
EventManager.Instance.AddEventListener(YogaEventType.Action_Fail, OnActionFailed);
EventManager.Instance.AddEventListener(YogaEventType.Action_Start, OnActionStart);
EventManager.Instance.AddEventListener(YogaEventType.Action_End, OnActionEnd);
//extra event
EventManager.Instance.AddEventListener(YogaEventType.Action_MoveDistanceExactly, ExtraMoveDistanceExactly);
EventManager.Instance.AddEventListener(YogaEventType.Action_MoveDistanceNotAccurate, ExtraMoveDistanceNotAccurate);
EventManager.Instance.AddEventListener(YogaEventType.Action_SpeedTooSlow, ExtraSpeedTooSlow);
EventManager.Instance.AddEventListener(YogaEventType.Action_SpeedTooFast, ExtraSpeedTooFast);
}
private void OnDisable()
{
EventManager.Instance.RemoveEventListener(YogaEventType.ActionSuccess, OnActionSuccess);
EventManager.Instance.RemoveEventListener(YogaEventType.ActionFailed, OnActionFailed);
EventManager.Instance.RemoveEventListener(YogaEventType.UI_ScoreUpdate, ScoreUpdate);
EventManager.Instance.RemoveEventListener(YogaEventType.UI_LevelFinished, ClearingSettlement);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_Success, OnActionSuccess);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_Fail, OnActionFailed);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_Start, OnActionStart);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_End, OnActionEnd);
//extra event
EventManager.Instance.RemoveEventListener(YogaEventType.Action_MoveDistanceExactly, ExtraMoveDistanceExactly);
EventManager.Instance.AddEventListener(YogaEventType.Action_MoveDistanceNotAccurate, ExtraMoveDistanceNotAccurate);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_SpeedTooSlow, ExtraSpeedTooSlow);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_SpeedTooFast, ExtraSpeedTooFast);
}
#region UI相关
private void OnActionSuccess()
{
_currentSuccessActionCount++;
_currentActionCount++;
AudioManager.Instance.PlayCVInQueue("Correct");
UpdateData();
}
private void OnActionFailed()
{
_currentActionCount++;
AudioManager.Instance.PlayCVInQueue("Wrong");
UpdateData();
}
private void UpdateData()
{
//如果达到最大数,则停止检测,跳转到下一个动作/下一个动作引导/奖励界面
if (CurrentActionCount >= MaxActionCount)
if (CurrentActionCount > MaxActionCount)//如果超过最大数,则停止检测,跳转到下一个动作/下一个动作引导/奖励界面
{
//跳转到下一个动作/下一个动作引导/奖励界面
UIManager.Instance.CloseCurrent(); //关闭当前界面并停止检测
//args[0] = successCount args[1] = totalCount
UIManager.Instance.ShowPanel<ClearingSettlementUI>(false, CurrentSuccessActionCount, MaxActionCount);
LogPrint.Warning("CurrentActionCount > MaxActionCount", PrintLevel.Normal);
ClearingSettlement();
}
//args[0] = successCount args[1] = excutedCount args[2] = totalCount
EventManager.Instance.Dispatch(YogaEventType.UpdateProgress, CurrentSuccessActionCount, CurrentActionCount, MaxActionCount);
EventManager.Instance.Dispatch(YogaEventType.UpdateProgress, CurrentSuccessActionCount, CurrentActionCount, MaxActionCount);//args[0] = successCount args[1] = excutedCount args[2] = totalCount
}
public bool IsCorrectAction(List<Point> personPoints, AvatarAction actionType)
/// <summary>
/// 跳转结算界面
/// </summary>
public void ClearingSettlement()
{
if (!_actions.ContainsKey(actionType))
{
LogPrint.Error("ActionType is not exist");
return false;
}
var result = _actions[actionType].CheckPose(personPoints);
return result;
//跳转到奖励界面
UIManager.Instance.CloseCurrent(); //关闭当前界面并停止检测
UIManager.Instance.ShowPanel<ClearingSettlementUI>(false, CurrentSuccessActionCount, MaxActionCount);//args[0] = successCount args[1] = totalCount
}
public void ScoreUpdate()
{
if (_isCorrectAction)
{
EventManager.Instance.Dispatch(YogaEventType.Action_Success);
}
else
{
EventManager.Instance.Dispatch(YogaEventType.Action_Fail);
}
_isCorrectAction = false;//重置
}
#endregion
#region
//采样质量评估
public void SampleQualityEvaluation(AvatarAction actionType, DateTime startTime, DateTime endTime)
{
//获取时间间隔内的所有点及向量变化
var framePoints = _estimateKeyPointsCache.Where(x => x.Item1 >= startTime && x.Item1 <= endTime).ToList();
if (framePoints == null)
{
LogPrint.Warning("No point has been estimated!");
framePoints = new List<(DateTime, List<Point>)>();
}
//循环遍历所有的点,检测是否符合最低点数要求
var checkedPoints = new List<(DateTime, List<Point>)>();
for (int i = 0; i < framePoints.Count; i++)
{
var p = framePoints[i];
if (!ActionCheckPoints(p.Item2))
continue;
checkedPoints.Add(p);
}
if (checkedPoints.Count < 2) //0级实现逻辑
{
NeedMoreData(actionType, startTime, endTime);
}
else
{
_actions[actionType].AnalyzingAction(checkedPoints);
}
}
//需要更多数据
private void NeedMoreData(AvatarAction actionType, DateTime startTime, DateTime endTime)
{
//获取1秒后时间间隔内的所有点及向量变化
var points = _estimateKeyPointsCache.Where(x => x.Item1 >= startTime.AddSeconds(1) && x.Item1 <= endTime.AddSeconds(1)).ToList();
if (points == null)
{
//提示摆正姿势
LogPrint.Warning("No point has been estimated!");
return;
}
//检测动作是否正确
_actions[actionType].AnalyzingAction(points, true);
}
#endregion
#region
private void OnActionStart(params object[] args)
{
//如果上一次动作还未结束
if (_isActionRunning)
{
//结束上一次动作
OnActionEnd();
}
if (args == null || args.Length < 2)
{
LogPrint.Error("GetActionBasePoint args is null. Please check animation event trigger configuration.");
return;
}
try
{
AvatarAction actionType = (AvatarAction)args.FirstOrDefault();
bool isMoveBack = (bool)args.LastOrDefault();
LogPrint.Log($"PlayGuideVoice: {actionType}", PrintLevel.Normal);
if (isMoveBack)
{
AudioManager.Instance.PlayCVInQueue(actionType.ToString());
}
else
{
AudioManager.Instance.PlayCVInQueue("BackToPosition");
}
//获取开始时间标记戳
ActionStartTime = DateTime.Now;
_isActionRunning = true;
}
catch (Exception e)
{
LogPrint.Exception(e);
return;
}
}
private void OnActionEnd(params object[] args)
{
//如果上一次动作已经结束
if (!_isActionRunning)
return;
if (args == null || args.Length == 0)
{
LogPrint.Error("GetActionBasePoint args is null. Please check animation event trigger configuration.");
return;
}
try
{
AvatarAction actionType = (AvatarAction)args.FirstOrDefault();
bool isActionEnd = (bool)args.LastOrDefault();
var startTime = ActionStartTime;
var endTime = DateTime.Now;
LogPrint.Log($"PlayGuideVoice: {actionType}", PrintLevel.Normal);
if (isActionEnd)
{
AudioManager.Instance.PlayCVInQueue("End");
}
else
{
AudioManager.Instance.PlayCVInQueue("Hold");
}
//结束上一次动作
//对动作进行采样质量评估
SampleQualityEvaluation(actionType, startTime, endTime);
_isActionRunning = false;
}
catch (Exception e)
{
LogPrint.Exception(e);
return;
}
}
/// extra
private void ExtraMoveDistanceExactly()
{
AudioManager.Instance.PlayCVInQueue("ExactlyCorrect");
}
private void ExtraMoveDistanceNotAccurate()
{
AudioManager.Instance.PlayCVInQueue("NotAccurate");
}
private void ExtraSpeedTooFast()
{
AudioManager.Instance.PlayCVInQueue("SpeedTooFast");
}
private void ExtraSpeedTooSlow()
{
AudioManager.Instance.PlayCVInQueue("SpeedTooSlow");
}
#endregion
public bool ActionCheckPoints(List<Point> points)
{
if (points == null || points.Count == 0)
{
//LogPrint.Log("ActionCheckPoints points is null");
LogPrint.Log("ActionCheckPoints points is null");
return false;
}
@ -152,19 +358,19 @@ public class YogaManager : MonoSingleton<YogaManager>
// LogPrint.Warning($"ActionPoints p({i}): {i.tagName()}, value: {p.x},{p.y}");
//}
foreach (var p in Action.MustPoints)
foreach (var p in LevelData.MustPoints)
{
if (!p.IsValid(points)) //有一个点不符合 返回false
{
//LogPrint.Error($"ActionCheckPoints failed, {p} is not valid");
LogPrint.Error($"ActionCheckPoints failed, {p} is not valid");
return false;
}
}
//不设的情况下,不检测
if (Action.AnyPoints != null && Action.AnyPoints.Count > 0)
if (LevelData.AnyPoints != null && LevelData.AnyPoints.Count > 0)
{
foreach (var p in Action.AnyPoints)
foreach (var p in LevelData.AnyPoints)
{
if (p.IsValid(points)) //有一个点符合 返回true
{

View File

@ -40,10 +40,11 @@ public partial class SROptions
}
}
[Category("瑜伽设置")]
[Category("瑜伽设置"), DisplayName("WebCamera和USBCamera之间转换")]
public void SetCameraDeviceType()
{
//WebCamera和USBCamera之间转换
EventManager.Instance.Dispatch(YogaEventType.DEBUG_CONSOLE_ChangeCamMode);
}
[Category("瑜伽设置"), DisplayName("动作捕捉开关")]
@ -73,4 +74,7 @@ public partial class SROptions
}
}
//[Category("Debug 设置"), DisplayName("鱼眼透视畸变修正"), NumberRange(-3.5, 3.5)]
//public
}

View File

@ -5,7 +5,7 @@ using UnityEngine;
public class LogPrint
{
private static PrintLevel _level = PrintLevel.Normal;
private static PrintLevel _level = PrintLevel.Details;
public static int Level
{

View File

@ -0,0 +1,56 @@

using OpenCVForUnity.CoreModule;
using UnityEngine;
public class PictureUtility
{
private static Material _flipMaterial;
public static Material FlipMaterial
{
get
{
if (_flipMaterial == null)
_flipMaterial = Resources.Load<Material>("Materials/Unlit_FlipHorizontal");
return _flipMaterial;
}
set => _flipMaterial = value;
}
public static Texture2D HorizontalFlipTexture(Texture2D texture)
{
//得到图片的宽高
Texture2D retVal = new Texture2D(texture.width, texture.height);
RenderTexture tmp = RenderTexture.GetTemporary(texture.width, texture.height, 0, RenderTextureFormat.ARGB32);
Graphics.Blit(texture, tmp, _flipMaterial);
RenderTexture.active = tmp;
retVal.ReadPixels(new UnityEngine.Rect(0, 0, texture.width, texture.height), 0, 0);
RenderTexture.ReleaseTemporary(tmp);
return retVal;
}
public static Mat HorizontalFlipMat(Mat mat)
{
Mat dst = new Mat();
Core.flip(mat, dst, 1);
return dst;
}
//纠正鱼眼透视畸变
public static Mat Undistort(Mat src)
{
//摄像机的4个畸变系数k1,k2,k3,k4
Mat K = new Mat(3, 3, CvType.CV_64FC1);
K.put(0, 0, 1151.7, 0, 985.6, 0, 1153.4, 573.004, 0, 0, 1);
Mat D = new Mat(5, 1, CvType.CV_64FC1);
//D.put(0, 0, -0.42, 0.2196, 0.0038, 0.013, -0.06);
D.put(0, 0, -0.01, 0.09, 0, 0, -0.19);
Mat retVal = src.clone();
OpenCVForUnity.Calib3dModule.Calib3d.undistort(src, retVal, K, D);
return retVal;
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 6cf67ab838592d94aaae4e32fb70494f
guid: 4de373af1bafd2f448484f58d5d6eac3
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -1,14 +1,13 @@
using System;
using SRF;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Video;
using Yoga;
[RequireComponent(typeof(VideoPlayer))]
public class ActionGuideVideoPanel : UIPopupBase
{
public VideoPlayer _video;
private YogaData _action;
private YogaData _data;
private void Awake()
{
@ -18,10 +17,18 @@ public class ActionGuideVideoPanel : UIPopupBase
public override void Init(object[] pageData)
{
base.Init(pageData);
_action = pageData[0] as YogaData;
_data = pageData[0] as YogaData;
//动作引导界面
var video = Resources.Load<VideoClip>(_action.VideoPath);
Debug.Log(_data.VideoPath);
var video = Resources.Load<VideoClip>(_data.VideoPath);
if (_video == null)
{
_video = gameObject.GetComponentOrAdd<VideoPlayer>();
}
_video.clip = video;
_video.isLooping = true;
_video.playOnAwake = false;
_video.Prepare();
@ -30,7 +37,7 @@ public class ActionGuideVideoPanel : UIPopupBase
public void OnOKClicked()
{
PageDispose();
UIManager.Instance.ShowPanel<GuideUI>(_action);
UIManager.Instance.ShowPanel<GuideUI>(_data);
}
private void PageDispose()

View File

@ -1,9 +1,7 @@
using OpenCVForUnity.CoreModule;
using OpenCVForUnity.ImgprocModule;
using OpenCVForUnity.UnityUtils;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
@ -15,11 +13,15 @@ namespace Yoga
protected Mat _bgrMat;
protected bool _isOnCamCapture = false;
protected bool _isCorrectAction = false;
protected Texture2D _displayTexture;
public bool IsOnCamCapture { get => _isOnCamCapture; internal set => _isOnCamCapture = value; }
private void Awake()
{
Init();
}
public void Init()
{
Utils.setDebugMode(true); //打印日志
MatInitial();
@ -69,9 +71,9 @@ namespace Yoga
}
//YogaManager.Instance.CurrentEstimator.DebugPrint(ref img);
if (YogaManager.Instance.CurrPersonPoints != null && YogaManager.Instance.CurrPersonPoints.Count > 0)
if (YogaManager.Instance.CurrEstimateKeyPoints != null && YogaManager.Instance.CurrEstimateKeyPoints.Count > 0)
{
List<Point> points = YogaManager.Instance.CurrPersonPoints;
List<Point> points = YogaManager.Instance.CurrEstimateKeyPoints;
for (int i = 0; i < YogaConfig.POSE_PAIRS.GetLength(0); i++)
{
@ -116,69 +118,6 @@ namespace Yoga
this.enabled = false;
_isOnCamCapture = false;
}
private void GetActionBasePoint()
{
var startTime = DateTime.Now;
while (true)
{
if (YogaManager.Instance.CurrPersonPoints != null && YogaManager.Instance.CurrPersonPoints.Count != 0)
{
YogaManager.Instance.Points = YogaManager.Instance.CurrPersonPoints;
break;
}
if (startTime.AddMilliseconds(100) < DateTime.Now)
{
LogPrint.Error("GetActionBasePoint timeout");
break;
}
}
}
private void EstimateAction(params object[] args)
{
var type = args.FirstOrDefault();
if (type == null)
{
LogPrint.Error("EstimateAction type is null");
return;
}
AvatarAction actionType = (AvatarAction)args.FirstOrDefault();
//检测动作
var startTime = DateTime.Now;
while (true)
{
if (YogaManager.Instance.ActionCheckPoints(YogaManager.Instance.CurrPersonPoints))
{
_isCorrectAction = (_isCorrectAction || YogaManager.Instance.IsCorrectAction(YogaManager.Instance.CurrPersonPoints, actionType));
break;
}
if (startTime.AddMilliseconds(100) < DateTime.Now)
{
LogPrint.Warning("请摆正姿势");
LogPrint.Warning("EstimateAction timeout");
break;
}
}
}
public void ScoreUpdate()
{
if (_isCorrectAction)
{
EventManager.Instance.Dispatch(YogaEventType.ActionSuccess);
}
else
{
EventManager.Instance.Dispatch(YogaEventType.ActionFailed);
}
_isCorrectAction = false;//重置
}
#endregion
protected virtual void OnRelease()
@ -192,18 +131,12 @@ namespace Yoga
{
EventManager.Instance.AddEventListener(YogaEventType.StartMotionCapture, OnStartMotionCapture);
EventManager.Instance.AddEventListener(YogaEventType.StopMotionCapture, OnStopMotionCapture);
EventManager.Instance.AddEventListener(YogaEventType.EstimateAction, EstimateAction);
EventManager.Instance.AddEventListener(YogaEventType.ScoreUpdate, ScoreUpdate);
EventManager.Instance.AddEventListener(YogaEventType.GetActionBasePoint, GetActionBasePoint);
}
protected virtual void EventRemove()
{
EventManager.Instance.RemoveEventListener(YogaEventType.StartMotionCapture, OnStartMotionCapture);
EventManager.Instance.RemoveEventListener(YogaEventType.StopMotionCapture, OnStopMotionCapture);
EventManager.Instance.RemoveEventListener(YogaEventType.EstimateAction, EstimateAction);
EventManager.Instance.RemoveEventListener(YogaEventType.ScoreUpdate, ScoreUpdate);
EventManager.Instance.RemoveEventListener(YogaEventType.GetActionBasePoint, GetActionBasePoint);
}
protected abstract void MatInitial();
protected abstract Mat GetMat();

View File

@ -10,12 +10,6 @@ namespace Yoga
{
public class MotionUSBCameraCaptureManager : CaptureManagerBase, IUVCDrawer
{
private Material _flipImg;
private void Awake()
{
_flipImg = Resources.Load<Material>("Materials/Unlit_FlipHorizontal");
}
protected override Mat GetMat()
{
Mat img = null;
@ -46,7 +40,7 @@ namespace Yoga
Texture2D tmpTex = new Texture2D(UVCManager.Instance.DefaultWidth, UVCManager.Instance.DefaultHeight);
Utils.textureToTexture2D(picCaptured, tmpTex);
tmpTex = HorizontalFlipTexture(tmpTex);//picCaptured texture水平反转
tmpTex = PictureUtility.HorizontalFlipTexture(tmpTex);//picCaptured texture水平反转
img = new Mat(UVCManager.Instance.DefaultHeight, UVCManager.Instance.DefaultWidth, CvType.CV_8UC3);
Utils.texture2DToMat(tmpTex, img);
}
@ -62,18 +56,6 @@ namespace Yoga
Debug.LogWarning("USB Camera!");
}
public Texture2D HorizontalFlipTexture(Texture2D texture)
{
//得到图片的宽高
Texture2D retVal = new Texture2D(texture.width, texture.height);
RenderTexture tmp = RenderTexture.GetTemporary(texture.width, texture.height, 0, RenderTextureFormat.ARGB32);
Graphics.Blit(texture, tmp, _flipImg);
RenderTexture.active = tmp;
retVal.ReadPixels(new UnityEngine.Rect(0, 0, texture.width, texture.height), 0, 0);
RenderTexture.ReleaseTemporary(tmp);
return retVal;
}
#region UVC
public UVCFilter[] UVCFilters;
private Texture SavedTexture;

View File

@ -1,4 +1,5 @@
using OpenCVForUnity.CoreModule;
using OpenCVForUnity.ImgprocModule;
using OpenCVForUnity.UnityUtils;
using OpenCVForUnity.UnityUtils.Helper;
using UnityEngine;
@ -8,8 +9,10 @@ namespace Yoga
{
public class MotionVideoCaptureManager : CaptureManagerBase
{
public bool FlipHorizontal = true;
private VideoCaptureToMatHelper _videoCaptureToMatHelper;
private readonly string VIDEO_FILENAME = "Video/WIN_20231124_19_56_12_Pro.mp4";
private readonly string VIDEO_FILENAME = "Video/WIN_20231124_20_02_38_Pro.mp4";
protected override Mat GetMat()
{
Mat img = null;
@ -18,7 +21,8 @@ namespace Yoga
_videoCaptureToMatHelper.Play();
if (_videoCaptureToMatHelper.IsPlaying() && _videoCaptureToMatHelper.DidUpdateThisFrame())
{
img = _videoCaptureToMatHelper.GetMat();
//img = PictureUtility.HorizontalFlipMat(_videoCaptureToMatHelper.GetMat());
//img = PictureUtility.Undistort(img);
}
return img;
@ -73,6 +77,10 @@ namespace Yoga
Camera.main.orthographicSize = height / 2;
}
if (!CVEstimator.Instance.IsInited)
{
CVEstimator.Instance.Init();
}
_bgrMat = new Mat(rgbMat.rows(), rgbMat.cols(), CvType.CV_8UC3);
}

View File

@ -7,12 +7,6 @@ public class TestManager : MonoBehaviour
// Start is called before the first frame update
void Start()
{
CVEstimator.Instance.Init();
}
// Update is called once per frame
void Update()
{
UIManager.Instance.ShowPanel<TestUI>();
}
}

View File

@ -5,6 +5,7 @@ using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using Yoga;
public class GuideUI : UIPanelBase
{
@ -44,17 +45,19 @@ public class GuideUI : UIPanelBase
private void OnEnable()
{
EventManager.Instance.AddEventListener(YogaEventType.PlayAnimation, PlayAnimation);
EventManager.Instance.AddEventListener(YogaEventType.ActionSuccess, ShowSuccessEffect);
EventManager.Instance.AddEventListener(YogaEventType.Action_Success, ShowSuccessEffect);
EventManager.Instance.AddEventListener(YogaEventType.UpdateProgress, UpdateSuccessCount);
EventManager.Instance.AddEventListener(YogaEventType.ActionFailed, ShowFailEffect);
EventManager.Instance.AddEventListener(YogaEventType.Action_Fail, ShowFailEffect);
EventManager.Instance.AddEventListener(YogaEventType.DEBUG_CONSOLE_ChangeCamMode, ChangeCameraCaptureMode);
}
private void OnDisable()
{
EventManager.Instance.RemoveEventListener(YogaEventType.PlayAnimation, PlayAnimation);
EventManager.Instance.RemoveEventListener(YogaEventType.ActionSuccess, ShowSuccessEffect);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_Success, ShowSuccessEffect);
EventManager.Instance.RemoveEventListener(YogaEventType.UpdateProgress, UpdateSuccessCount);
EventManager.Instance.RemoveEventListener(YogaEventType.ActionFailed, ShowFailEffect);
EventManager.Instance.RemoveEventListener(YogaEventType.Action_Fail, ShowFailEffect);
EventManager.Instance.RemoveEventListener(YogaEventType.DEBUG_CONSOLE_ChangeCamMode, ChangeCameraCaptureMode);
}
#region Event Func
@ -154,7 +157,7 @@ public class GuideUI : UIPanelBase
base.OnEnter();
_guide.SetActive(true);
EventManager.Instance.Dispatch(YogaEventType.StartMotionCapture);
EventManager.Instance.Dispatch(YogaEventType.PlayAnimation, YogaManager.Instance.Action.Action);
EventManager.Instance.Dispatch(YogaEventType.PlayAnimation, YogaManager.Instance.LevelData.Action);
_startTime = DateTime.Now;
InvokeRepeating("ProgressUpdate", 0, 0.05f); //20fps
@ -168,4 +171,31 @@ public class GuideUI : UIPanelBase
GuideMgr.Stop();
EventManager.Instance.Dispatch(YogaEventType.StopMotionCapture);
}
private void ChangeCameraCaptureMode()
{
Transform webCam = _content.Find("WebCameraCaptureManager");
Transform usbCam = _content.Find("USBCameraCaptureManager");
CaptureManagerBase manager;
if (webCam == null || usbCam == null)
{
LogPrint.Error("ChangeCameraCaptureMode webCam or usbCam is null");
return;
}
if (webCam.gameObject.activeSelf)
{
webCam.gameObject.SetActive(false);
usbCam.gameObject.SetActive(true);
manager = usbCam.GetComponent<MotionUSBCameraCaptureManager>();
}
else
{
webCam.gameObject.SetActive(true);
usbCam.gameObject.SetActive(false);
manager = webCam.GetComponent<MotionWebCaptureManager>();
}
manager.Init();
manager.IsOnCamCapture = true;
CVEstimator.Instance.StartEstimation();
}
}

View File

@ -5,19 +5,26 @@ using Yoga;
public class RobotController : MonoBehaviour
{
public void CheckAction(AvatarAction action)
public void ActionEnd(AvatarAction action)
{
EventManager.Instance.Dispatch(YogaEventType.EstimateAction, action);
EventManager.Instance.Dispatch(YogaEventType.Action_End, action, true);
}
public void ActionHold(AvatarAction action)
{
EventManager.Instance.Dispatch(YogaEventType.Action_End, action, false);
}
public void FinishCurrentLevel()
{
EventManager.Instance.Dispatch(YogaEventType.UI_LevelFinished);
}
public void FinishCurrentActionCheck()
public void ActionStart(AvatarAction action)
{
EventManager.Instance.Dispatch(YogaEventType.ScoreUpdate);
EventManager.Instance.Dispatch(YogaEventType.Action_Start, action, true);
}
public void GetActionBasePoint()
public void ActionBackStart(AvatarAction action)
{
EventManager.Instance.Dispatch(YogaEventType.GetActionBasePoint);
EventManager.Instance.Dispatch(YogaEventType.Action_Start, action, false);
}
}
@ -33,6 +40,8 @@ public enum AvatarAction
HeadShake,
Nod,
HandsUp,
HandsHold,
HandsDown,
Stop,
Hold,
None
}

View File

@ -1,6 +1,7 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Yoga;
public class TestUI : UIPanelBase
{
@ -8,4 +9,25 @@ public class TestUI : UIPanelBase
{
base.Init(pageData);
}
public override void OnEnter()
{
base.OnEnter();
var manager = FindAnyObjectByType<MotionVideoCaptureManager>();
manager.IsOnCamCapture = true;
GlobalData.Instance.IsEstimationPrintMode = true;
CVEstimator.Instance.StartEstimation();
}
public void OnPosBtnClick()
{
if (GlobalData.Instance.Position == PositionType.CoDriver)
{
GlobalData.Instance.Position = PositionType.Driver;
}
else
{
GlobalData.Instance.Position = PositionType.CoDriver;
}
}
}

View File

@ -17,6 +17,7 @@ public static class UILoadConfig
{ "HudUI" , "UI/HUDRoot" },
{ "MeditationVideoUI" , "UI/MeditationVideoPanel" },
{ "FaceDetectUI" , "UI/FaceDetectUI" },
{ "TestUI" , "UI/TestUI" },
};
public static string GetPath(string typeName)

View File

@ -7,10 +7,6 @@ public class YogaMainManager : MonoBehaviour
private void Awake()
{
UIManager.Instance.LoadReset();
if (YogaManager.Instance.Action == null)
YogaManager.Instance.InitData();
UIManager.Instance.ShowPanel<ActionGuideVideoPanel>(false, YogaManager.Instance.Action);
UIManager.Instance.ShowPanel<ActionGuideVideoPanel>(false, YogaManager.Instance.LevelData);
}
}

View File

@ -131,7 +131,6 @@ public static class YogaConfig
var point = points[BODY_PARTS[partName]];
if (point == new Point(-1, -1))
{
LogPrint.Log($"{partName}不在画面中");
return false;
}
@ -139,6 +138,7 @@ public static class YogaConfig
}
public static readonly double[] InMean = new double[] { 128.0, 128.0, 128.0 };
public static int CurrEstimateKeyPointsMaxCount = 300;
}

View File

@ -19,7 +19,7 @@ public class YogaDataLoader
MaxActionCount = 1000,
TotalSeconds = 20.0f,
RectCutRate = 0.2f,
MustPoints = new List<string>() { "Nose", "REye", "LEye", "Neck" },
MustPoints = new List<string>() { "Nose", /*"REye", "LEye", */"Neck" },
//AnyPoints = new List<string>() { "RWrist", "LWrist" }
};
#endif