浏览代码
Revert "Merge from master"
Revert "Merge from master"
This reverts commit c0828e485298b9f68da2fa99db015d21dcd904cf./schema-0.1.0
You-Cyuan Jhang
3 年前
当前提交
66a2d04d
共有 305 个文件被更改,包括 3604 次插入 和 4538 次删除
-
17.github/pull_request_template.md
-
6.gitignore
-
143.yamato/promotion.yml
-
43.yamato/upm-ci-testprojects.yml
-
125.yamato/upm-ci-full.yml
-
2LICENSE.md
-
87README.md
-
74TestProjects/PerceptionHDRP/Assets/HDRenderPipelineAsset.asset
-
492TestProjects/PerceptionHDRP/Assets/Scenes/SampleScene.unity
-
11TestProjects/PerceptionHDRP/Packages/manifest.json
-
5TestProjects/PerceptionHDRP/ProjectSettings/EditorBuildSettings.asset
-
2TestProjects/PerceptionHDRP/ProjectSettings/EditorSettings.asset
-
31TestProjects/PerceptionHDRP/ProjectSettings/ProjectSettings.asset
-
4TestProjects/PerceptionHDRP/ProjectSettings/ProjectVersion.txt
-
559TestProjects/PerceptionURP/Assets/Scenes/SampleScene.unity
-
3TestProjects/PerceptionURP/Assets/Settings/ForwardRenderer.asset
-
2TestProjects/PerceptionURP/Assets/Settings/ForwardRenderer.asset.meta
-
5TestProjects/PerceptionURP/Assets/Settings/UniversalRP-HighQuality.asset
-
9TestProjects/PerceptionURP/Packages/manifest.json
-
2TestProjects/PerceptionURP/ProjectSettings/EditorSettings.asset
-
2TestProjects/PerceptionURP/ProjectSettings/GraphicsSettings.asset
-
49TestProjects/PerceptionURP/ProjectSettings/ProjectSettings.asset
-
4TestProjects/PerceptionURP/ProjectSettings/UnityConnectSettings.asset
-
4TestProjects/PerceptionURP/ProjectSettings/ProjectVersion.txt
-
414com.unity.perception/CHANGELOG.md
-
173com.unity.perception/Documentation~/Schema/Synthetic_Dataset_Schema.md
-
35com.unity.perception/Documentation~/SetupSteps.md
-
125com.unity.perception/Documentation~/images/LabelingConfigurationFinished.PNG
-
366com.unity.perception/Documentation~/images/MainCameraConfig.PNG
-
28com.unity.perception/Editor/Unity.Perception.Editor.asmdef
-
3com.unity.perception/Editor/GroundTruth/InstanceSegmentationPassEditor.cs
-
2com.unity.perception/Editor/GroundTruth/LabelingConfigurationEditor.cs.meta
-
934com.unity.perception/Editor/GroundTruth/LabelingEditor.cs
-
2com.unity.perception/Editor/GroundTruth/LabelingEditor.cs.meta
-
2com.unity.perception/Editor/GroundTruth/SemanticSegmentationPassEditor.cs
-
2com.unity.perception/LICENSE.md
-
1com.unity.perception/Runtime/AssemblyInfo.cs
-
16com.unity.perception/Runtime/Unity.Perception.Runtime.asmdef
-
45com.unity.perception/Runtime/GroundTruth/GroundTruthRendererFeature.cs
-
23com.unity.perception/Runtime/GroundTruth/IGroundTruthGenerator.cs
-
64com.unity.perception/Runtime/GroundTruth/Labeling/Labeling.cs
-
2com.unity.perception/Runtime/GroundTruth/Labeling/StartingLabelId.cs
-
69com.unity.perception/Runtime/GroundTruth/RenderTextureReader.cs
-
25com.unity.perception/Runtime/GroundTruth/RenderedObjectInfo.cs
-
121com.unity.perception/Runtime/GroundTruth/RenderedObjectInfoGenerator.cs
-
10com.unity.perception/Runtime/GroundTruth/Resources/InstanceSegmentation.shader
-
18com.unity.perception/Runtime/GroundTruth/Resources/LabeledObjectHistogram.compute
-
29com.unity.perception/Runtime/GroundTruth/Resources/SemanticSegmentation.shader
-
123com.unity.perception/Runtime/GroundTruth/SimulationManager.cs
-
5com.unity.perception/Runtime/GroundTruth/Ego.cs
-
871com.unity.perception/Runtime/GroundTruth/PerceptionCamera.cs
-
210com.unity.perception/Runtime/GroundTruth/SimulationState.cs
-
18com.unity.perception/Runtime/GroundTruth/SimulationState_Json.cs
-
6com.unity.perception/Tests/Editor/BuildPerceptionPlayer.cs
-
16com.unity.perception/Tests/Editor/Unity.Perception.Editor.Tests.asmdef
-
175com.unity.perception/Tests/Editor/PerceptionCameraEditorTests.cs
-
46com.unity.perception/Tests/Editor/SimulationManagerEditorTests.cs
-
2com.unity.perception/Tests/Runtime/Unity.Perception.Runtime.Tests.asmdef
-
11com.unity.perception/Tests/Runtime/GroundTruthTests/DatasetJsonUtilityTests.cs
-
36com.unity.perception/Tests/Runtime/GroundTruthTests/TestHelper.cs
-
40com.unity.perception/Tests/Runtime/GroundTruthTests/GroundTruthTestBase.cs
-
122com.unity.perception/Tests/Runtime/GroundTruthTests/PerceptionCameraIntegrationTests.cs
-
520com.unity.perception/Tests/Runtime/GroundTruthTests/SegmentationGroundTruthTests.cs
-
32com.unity.perception/package.json
-
2com.unity.perception/Editor/GroundTruth/ObjectCountPassEditor.cs.meta
-
2com.unity.perception/Runtime/GroundTruth/GroundTruthInfo.cs.meta
-
8com.unity.perception/Runtime/GroundTruth/GroundTruthLabelSetupSystem.cs.meta
-
8com.unity.perception/Runtime/GroundTruth/GroundTruthPass.cs.meta
-
2com.unity.perception/Runtime/GroundTruth/ObjectCountPass.cs.meta
-
2com.unity.perception/Runtime/GroundTruth/SimulationManagementComponentSystem.cs.meta
-
2com.unity.perception/Runtime/GroundTruth/Labeling/LabelingConfiguration.cs.meta
-
35com.unity.perception/Runtime/GroundTruth/GroundTruthPass.cs
-
14com.unity.perception/Runtime/GroundTruth/InstanceSegmentationPass.cs
-
25com.unity.perception/Runtime/GroundTruth/SemanticSegmentationPass.cs
-
2com.unity.perception/Runtime/GroundTruth/SemanticSegmentationPass.cs.meta
-
2com.unity.perception/Runtime/GroundTruth/GroundTruthCrossPipelinePass.cs.meta
-
2com.unity.perception/Runtime/GroundTruth/InstanceSegmentationCrossPipelinePass.cs.meta
-
2com.unity.perception/Runtime/GroundTruth/SemanticSegmentationCrossPipelinePass.cs.meta
-
8TestProjects/PerceptionHDRP/Assets/LabelingConfiguration.asset.meta
-
26TestProjects/PerceptionHDRP/Assets/LabelingConfiguration.asset
-
8TestProjects/PerceptionURP/Assets/ExampleLabelingConfiguration.asset.meta
-
8TestProjects/PerceptionURP/Assets/Settings/UniversalRP-HighQuality.asset.meta
-
26TestProjects/PerceptionURP/Assets/ExampleLabelingConfiguration.asset
-
48com.unity.perception/Documentation~/GettingStarted.md
-
27com.unity.perception/Documentation~/GroundTruth-Labeling.md
-
15com.unity.perception/Documentation~/index.md
-
21com.unity.perception/Editor/GroundTruth/ObjectCountPassEditor.cs
-
157com.unity.perception/Editor/GroundTruth/LabelingConfigurationEditor.cs
-
107com.unity.perception/Runtime/GroundTruth/GroundTruthCrossPipelinePass.cs
-
15com.unity.perception/Runtime/GroundTruth/GroundTruthInfo.cs
-
106com.unity.perception/Runtime/GroundTruth/GroundTruthLabelSetupSystem.cs
-
74com.unity.perception/Runtime/GroundTruth/InstanceSegmentationCrossPipelinePass.cs
-
108com.unity.perception/Runtime/GroundTruth/Labeling/LabelingConfiguration.cs
-
181com.unity.perception/Runtime/GroundTruth/ObjectCountPass.cs
-
64com.unity.perception/Runtime/GroundTruth/SemanticSegmentationCrossPipelinePass.cs
-
13com.unity.perception/Runtime/GroundTruth/SimulationManagementComponentSystem.cs
-
192com.unity.perception/Tests/Runtime/GroundTruthTests/BoundingBox2DTests.cs
-
253com.unity.perception/Tests/Runtime/GroundTruthTests/Main Camera.prefab
-
7com.unity.perception/Tests/Runtime/GroundTruthTests/Main Camera.prefab.meta
-
147com.unity.perception/Tests/Runtime/GroundTruthTests/ObjectCountTests.cs
|
|||
# Peer Review Information: |
|||
Information on any code, feature, documentation changes here |
|||
**Editor Version Target**: 2019.4 |
|||
**Editor Version Target (i.e. 19.3, 20.1)**: 2019.3 |
|||
|
|||
<br> |
|||
**Package Tests (Pass/Fail)**: |
|||
[X] - Make sure automation passes |
|||
<br> |
|||
|
|||
<br> |
|||
|
|||
## Checklist |
|||
- [ ] - Updated docs |
|||
- [ ] - Updated changelog |
|||
- [ ] - Updated test rail |
|||
<br> |
|||
**Notes + Expectations**: |
|
|||
{% metadata_file .yamato/environments.yml %} |
|||
|
|||
--- |
|||
{% for variant in package_variants %} |
|||
{% for editor in complete_editors %} |
|||
{% for platform in test_platforms %} |
|||
promotion_test_{{ platform.name }}_{{ editor.version }}: |
|||
name : Package promotion tests ({{variant.name}} pkg, {{ editor.version }}, {{ platform.name }}) |
|||
agent: |
|||
type: {{ platform.type }} |
|||
image: {{ platform.image }} |
|||
flavor: {{ platform.flavor}} |
|||
variables: |
|||
UPMCI_PROMOTION: 1 |
|||
commands: |
|||
- git submodule update --init --recursive |
|||
- npm install upm-ci-utils@stable -g --registry {{ upmci_registry }} |
|||
- upm-ci package test -u {{ editor.version }} --package-path ./com.unity.perception --type vetting-tests |
|||
artifacts: |
|||
logs: |
|||
paths: |
|||
- "upm-ci~/test-results/**/*" |
|||
dependencies: |
|||
- .yamato/upm-ci-full.yml#pack_{{ variant.name }} |
|||
{% endfor %} |
|||
{% endfor %} |
|||
{% endfor %} |
|||
|
|||
promotion_test_trigger: |
|||
name: Promotion Tests Trigger |
|||
dependencies: |
|||
{% for editor in complete_editors %} |
|||
{% for platform in publish_platforms %} |
|||
{% for suite in suites %} |
|||
{% for project in projects %} |
|||
- .yamato/promote.yml#promotion_test_{{platform.name}}_{{editor.version}} |
|||
- .yamato/upm-ci-full.yml#pkg_test_Perception_{{platform.name}}_{{editor.version}} |
|||
- .yamato/upm-ci-testprojects.yml#{{project.name}}_windows_{{suite.name}}_{{editor.version}} |
|||
{% endfor %} |
|||
{% endfor %} |
|||
{% endfor %} |
|||
{% endfor %} |
|||
|
|||
|
|||
promote: |
|||
name: Promote to Production |
|||
agent: |
|||
type: Unity::VM |
|||
image: package-ci/win10:stable |
|||
flavor: b1.large |
|||
variables: |
|||
UPMCI_PROMOTION: 1 |
|||
commands: |
|||
- npm install upm-ci-utils@stable -g --registry {{ upmci_registry }} |
|||
- upm-ci package promote --package-path ./com.unity.perception |
|||
# The Yamato build step `publish` will publish the com.unity.perception package to the `upm-candidates` registry. To see which versions of the package have been published, see |
|||
# * https://artifactory.prd.cds.internal.unity3d.com/artifactory/webapp/#/artifacts/browse/tree/General/upm-candidates/com.unity.perception |
|||
# * https://bintray.com/unity |
|||
#test_editors: |
|||
# - version: 2019.1 |
|||
#test_platforms: |
|||
# - name: win |
|||
# type: Unity::VM |
|||
# image: package-ci/win10:stable |
|||
# flavor: b1.large |
|||
#--- |
|||
#{% for editor in test_editors %} |
|||
#{% for platform in test_platforms %} |
|||
#promotion_test_{{ platform.name }}_{{ editor.version }}: |
|||
# name : Promotion Test {{ editor.version }} on {{ platform.name }} |
|||
# agent: |
|||
# type: {{ platform.type }} |
|||
# image: {{ platform.image }} |
|||
# flavor: {{ platform.flavor}} |
|||
# variables: |
|||
# UPMCI_PROMOTION: 1 |
|||
# commands: |
|||
# - npm install upm-ci-utils@latest -g --registry https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-npm |
|||
# - upm-ci package test --unity-version {{ editor.version }} |
|||
# artifacts: |
|||
# logs: |
|||
# paths: |
|||
# - "upm-ci~/test-results/**/*" |
|||
# dependencies: |
|||
# - .yamato/upm-ci.yml#pack |
|||
#{% endfor %} |
|||
#{% endfor %} |
|||
# |
|||
#promotion_test_trigger: |
|||
# name: Promotion Tests Trigger |
|||
# agent: |
|||
# type: Unity::VM |
|||
# image: package-ci/win10:stable |
|||
# flavor: b1.large |
|||
# artifacts: |
|||
# logs: |
|||
# paths: |
|||
# - "upm-ci~/test-results/**/*" |
|||
# packages: |
|||
# paths: |
|||
# - "upm-ci~/packages/**/*" |
|||
# dependencies: |
|||
#{% for editor in test_editors %} |
|||
#{% for platform in test_platforms %} |
|||
# - .yamato/promotion.yml#promotion_test_{{platform.name}}_{{editor.version}} |
|||
#{% endfor %} |
|||
#{% endfor %} |
|||
# |
|||
#promote: |
|||
# name: Promote to Production |
|||
# agent: |
|||
# type: Unity::VM |
|||
# image: package-ci/win10:stable |
|||
# flavor: b1.large |
|||
# variables: |
|||
# UPMCI_PROMOTION: 1 |
|||
# commands: |
|||
# - npm install upm-ci-utils@latest -g --registry https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-npm |
|||
# - upm-ci package promote |
|||
artifacts: |
|||
artifacts: |
|||
paths: |
|||
- "upm-ci~/packages/*.tgz" |
|||
dependencies: |
|||
{% for variant in package_variants %} |
|||
{% for editor in complete_editors %} |
|||
{% for platform in publish_platforms %} |
|||
- .yamato/upm-ci-full.yml#pack_{{ variant.name }} |
|||
- .yamato/promote.yml#promotion_test_{{ platform.name }}_{{ editor.version }} |
|||
{% endfor %} |
|||
{% endfor %} |
|||
{% endfor %} |
|||
# artifacts: |
|||
# artifacts: |
|||
# paths: |
|||
# - "upm-ci~/packages/*.tgz" |
|||
# dependencies: |
|||
# - .yamato/upm-ci.yml#pack |
|||
#{% for editor in test_editors %} |
|||
#{% for platform in test_platforms %} |
|||
# - .yamato/promotion.yml#promotion_test_{{ platform.name }}_{{ editor.version }} |
|||
#{% endfor %} |
|||
#{% endfor %} |
|
|||
<img src="com.unity.perception/Documentation~/images/unity-wide-whiteback.png" align="middle" width="3000"/> |
|||
<img src="com.unity.perception/Documentation~/images/unity-wide.png" align="middle" width="3000"/> |
|||
![ReleaseBadge](https://badge-proxy.cds.internal.unity3d.com/5ab9a162-9dd0-4ba1-ba41-cf25378a927a) |
|||
# Perception |
|||
The Perception package provides a toolkit for generating large-scale datasets for perception-based machine learning training and validation. It is focused on a handful of camera-based use cases for now and will ultimately expand to other forms of sensors and machine learning tasks. |
|||
<img src="https://img.shields.io/badge/unity-2019.4-green.svg?style=flat-square" alt="unity 2019.4"> |
|||
<img src="https://img.shields.io/badge/unity-2020.2-green.svg?style=flat-square" alt="unity 2020.2"> |
|||
|
|||
> com.unity.perception is in active development. Its features and API are subject to significant change as development progresses. |
|||
|
|||
|
|||
# Perception Package ([Unity Computer Vision](https://unity.com/computer-vision)) |
|||
|
|||
The Perception package provides a toolkit for generating large-scale datasets for computer vision training and validation. It is focused on a handful of camera-based use cases for now and will ultimately expand to other forms of sensors and machine learning tasks. |
|||
|
|||
Visit the [Unity Computer Vision](https://unity.com/computer-vision) page for more information on our tools and offerings! |
|||
|
|||
## Getting Started |
|||
|
|||
**[Quick Installation Instructions](com.unity.perception/Documentation~/SetupSteps.md)** |
|||
Get your local Perception workspace up and running quickly. Recommended for users with prior Unity experience. |
|||
|
|||
**[Perception Tutorial](com.unity.perception/Documentation~/Tutorial/TUTORIAL.md)** |
|||
Detailed instructions covering all the important steps from installing Unity Editor, to creating your first computer vision data generation project, building a randomized Scene, and generating large-scale synthetic datasets by leveraging the power of Unity Simulation. No prior Unity experience required. |
|||
|
|||
**[Human Pose Labeling and Randomization Tutorial](com.unity.perception/Documentation~/HPTutorial/TUTORIAL.md)** |
|||
Step by step instructions for using the keypoint, pose, and animation randomization tools included in the Perception package. It is recommended that you finish Phase 1 of the Perception Tutorial above before starting this tutorial. |
|||
|
|||
## Documentation |
|||
In-depth documentation on individual components of the package. |
|||
|
|||
|Feature|Description| |
|||
|---|---| |
|||
|[Labeling](com.unity.perception/Documentation~/GroundTruthLabeling.md)|A component that marks a GameObject and its descendants with a set of labels| |
|||
|[Label Config](com.unity.perception/Documentation~/GroundTruthLabeling.md#label-config)|An asset that defines a taxonomy of labels for ground truth generation| |
|||
|[Perception Camera](com.unity.perception/Documentation~/PerceptionCamera.md)|Captures RGB images and ground truth from a [Camera](https://docs.unity3d.com/Manual/class-Camera.html).| |
|||
|[Dataset Capture](com.unity.perception/Documentation~/DatasetCapture.md)|Ensures sensors are triggered at proper rates and accepts data for the JSON dataset.| |
|||
|[Randomization](com.unity.perception/Documentation~/Randomization/Index.md)|The Randomization tool set lets you integrate domain randomization principles into your simulation.| |
|||
## Documenation |
|||
**Click [here](com.unity.perception/Documentation~/SetupSteps.md) to set up a Perception project** |
|||
## Community and Support |
|||
**Click [here](com.unity.perception/Documentation~/GettingStarted.md) to get the started with Perception** |
|||
For setup problems or discussions about leveraging the Perception package in your project, please create a new thread on the **[Unity Computer Vision forum](https://forum.unity.com/forums/computer-vision.626/)** and make sure to include as much detail as possible. If you run into any other problems with the Perception package or have a specific feature request, please submit a **[GitHub issue](https://github.com/Unity-Technologies/com.unity.perception/issues)**. |
|||
|
|||
For any other questions or feedback, connect directly with the Computer Vision team at [computer-vision@unity3d.com](mailto:computer-vision@unity3d.com). |
|||
|
|||
## Example Projects |
|||
|
|||
### SynthDet |
|||
|
|||
<img src="com.unity.perception/Documentation~/images/synthdet.png"/> |
|||
|
|||
[SynthDet](https://github.com/Unity-Technologies/SynthDet) is an end-to-end solution for training a 2D object detection model using synthetic data. |
|||
|
|||
### Unity Simulation Smart Camera example |
|||
<img src="com.unity.perception/Documentation~/images/smartcamera.png"/> |
|||
|
|||
The [Unity Simulation Smart Camera Example](https://github.com/Unity-Technologies/Unity-Simulation-Smart-Camera-Outdoor) illustrates how the Perception package could be used in a smart city or autonomous vehicle simulation. You can generate datasets locally or at scale in [Unity Simulation](https://unity.com/products/unity-simulation). |
|||
|
|||
|
|||
### Robotics Object Pose Estimation Demo |
|||
<img src="com.unity.perception/Documentation~/images/robotics_pose.png"/> |
|||
|
|||
The [Robotics Object Pose Estimation Demo & Tutorial](https://github.com/Unity-Technologies/Robotics-Object-Pose-Estimation) demonstrates pick-and-place with a robot arm in Unity. It includes using ROS with Unity, importing URDF models, collecting labeled training data using the Perception package, and training and deploying a deep learning model. |
|||
|
|||
## Local development |
|||
The repository includes two projects for local development in `TestProjects` folder, one set up for HDRP and the other for URP. |
|||
|
|||
### Suggested IDE Setup |
|||
## Suggested IDE Setup |
|||
|
|||
## Known issues |
|||
|
|||
* The Linux Editor 2019.4.7f1 and 2019.4.8f1 might hang when importing HDRP-based Perception projects. For Linux Editor support, use 2019.4.6f1 or 2020.1 |
|||
* To get automatic feedback and fixups on formatting and naming convention violations, set up Rider/JetBrains with our Unity standard .dotsettings file by following [these instructions](https://github.cds.internal.unity3d.com/unity/com.unity.coding/tree/master/UnityCoding/Packages/com.unity.coding/Coding~/Configs/JetBrains). |
|||
* If you use VS Code, install the Editorconfig extension to get automatic code formatting according to our convention |
|||
|
|||
## Citation |
|||
If you find this package useful, consider citing it using: |
|||
``` |
|||
@misc{com.unity.perception2021, |
|||
title={Unity {P}erception Package}, |
|||
author={{Unity Technologies}}, |
|||
howpublished={\url{https://github.com/Unity-Technologies/com.unity.perception}}, |
|||
year={2020} |
|||
} |
|||
``` |
|
|||
m_EditorVersion: 2019.4.19f1 |
|||
m_EditorVersionWithRevision: 2019.4.19f1 (ca5b14067cec) |
|||
m_EditorVersion: 2019.3.13f1 |
|||
m_EditorVersionWithRevision: 2019.3.13f1 (d4ddf0d95db9) |
|
|||
m_EditorVersion: 2019.4.19f1 |
|||
m_EditorVersionWithRevision: 2019.4.19f1 (ca5b14067cec) |
|||
m_EditorVersion: 2019.3.13f1 |
|||
m_EditorVersionWithRevision: 2019.3.13f1 (d4ddf0d95db9) |
|
|||
# Installing the Perception package in your project |
|||
# Setup for local development |
|||
* Clone the [Perception](https://github.com/Unity-Technologies/com.unity.perception) repository |
|||
* Install and use Unity latest [2019.3 Unity editor](https://unity.com/releases/2019-3) |
|||
![ReleaseBadge](https://badge-proxy.cds.internal.unity3d.com/5ab9a162-9dd0-4ba1-ba41-cf25378a927a) |
|||
## Setting up a Project |
|||
Below are two options for getting started using the Perception package. Option 1 is opening existing test projects in the repository. Option 2 new Unity project and integrate the Perception package. |
|||
This page provides brief instructions on installing the Perception package. Head over to the [Perception Tutorial](Tutorial/TUTORIAL.md) for more detailed instructions and steps for building a sample project. |
|||
### Option 1: PerceptionHDRP & PerceptionURP Projects |
|||
The repository includes two projects for local development in `TestProjects` folder, one set up for HDRP and the other for URP. You can open these with the Unity |
|||
editor you installed in Setup instructions. |
|||
<img src="images/TestProjects.PNG" align="middle"/> |
|||
1. Install the latest version of **2020.2.x** Unity Editor from [here](https://unity3d.com/get-unity/download/archive). (The Perception package has not been fully tested on newer Unity versions) |
|||
1. Create a new HDRP or URP project, or open an existing project. |
|||
1. Open `Window` -> `Package Manager` |
|||
1. In the Package Manager window find and click the ***+*** button in the upper lefthand corner of the window |
|||
1. Select ***Add package from git URL...*** |
|||
1. Enter `com.unity.perception` and click ***Add*** |
|||
### Option 2: Create a new Project |
|||
These option is walkthrough in creating a new project, then adding the Perception SDK package to the project for development use. |
|||
*The following instructions reference the Unity doc's page on [installing a local package](https://docs.unity3d.com/Manual/upm-ui-local.html)* |
|||
Note that although the Perception package is compatible with both URP and HDRP, Unity Simulation currently only supports URP projects, therefore a URP project is recommended. |
|||
|
|||
If you want a specific version of the package, append the version to the end of the "git URL". Ex. `com.unity.perception@0.8.0-preview.1` |
|||
#### Create a new project |
|||
1. Create a new HDRP project or open an existing project |
|||
1. Creating anew HDRP project can be done by creating a new project using the HDRP template |
|||
2. Back in Unity editor, got Window -> Package Manager |
|||
1. Add the High Definition RP package, version 7.1.2 or later from the packages list |
|||
2. In the Package Manager window find and click the ***+*** button in the upper lefthand corner of the window |
|||
3. Select the ***add package from disk*** option |
|||
4. Navigate to the com.unity.perception folder in your cloned repository and select the package.json file |
|||
3. Once you have a project with Perception SDK installed you can move forward to the Getting Started walkthrough |
|||
To install from a local clone of the repository, see [installing a local package](https://docs.unity3d.com/Manual/upm-ui-local.html) in the Unity manual. |
|||
Once completed you can move on to the getting started steps, click [here](Documentation~/GettingStarted.md) to start project setup. |
|
|||
fileFormatVersion: 2 |
|||
guid: 43cb2a3117353435abe59ca5217974a8 |
|||
guid: 910dd3186e1c4fad8eb6aca9b9ee0f48 |
|||
timeCreated: 1585940009 |
|
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UnityEditor.UIElements; |
|||
using UnityEditorInternal; |
|||
using UnityEngine.UIElements; |
|||
using Button = UnityEngine.UIElements.Button; |
|||
using Toggle = UnityEngine.UIElements.Toggle; |
|||
[CustomEditor(typeof(Labeling)), CanEditMultipleObjects] |
|||
[CustomEditor(typeof(Labeling))] |
|||
VisualElement m_Root; |
|||
VisualElement m_ManualLabelingContainer; |
|||
VisualElement m_AutoLabelingContainer; |
|||
VisualElement m_FromLabelConfigsContainer; |
|||
VisualElement m_SuggestedLabelsContainer; |
|||
VisualElement m_SuggestedOnNamePanel; |
|||
VisualElement m_SuggestedOnPathPanel; |
|||
ListView m_CurrentLabelsListView; |
|||
ListView m_SuggestedLabelsListViewFromName; |
|||
ListView m_SuggestedLabelsListViewFromPath; |
|||
ScrollView m_LabelConfigsScrollView; |
|||
PopupField<string> m_LabelingSchemesPopup; |
|||
Button m_AddButton; |
|||
Button m_AddAutoLabelToConfButton; |
|||
Toggle m_AutoLabelingToggle; |
|||
Label m_CurrentAutoLabel; |
|||
Label m_CurrentAutoLabelTitle; |
|||
Label m_AddManualLabelsTitle; |
|||
|
|||
Labeling m_Labeling; |
|||
|
|||
string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/"; |
|||
string m_UxmlPath; |
|||
|
|||
List<string> m_SuggestedLabelsBasedOnName = new List<string>(); |
|||
List<string> m_SuggestedLabelsBasedOnPath = new List<string>(); |
|||
|
|||
public List<string> CommonLabels { get; private set; } = new List<string>(); |
|||
|
|||
List<Type> m_LabelConfigTypes; |
|||
readonly List<ScriptableObject> m_AllLabelConfigsInProject = new List<ScriptableObject>(); |
|||
|
|||
readonly List<AssetLabelingScheme> m_LabelingSchemes = new List<AssetLabelingScheme>(); |
|||
|
|||
/// <summary>
|
|||
/// List of separator characters used for parsing asset names for auto labeling or label suggestion purposes
|
|||
/// </summary>
|
|||
public static readonly string[] NameSeparators = {".", "-", "_"}; |
|||
/// <summary>
|
|||
/// List of separator characters used for parsing asset paths for auto labeling or label suggestion purposes
|
|||
/// </summary>
|
|||
public static readonly string[] PathSeparators = {"/"}; |
|||
|
|||
void OnEnable() |
|||
{ |
|||
m_LabelConfigTypes = AddToConfigWindow.FindAllSubTypes(typeof(LabelConfig<>)); |
|||
|
|||
var mySerializedObject = new SerializedObject(serializedObject.targetObjects[0]); |
|||
m_Labeling = mySerializedObject.targetObject as Labeling; |
|||
|
|||
m_UxmlPath = m_UxmlDir + "Labeling_Main.uxml"; |
|||
m_Root = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(m_UxmlPath).CloneTree(); |
|||
|
|||
m_CurrentLabelsListView = m_Root.Q<ListView>("current-labels-listview"); |
|||
m_SuggestedLabelsListViewFromName = m_Root.Q<ListView>("suggested-labels-name-listview"); |
|||
m_SuggestedLabelsListViewFromPath = m_Root.Q<ListView>("suggested-labels-path-listview"); |
|||
m_LabelConfigsScrollView = m_Root.Q<ScrollView>("label-configs-scrollview"); |
|||
m_SuggestedOnNamePanel = m_Root.Q<VisualElement>("suggested-labels-from-name"); |
|||
m_SuggestedOnPathPanel = m_Root.Q<VisualElement>("suggested-labels-from-path"); |
|||
m_AddButton = m_Root.Q<Button>("add-label"); |
|||
m_CurrentAutoLabel = m_Root.Q<Label>("current-auto-label"); |
|||
m_CurrentAutoLabelTitle = m_Root.Q<Label>("current-auto-label-title"); |
|||
m_AutoLabelingToggle = m_Root.Q<Toggle>("auto-or-manual-toggle"); |
|||
m_ManualLabelingContainer = m_Root.Q<VisualElement>("manual-labeling"); |
|||
m_AutoLabelingContainer = m_Root.Q<VisualElement>("automatic-labeling"); |
|||
m_FromLabelConfigsContainer = m_Root.Q<VisualElement>("from-label-configs"); |
|||
m_SuggestedLabelsContainer = m_Root.Q<VisualElement>("suggested-labels"); |
|||
m_AddAutoLabelToConfButton = m_Root.Q<Button>("add-auto-label-to-config"); |
|||
m_AddManualLabelsTitle = m_Root.Q<Label>("add-manual-labels-title"); |
|||
var dropdownParent = m_Root.Q<VisualElement>("drop-down-parent"); |
|||
|
|||
m_ItIsPossibleToAddMultipleAutoLabelsToConfig = false; |
|||
InitializeLabelingSchemes(dropdownParent); |
|||
AssesAutoLabelingStatus(); |
|||
|
|||
m_FirstItemLabelsArray = serializedObject.FindProperty(nameof(Labeling.labels)); |
|||
|
|||
if (serializedObject.targetObjects.Length > 1) |
|||
{ |
|||
var addedTitle = m_Root.Q<Label>("added-labels-title"); |
|||
addedTitle.text = "Common Labels of Selected Items"; |
|||
|
|||
m_SuggestedOnNamePanel.style.display = DisplayStyle.None; |
|||
|
|||
m_AddAutoLabelToConfButton.text = "Add Automatic Labels of All Selected Assets to Config..."; |
|||
} |
|||
else |
|||
{ |
|||
m_AddAutoLabelToConfButton.text = "Add to Label Config..."; |
|||
} |
|||
|
|||
m_AddAutoLabelToConfButton.clicked += () => |
|||
{ |
|||
AddToConfigWindow.ShowWindow(CreateUnionOfAllLabels().ToList()); |
|||
}; |
|||
|
|||
m_AddButton.clicked += () => |
|||
{ |
|||
var labelsUnion = CreateUnionOfAllLabels(); |
|||
var newLabel = FindNewLabelValue(labelsUnion); |
|||
foreach (var targetObject in targets) |
|||
{ |
|||
if (targetObject is Labeling labeling) |
|||
{ |
|||
var serializedLabelingObject2 = new SerializedObject(labeling); |
|||
var serializedLabelArray2 = serializedLabelingObject2.FindProperty(nameof(Labeling.labels)); |
|||
serializedLabelArray2.InsertArrayElementAtIndex(serializedLabelArray2.arraySize); |
|||
serializedLabelArray2.GetArrayElementAtIndex(serializedLabelArray2.arraySize-1).stringValue = newLabel; |
|||
serializedLabelingObject2.ApplyModifiedProperties(); |
|||
serializedLabelingObject2.SetIsDifferentCacheDirty(); |
|||
serializedObject.SetIsDifferentCacheDirty(); |
|||
} |
|||
} |
|||
ChangesHappeningInForeground = true; |
|||
RefreshManualLabelingData(); |
|||
}; |
|||
|
|||
m_AutoLabelingToggle.RegisterValueChangedCallback(evt => |
|||
{ |
|||
AutoLabelToggleChanged(); |
|||
}); |
|||
|
|||
ChangesHappeningInForeground = true; |
|||
m_Root.schedule.Execute(CheckForModelChanges).Every(30); |
|||
} |
|||
|
|||
int m_PreviousLabelsArraySize = -1; |
|||
/// <summary>
|
|||
/// This boolean is used to signify when changes in the model are triggered directly from the inspector UI by the user.
|
|||
/// In these cases, the scheduled model checker does not need to update the UI again.
|
|||
/// </summary>
|
|||
public bool ChangesHappeningInForeground { get; set; } |
|||
|
|||
SerializedProperty m_FirstItemLabelsArray; |
|||
|
|||
void CheckForModelChanges() |
|||
{ |
|||
if (ChangesHappeningInForeground) |
|||
{ |
|||
ChangesHappeningInForeground = false; |
|||
m_PreviousLabelsArraySize = m_FirstItemLabelsArray.arraySize; |
|||
return; |
|||
} |
|||
|
|||
if (m_FirstItemLabelsArray.arraySize != m_PreviousLabelsArraySize) |
|||
{ |
|||
AssesAutoLabelingStatus(); |
|||
RefreshManualLabelingData(); |
|||
m_PreviousLabelsArraySize = m_FirstItemLabelsArray.arraySize; |
|||
} |
|||
} |
|||
|
|||
bool SerializedObjectHasValidLabelingScheme(SerializedObject serObj) |
|||
{ |
|||
var schemeName = serObj.FindProperty(nameof(Labeling.autoLabelingSchemeType)).stringValue; |
|||
return IsValidLabelingSchemeName(schemeName); |
|||
} |
|||
|
|||
bool IsValidLabelingSchemeName(string schemeName) |
|||
{ |
|||
return schemeName != string.Empty && |
|||
m_LabelingSchemes.FindAll(scheme => scheme.GetType().Name == schemeName).Count > 0; |
|||
} |
|||
|
|||
bool m_ItIsPossibleToAddMultipleAutoLabelsToConfig; |
|||
|
|||
void UpdateUiAspects() |
|||
{ |
|||
m_ManualLabelingContainer.SetEnabled(!m_AutoLabelingToggle.value); |
|||
m_AutoLabelingContainer.SetEnabled(m_AutoLabelingToggle.value); |
|||
|
|||
m_AddManualLabelsTitle.style.display = m_AutoLabelingToggle.value ? DisplayStyle.None : DisplayStyle.Flex; |
|||
m_FromLabelConfigsContainer.style.display = m_AutoLabelingToggle.value ? DisplayStyle.None : DisplayStyle.Flex; |
|||
m_SuggestedLabelsContainer.style.display = m_AutoLabelingToggle.value ? DisplayStyle.None : DisplayStyle.Flex; |
|||
|
|||
m_CurrentLabelsListView.style.minHeight = m_AutoLabelingToggle.value ? 70 : 120; |
|||
|
|||
if (!m_AutoLabelingToggle.value || serializedObject.targetObjects.Length > 1 || |
|||
!SerializedObjectHasValidLabelingScheme(new SerializedObject(serializedObject.targetObjects[0]))) |
|||
{ |
|||
m_CurrentAutoLabel.style.display = DisplayStyle.None; |
|||
m_AddAutoLabelToConfButton.SetEnabled(false); |
|||
} |
|||
else |
|||
{ |
|||
m_CurrentAutoLabel.style.display = DisplayStyle.Flex; |
|||
m_AddAutoLabelToConfButton.SetEnabled(true); |
|||
} |
|||
|
|||
if(m_AutoLabelingToggle.value && serializedObject.targetObjects.Length > 1 && m_ItIsPossibleToAddMultipleAutoLabelsToConfig) |
|||
{ |
|||
m_AddAutoLabelToConfButton.SetEnabled(true); |
|||
} |
|||
|
|||
|
|||
if (serializedObject.targetObjects.Length == 1) |
|||
{ |
|||
m_AutoLabelingToggle.text = "Use Automatic Labeling"; |
|||
} |
|||
else |
|||
{ |
|||
m_CurrentAutoLabelTitle.text = "Select assets individually to inspect their automatic labels."; |
|||
m_AutoLabelingToggle.text = "Use Automatic Labeling for All Selected Items"; |
|||
} |
|||
} |
|||
|
|||
void UpdateCurrentAutoLabelValue(SerializedObject serObj) |
|||
{ |
|||
var array = serObj.FindProperty(nameof(Labeling.labels)); |
|||
if (array.arraySize > 0) |
|||
{ |
|||
m_CurrentAutoLabel.text = array.GetArrayElementAtIndex(0).stringValue; |
|||
} |
|||
} |
|||
|
|||
bool AreSelectedAssetsCompatibleWithAutoLabelScheme(AssetLabelingScheme scheme) |
|||
{ |
|||
foreach (var asset in serializedObject.targetObjects) |
|||
{ |
|||
string label = scheme.GenerateLabel(asset); |
|||
if (label == null) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
void InitializeLabelingSchemes(VisualElement parent) |
|||
{ |
|||
//this function should be called only once during the lifecycle of the editor element
|
|||
AssetLabelingScheme labelingScheme = new AssetNameLabelingScheme(); |
|||
if (AreSelectedAssetsCompatibleWithAutoLabelScheme(labelingScheme)) m_LabelingSchemes.Add(labelingScheme); |
|||
|
|||
labelingScheme = new AssetFileNameLabelingScheme(); |
|||
if (AreSelectedAssetsCompatibleWithAutoLabelScheme(labelingScheme)) m_LabelingSchemes.Add(labelingScheme); |
|||
|
|||
labelingScheme = new CurrentOrParentsFolderNameLabelingScheme(); |
|||
if (AreSelectedAssetsCompatibleWithAutoLabelScheme(labelingScheme)) m_LabelingSchemes.Add(labelingScheme); |
|||
|
|||
var descriptions = m_LabelingSchemes.Select(scheme => scheme.Description).ToList(); |
|||
descriptions.Insert(0, "<Select Scheme>"); |
|||
m_LabelingSchemesPopup = new PopupField<string>(descriptions, 0) {label = "Labeling Scheme"}; |
|||
m_LabelingSchemesPopup.style.marginLeft = 0; |
|||
parent.Add(m_LabelingSchemesPopup); |
|||
|
|||
m_LabelingSchemesPopup.RegisterValueChangedCallback(evt => AssignAutomaticLabelToSelectedAssets()); |
|||
} |
|||
|
|||
void AutoLabelToggleChanged() |
|||
{ |
|||
UpdateUiAspects(); |
|||
|
|||
if (!m_AutoLabelingToggle.value) |
|||
{ |
|||
m_ItIsPossibleToAddMultipleAutoLabelsToConfig = false; |
|||
|
|||
foreach (var targetObj in serializedObject.targetObjects) |
|||
{ |
|||
var serObj = new SerializedObject(targetObj); |
|||
serObj.FindProperty(nameof(Labeling.useAutoLabeling)).boolValue = false; |
|||
|
|||
if (SerializedObjectHasValidLabelingScheme(serObj)) |
|||
{ |
|||
//asset already had a labeling scheme before auto labeling was disabled, which means it has auto label(s) attached. these should be cleared now.
|
|||
serObj.FindProperty(nameof(Labeling.labels)).ClearArray(); |
|||
} |
|||
|
|||
serObj.FindProperty(nameof(Labeling.autoLabelingSchemeType)).stringValue = string.Empty; |
|||
m_LabelingSchemesPopup.index = 0; |
|||
|
|||
serObj.ApplyModifiedProperties(); |
|||
serObj.SetIsDifferentCacheDirty(); |
|||
} |
|||
} |
|||
|
|||
ChangesHappeningInForeground = true; |
|||
RefreshManualLabelingData(); |
|||
} |
|||
|
|||
void AssignAutomaticLabelToSelectedAssets() |
|||
{ |
|||
//the 0th index of this popup is "<Select Scheme>" and should not do anything
|
|||
if (m_LabelingSchemesPopup.index == 0) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
m_ItIsPossibleToAddMultipleAutoLabelsToConfig = true; |
|||
|
|||
var labelingScheme = m_LabelingSchemes[m_LabelingSchemesPopup.index - 1]; |
|||
|
|||
foreach (var targetObj in serializedObject.targetObjects) |
|||
{ |
|||
var serObj = new SerializedObject(targetObj); |
|||
serObj.FindProperty(nameof(Labeling.useAutoLabeling)).boolValue = true; //only set this flag once the user has actually chosen a scheme, otherwise, we will not touch the flag
|
|||
serObj.FindProperty(nameof(Labeling.autoLabelingSchemeType)).stringValue = labelingScheme.GetType().Name; |
|||
var serLabelsArray = serObj.FindProperty(nameof(Labeling.labels)); |
|||
serLabelsArray.ClearArray(); |
|||
serLabelsArray.InsertArrayElementAtIndex(0); |
|||
var label = labelingScheme.GenerateLabel(targetObj); |
|||
serLabelsArray.GetArrayElementAtIndex(0).stringValue = label; |
|||
if (targetObj == serializedObject.targetObjects[0] && serializedObject.targetObjects.Length == 1) |
|||
{ |
|||
UpdateCurrentAutoLabelValue(serObj); |
|||
} |
|||
serObj.ApplyModifiedProperties(); |
|||
serObj.SetIsDifferentCacheDirty(); |
|||
} |
|||
|
|||
UpdateUiAspects(); |
|||
ChangesHappeningInForeground = true; |
|||
RefreshManualLabelingData(); |
|||
} |
|||
|
|||
void AssesAutoLabelingStatus() |
|||
{ |
|||
var enabledOrNot = true; |
|||
if (serializedObject.targetObjects.Length == 1) |
|||
{ |
|||
var serObj = new SerializedObject(serializedObject.targetObjects[0]); |
|||
var enabled = serObj.FindProperty(nameof(Labeling.useAutoLabeling)).boolValue; |
|||
m_AutoLabelingToggle.value = enabled; |
|||
var currentLabelingSchemeName = serObj.FindProperty(nameof(Labeling.autoLabelingSchemeType)).stringValue; |
|||
if (IsValidLabelingSchemeName(currentLabelingSchemeName)) |
|||
{ |
|||
m_LabelingSchemesPopup.index = |
|||
m_LabelingSchemes.FindIndex(scheme => scheme.GetType().Name.ToString() == currentLabelingSchemeName) + 1; |
|||
} |
|||
UpdateCurrentAutoLabelValue(serObj); |
|||
} |
|||
else |
|||
{ |
|||
string unifiedLabelingScheme = null; |
|||
var allAssetsUseSameLabelingScheme = true; |
|||
|
|||
foreach (var targetObj in serializedObject.targetObjects) |
|||
{ |
|||
var serObj = new SerializedObject(targetObj); |
|||
var enabled = serObj.FindProperty(nameof(Labeling.useAutoLabeling)).boolValue; |
|||
enabledOrNot &= enabled; |
|||
|
|||
var schemeName = serObj.FindProperty(nameof(Labeling.autoLabelingSchemeType)).stringValue; |
|||
if (schemeName == string.Empty) |
|||
{ |
|||
//if any of the selected assets does not have a labeling scheme, they can't all have the same valid scheme
|
|||
allAssetsUseSameLabelingScheme = false; |
|||
} |
|||
|
|||
if (allAssetsUseSameLabelingScheme) |
|||
{ |
|||
if (unifiedLabelingScheme == null) |
|||
{ |
|||
unifiedLabelingScheme = schemeName; |
|||
} |
|||
else if (unifiedLabelingScheme != schemeName) |
|||
{ |
|||
allAssetsUseSameLabelingScheme = false; |
|||
} |
|||
} |
|||
} |
|||
m_AutoLabelingToggle.value = enabledOrNot; |
|||
|
|||
if (allAssetsUseSameLabelingScheme) |
|||
{ |
|||
//all selected assets have the same scheme recorded in their serialized objects
|
|||
m_LabelingSchemesPopup.index = |
|||
m_LabelingSchemes.FindIndex(scheme => scheme.GetType().Name.ToString() == unifiedLabelingScheme) + 1; |
|||
|
|||
m_ItIsPossibleToAddMultipleAutoLabelsToConfig = enabledOrNot; |
|||
//if all selected assets have the same scheme recorded in their serialized objects, and they all
|
|||
//have auto labeling enabled, we can now add all auto labels to a config
|
|||
} |
|||
else |
|||
{ |
|||
//the selected DO NOT have the same scheme recorded in their serialized objects
|
|||
m_LabelingSchemesPopup.index = 0; |
|||
} |
|||
} |
|||
|
|||
UpdateUiAspects(); |
|||
} |
|||
|
|||
HashSet<string> CreateUnionOfAllLabels() |
|||
{ |
|||
HashSet<String> result = new HashSet<string>(); |
|||
foreach (var obj in targets) |
|||
{ |
|||
if (obj is Labeling labeling) |
|||
{ |
|||
result.UnionWith(labeling.labels); |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
string FindNewLabelValue(HashSet<string> labels) |
|||
{ |
|||
string baseLabel = "New Label"; |
|||
string label = baseLabel; |
|||
int count = 1; |
|||
while (labels.Contains(label)) |
|||
{ |
|||
label = baseLabel + "_" + count++; |
|||
} |
|||
return label; |
|||
} |
|||
|
|||
public override VisualElement CreateInspectorGUI() |
|||
{ |
|||
serializedObject.Update(); |
|||
m_Labeling = serializedObject.targetObject as Labeling; |
|||
RefreshCommonLabels(); |
|||
RefreshSuggestedLabelLists(); |
|||
RefreshLabelConfigsList(); |
|||
SetupListsAndScrollers(); |
|||
return m_Root; |
|||
} |
|||
|
|||
void RefreshLabelConfigsList() |
|||
{ |
|||
List<string> labelConfigGuids = new List<string>(); |
|||
foreach (var type in m_LabelConfigTypes) |
|||
{ |
|||
labelConfigGuids.AddRange(AssetDatabase.FindAssets("t:"+type.Name)); |
|||
} |
|||
|
|||
m_AllLabelConfigsInProject.Clear(); |
|||
foreach (var configGuid in labelConfigGuids) |
|||
{ |
|||
var asset = AssetDatabase.LoadAssetAtPath<ScriptableObject>(AssetDatabase.GUIDToAssetPath(configGuid)); |
|||
m_AllLabelConfigsInProject.Add(asset); |
|||
} |
|||
} |
|||
|
|||
void RemoveAddedLabelsFromSuggestedLists() |
|||
{ |
|||
m_SuggestedLabelsBasedOnName.RemoveAll(s => CommonLabels.Contains(s)); |
|||
m_SuggestedLabelsBasedOnPath.RemoveAll(s => CommonLabels.Contains(s)); |
|||
} |
|||
|
|||
void RefreshSuggestedLabelLists() |
|||
{ |
|||
m_SuggestedLabelsBasedOnName.Clear(); |
|||
m_SuggestedLabelsBasedOnPath.Clear(); |
|||
|
|||
//based on name
|
|||
if (serializedObject.targetObjects.Length == 1) |
|||
{ |
|||
string assetName = serializedObject.targetObject.name; |
|||
var pieces = assetName.Split(NameSeparators, StringSplitOptions.RemoveEmptyEntries).ToList(); |
|||
if (pieces.Count > 1) |
|||
{ |
|||
//means the asset name was actually split
|
|||
m_SuggestedLabelsBasedOnName.Add(assetName); |
|||
} |
|||
|
|||
m_SuggestedLabelsBasedOnName.AddRange(pieces); |
|||
} |
|||
|
|||
//based on path
|
|||
string assetPath = GetAssetOrPrefabPath(m_Labeling.gameObject); |
|||
//var prefabObject = PrefabUtility.GetCorrespondingObjectFromSource(m_Labeling.gameObject);
|
|||
if (assetPath != null) |
|||
{ |
|||
var stringList = assetPath.Split(PathSeparators, StringSplitOptions.RemoveEmptyEntries).ToList(); |
|||
stringList.Reverse(); |
|||
m_SuggestedLabelsBasedOnPath.AddRange(stringList); |
|||
} |
|||
|
|||
foreach (var targetObject in targets) |
|||
{ |
|||
if (targetObject == target) |
|||
continue; //we have already taken care of this one above
|
|||
const int k_Indent = 7; |
|||
ReorderableList m_LabelsList; |
|||
assetPath = GetAssetOrPrefabPath(((Labeling)targetObject).gameObject); |
|||
//prefabObject = PrefabUtility.GetCorrespondingObjectFromSource(((Labeling)targetObject).gameObject);
|
|||
if (assetPath != null) |
|||
{ |
|||
var stringList = assetPath.Split(PathSeparators, StringSplitOptions.RemoveEmptyEntries).ToList(); |
|||
m_SuggestedLabelsBasedOnPath = m_SuggestedLabelsBasedOnPath.Intersect(stringList).ToList(); |
|||
} |
|||
} |
|||
|
|||
RemoveAddedLabelsFromSuggestedLists(); |
|||
//Debug.Log("list update, source list count is:" + m_SuggestedLabelsBasedOnPath.Count);
|
|||
} |
|||
|
|||
public void RefreshManualLabelingData() |
|||
public void OnEnable() |
|||
serializedObject.SetIsDifferentCacheDirty(); |
|||
serializedObject.Update(); |
|||
RefreshCommonLabels(); |
|||
RefreshSuggestedLabelLists(); |
|||
SetupSuggestedLabelsListViews(); |
|||
SetupCurrentLabelsListView(); |
|||
UpdateSuggestedPanelVisibility(); |
|||
m_LabelsList = new ReorderableList(serializedObject, serializedObject.FindProperty(nameof(global::UnityEngine.Perception.GroundTruth.Labeling.labels)), true, false, true, true); |
|||
m_LabelsList.drawElementCallback = DrawElement; |
|||
m_LabelsList.onAddCallback += OnAdd; |
|||
m_LabelsList.onRemoveCallback += OnRemove; |
|||
void SetupListsAndScrollers() |
|||
void OnRemove(ReorderableList list) |
|||
//Labels that have already been added to the target Labeling component
|
|||
SetupCurrentLabelsListView(); |
|||
//Labels suggested by the system, which the user can add
|
|||
SetupSuggestedLabelsListViews(); |
|||
//Add labels from Label Configs present in project
|
|||
SetupLabelConfigsScrollView(); |
|||
UpdateSuggestedPanelVisibility(); |
|||
if (list.index != -1) |
|||
Labeling.labels.RemoveAt(list.index); |
|||
void UpdateSuggestedPanelVisibility() |
|||
{ |
|||
m_SuggestedOnNamePanel.style.display = m_SuggestedLabelsBasedOnName.Count == 0 ? DisplayStyle.None : DisplayStyle.Flex; |
|||
|
|||
m_SuggestedOnPathPanel.style.display = m_SuggestedLabelsBasedOnPath.Count == 0 ? DisplayStyle.None : DisplayStyle.Flex; |
|||
|
|||
if (m_SuggestedLabelsBasedOnPath.Count == 0 && m_SuggestedLabelsBasedOnName.Count == 0) |
|||
{ |
|||
m_SuggestedLabelsContainer.style.display = DisplayStyle.None; |
|||
} |
|||
} |
|||
|
|||
|
|||
void RefreshCommonLabels() |
|||
{ |
|||
CommonLabels.Clear(); |
|||
CommonLabels.AddRange(((Labeling)serializedObject.targetObjects[0]).labels); |
|||
|
|||
foreach (var obj in serializedObject.targetObjects) |
|||
{ |
|||
CommonLabels = CommonLabels.Intersect(((Labeling) obj).labels).ToList(); |
|||
} |
|||
} |
|||
|
|||
void SetupCurrentLabelsListView() |
|||
{ |
|||
m_CurrentLabelsListView.itemsSource = CommonLabels; |
|||
|
|||
VisualElement MakeItem() => |
|||
new AddedLabelEditor(this, m_CurrentLabelsListView); |
|||
|
|||
void BindItem(VisualElement e, int i) |
|||
{ |
|||
if (e is AddedLabelEditor addedLabel) |
|||
{ |
|||
addedLabel.indexInList = i; |
|||
addedLabel.labelTextField.value = CommonLabels[i]; |
|||
} |
|||
} |
|||
|
|||
const int itemHeight = 35; |
|||
|
|||
m_CurrentLabelsListView.bindItem = BindItem; |
|||
m_CurrentLabelsListView.makeItem = MakeItem; |
|||
m_CurrentLabelsListView.itemHeight = itemHeight; |
|||
|
|||
m_CurrentLabelsListView.itemsSource = CommonLabels; |
|||
m_CurrentLabelsListView.selectionType = SelectionType.None; |
|||
} |
|||
|
|||
void SetupSuggestedLabelsListViews() |
|||
{ |
|||
SetupSuggestedLabelsBasedOnFlatList(m_SuggestedLabelsListViewFromName, m_SuggestedLabelsBasedOnName); |
|||
SetupSuggestedLabelsBasedOnFlatList(m_SuggestedLabelsListViewFromPath, m_SuggestedLabelsBasedOnPath); |
|||
} |
|||
|
|||
void SetupSuggestedLabelsBasedOnFlatList(ListView labelsListView, List<string> stringList) |
|||
{ |
|||
labelsListView.itemsSource = stringList; |
|||
|
|||
VisualElement MakeItem() => new SuggestedLabelElement(this); |
|||
Labeling Labeling => (Labeling)target; |
|||
void BindItem(VisualElement e, int i) |
|||
{ |
|||
if (e is SuggestedLabelElement suggestedLabel) |
|||
{ |
|||
suggestedLabel.label.text = stringList[i]; |
|||
} |
|||
} |
|||
|
|||
const int itemHeight = 32; |
|||
|
|||
labelsListView.bindItem = BindItem; |
|||
labelsListView.makeItem = MakeItem; |
|||
labelsListView.itemHeight = itemHeight; |
|||
labelsListView.selectionType = SelectionType.None; |
|||
} |
|||
void SetupLabelConfigsScrollView() |
|||
void OnAdd(ReorderableList list) |
|||
m_LabelConfigsScrollView.Clear(); |
|||
foreach (var config in m_AllLabelConfigsInProject) |
|||
{ |
|||
VisualElement configElement = new LabelConfigElement(this, config); |
|||
m_LabelConfigsScrollView.Add(configElement); |
|||
} |
|||
Labeling.labels.Add(""); |
|||
/// <summary>
|
|||
/// Get the path of the given asset in the project, or get the path of the given Scene GameObject's source prefab if any
|
|||
/// </summary>
|
|||
/// <param name="obj"></param>
|
|||
/// <returns></returns>
|
|||
public static string GetAssetOrPrefabPath(UnityEngine.Object obj) |
|||
void DrawElement(Rect rect, int index, bool isactive, bool isfocused) |
|||
string assetPath = AssetDatabase.GetAssetPath(obj); |
|||
|
|||
if (assetPath == string.Empty) |
|||
using (var change = new EditorGUI.ChangeCheckScope()) |
|||
//this indicates that gObj is a scene object and not a prefab directly selected from the Project tab
|
|||
var prefabObject = PrefabUtility.GetCorrespondingObjectFromSource(obj); |
|||
if (prefabObject) |
|||
{ |
|||
assetPath = AssetDatabase.GetAssetPath(prefabObject); |
|||
} |
|||
} |
|||
|
|||
return assetPath; |
|||
} |
|||
} |
|||
|
|||
class AddedLabelEditor : VisualElement |
|||
{ |
|||
string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/"; |
|||
|
|||
public TextField labelTextField; |
|||
public int indexInList; |
|||
|
|||
public AddedLabelEditor(LabelingEditor editor, ListView listView) |
|||
{ |
|||
var uxmlPath = m_UxmlDir + "AddedLabelElement.uxml"; |
|||
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(uxmlPath).CloneTree(this); |
|||
labelTextField = this.Q<TextField>("label-value"); |
|||
var removeButton = this.Q<Button>("remove-button"); |
|||
var addToConfigButton = this.Q<Button>("add-to-config-button"); |
|||
|
|||
labelTextField.isDelayed = true; |
|||
|
|||
labelTextField.RegisterValueChangedCallback((cEvent) => |
|||
{ |
|||
//Do not let the user define a duplicate label
|
|||
if (editor.CommonLabels.Contains(cEvent.newValue) && editor.CommonLabels.IndexOf(cEvent.newValue) != indexInList) |
|||
{ |
|||
//The listview recycles child visual elements and that causes the RegisterValueChangedCallback event to be called when scrolling.
|
|||
//Therefore, we need to make sure we are not in this code block just because of scrolling, but because the user is actively changing one of the labels.
|
|||
//The editor.CommonLabels.IndexOf(cEvent.newValue) != m_IndexInList check is for this purpose.
|
|||
|
|||
Debug.LogError("A label with the string " + cEvent.newValue + " has already been added to selected objects."); |
|||
editor.ChangesHappeningInForeground = true; |
|||
editor.RefreshManualLabelingData(); |
|||
var indent = k_Indent * index; |
|||
if (indent >= rect.width) |
|||
} |
|||
bool shouldRefresh = false; |
|||
|
|||
foreach (var targetObject in editor.targets) |
|||
{ |
|||
if (targetObject is Labeling labeling) |
|||
{ |
|||
var indexToModifyInTargetLabelList = |
|||
labeling.labels.IndexOf(editor.CommonLabels[indexInList]); |
|||
|
|||
|
|||
var serializedLabelingObject2 = new SerializedObject(labeling); |
|||
var serializedLabelArray2 = serializedLabelingObject2.FindProperty(nameof(Labeling.labels)); |
|||
serializedLabelArray2.GetArrayElementAtIndex(indexToModifyInTargetLabelList).stringValue = cEvent.newValue; |
|||
shouldRefresh = shouldRefresh || serializedLabelArray2.serializedObject.hasModifiedProperties; |
|||
serializedLabelingObject2.ApplyModifiedProperties(); |
|||
serializedLabelingObject2.SetIsDifferentCacheDirty(); |
|||
} |
|||
} |
|||
|
|||
//the value change event is called even when the listview recycles its child elements for re-use during scrolling, therefore, we should check to make sure there are modified properties, otherwise we would be doing the refresh for no reason (reduces scrolling performance)
|
|||
if (shouldRefresh) |
|||
var contentRect = new Rect(rect.x + indent, rect.y, rect.width - indent, rect.height); |
|||
var value = EditorGUI.TextField(contentRect, Labeling.labels[index]); |
|||
if (change.changed) |
|||
editor.ChangesHappeningInForeground = true; |
|||
editor.RefreshManualLabelingData(); |
|||
} |
|||
}); |
|||
|
|||
addToConfigButton.clicked += () => |
|||
{ |
|||
AddToConfigWindow.ShowWindow(labelTextField.value); |
|||
}; |
|||
|
|||
removeButton.clicked += () => |
|||
{ |
|||
List<string> commonLabels = new List<string>(); |
|||
|
|||
commonLabels.Clear(); |
|||
var firstTarget = editor.targets[0] as Labeling; |
|||
if (firstTarget != null) |
|||
{ |
|||
commonLabels.AddRange(firstTarget.labels); |
|||
|
|||
foreach (var obj in editor.targets) |
|||
{ |
|||
commonLabels = commonLabels.Intersect(((Labeling) obj).labels).ToList(); |
|||
} |
|||
|
|||
foreach (var targetObject in editor.targets) |
|||
{ |
|||
if (targetObject is Labeling labeling) |
|||
{ |
|||
RemoveLabelFromLabelingSerObj(labeling, commonLabels); |
|||
} |
|||
} |
|||
editor.serializedObject.SetIsDifferentCacheDirty(); |
|||
editor.RefreshManualLabelingData(); |
|||
} |
|||
}; |
|||
} |
|||
|
|||
void RemoveLabelFromLabelingSerObj(Labeling labeling, List<string> commonLabels) |
|||
{ |
|||
Dictionary<int, int> commonsIndexToLabelsIndex = new Dictionary<int, int>(); |
|||
|
|||
for (int i = 0; i < labeling.labels.Count; i++) |
|||
{ |
|||
string label = labeling.labels[i]; |
|||
|
|||
for (int j = 0; j < commonLabels.Count; j++) |
|||
{ |
|||
string label2 = commonLabels[j]; |
|||
|
|||
if (string.Equals(label, label2) && !commonsIndexToLabelsIndex.ContainsKey(j)) |
|||
{ |
|||
commonsIndexToLabelsIndex.Add(j, i); |
|||
} |
|||
Labeling.labels[index] = value; |
|||
|
|||
var serializedLabelingObject2 = new SerializedObject(labeling); |
|||
var serializedLabelArray2 = serializedLabelingObject2.FindProperty("labels"); |
|||
serializedLabelArray2.DeleteArrayElementAtIndex(commonsIndexToLabelsIndex[indexInList]); |
|||
serializedLabelingObject2.ApplyModifiedProperties(); |
|||
serializedLabelingObject2.SetIsDifferentCacheDirty(); |
|||
} |
|||
class SuggestedLabelElement : VisualElement |
|||
{ |
|||
string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/"; |
|||
public Label label; |
|||
|
|||
public SuggestedLabelElement(LabelingEditor editor) |
|||
public override void OnInspectorGUI() |
|||
var uxmlPath = m_UxmlDir + "SuggestedLabelElement.uxml"; |
|||
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(uxmlPath).CloneTree(this); |
|||
label = this.Q<Label>("label-value"); |
|||
var addButton = this.Q<Button>("add-button"); |
|||
|
|||
addButton.clicked += () => |
|||
{ |
|||
foreach (var targetObject in editor.serializedObject.targetObjects) |
|||
{ |
|||
if (targetObject is Labeling labeling) |
|||
{ |
|||
if (labeling.labels.Contains(label.text)) |
|||
continue; //Do not allow duplicate labels in one asset. Duplicate labels have no use and cause other operations (especially mutlt asset editing) to get messed up
|
|||
var serializedLabelingObject2 = new SerializedObject(targetObject); |
|||
var serializedLabelArray2 = serializedLabelingObject2.FindProperty("labels"); |
|||
serializedLabelArray2.InsertArrayElementAtIndex(serializedLabelArray2.arraySize); |
|||
serializedLabelArray2.GetArrayElementAtIndex(serializedLabelArray2.arraySize-1).stringValue = label.text; |
|||
serializedLabelingObject2.ApplyModifiedProperties(); |
|||
serializedLabelingObject2.SetIsDifferentCacheDirty(); |
|||
editor.serializedObject.SetIsDifferentCacheDirty(); |
|||
} |
|||
} |
|||
editor.ChangesHappeningInForeground = true; |
|||
editor.RefreshManualLabelingData(); |
|||
}; |
|||
} |
|||
} |
|||
|
|||
class LabelConfigElement : VisualElement |
|||
{ |
|||
string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/"; |
|||
bool m_Collapsed = true; |
|||
|
|||
ListView m_LabelsListView; |
|||
VisualElement m_CollapseToggle; |
|||
|
|||
public LabelConfigElement(LabelingEditor editor, ScriptableObject config) |
|||
{ |
|||
var uxmlPath = m_UxmlDir + "ConfigElementForAddingLabelsFrom.uxml"; |
|||
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(uxmlPath).CloneTree(this); |
|||
m_LabelsListView = this.Q<ListView>("label-config-contents-listview"); |
|||
var openButton = this.Q<Button>("open-config-button"); |
|||
var configName = this.Q<Label>("config-name"); |
|||
configName.text = config.name; |
|||
m_CollapseToggle = this.Q<VisualElement>("collapse-toggle"); |
|||
|
|||
openButton.clicked += () => |
|||
{ |
|||
Selection.SetActiveObjectWithContext(config, null); |
|||
}; |
|||
|
|||
var propertyInfo = config.GetType().GetProperty(IdLabelConfig.publicLabelEntriesFieldName); |
|||
if (propertyInfo != null) |
|||
{ |
|||
var objectList = (IEnumerable) propertyInfo.GetValue(config); |
|||
var labelEntryList = objectList.Cast<ILabelEntry>().ToList(); |
|||
var labelList = labelEntryList.Select(entry => entry.label).ToList(); |
|||
|
|||
m_LabelsListView.itemsSource = labelList; |
|||
|
|||
VisualElement MakeItem() |
|||
{ |
|||
var element = new SuggestedLabelElement(editor); |
|||
element.AddToClassList("label_add_from_config"); |
|||
return element; |
|||
} |
|||
|
|||
void BindItem(VisualElement e, int i) |
|||
{ |
|||
if (e is SuggestedLabelElement suggestedLabel) |
|||
{ |
|||
suggestedLabel.label.text = labelList[i]; |
|||
} |
|||
} |
|||
|
|||
const int itemHeight = 27; |
|||
|
|||
m_LabelsListView.bindItem = BindItem; |
|||
m_LabelsListView.makeItem = MakeItem; |
|||
m_LabelsListView.itemHeight = itemHeight; |
|||
m_LabelsListView.selectionType = SelectionType.None; |
|||
} |
|||
|
|||
m_CollapseToggle.RegisterCallback<MouseUpEvent>(evt => |
|||
{ |
|||
m_Collapsed = !m_Collapsed; |
|||
ApplyCollapseState(); |
|||
}); |
|||
|
|||
ApplyCollapseState(); |
|||
} |
|||
|
|||
void ApplyCollapseState() |
|||
{ |
|||
if (m_Collapsed) |
|||
{ |
|||
m_CollapseToggle.AddToClassList("collapsed-toggle-state"); |
|||
m_LabelsListView.AddToClassList("collapsed"); |
|||
} |
|||
else |
|||
{ |
|||
m_CollapseToggle.RemoveFromClassList("collapsed-toggle-state"); |
|||
m_LabelsListView.RemoveFromClassList("collapsed"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// A labeling scheme based on which an automatic label can be produced for a given asset. E.g. based on asset name, asset path, etc.
|
|||
/// </summary>
|
|||
abstract class AssetLabelingScheme |
|||
{ |
|||
/// <summary>
|
|||
/// The description of how this scheme generates labels. Used in the dropdown menu in the UI.
|
|||
/// </summary>
|
|||
public abstract string Description { get; } |
|||
|
|||
/// <summary>
|
|||
/// Generate a label for the given asset
|
|||
/// </summary>
|
|||
/// <param name="asset"></param>
|
|||
/// <returns></returns>
|
|||
public abstract string GenerateLabel(UnityEngine.Object asset); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Asset labeling scheme that outputs the given asset's name as its automatic label
|
|||
/// </summary>
|
|||
class AssetNameLabelingScheme : AssetLabelingScheme |
|||
{ |
|||
///<inheritdoc/>
|
|||
public override string Description => "Use asset name"; |
|||
|
|||
///<inheritdoc/>
|
|||
public override string GenerateLabel(UnityEngine.Object asset) |
|||
{ |
|||
return asset.name; |
|||
} |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Asset labeling scheme that outputs the given asset's file name, including extension, as its automatic label
|
|||
/// </summary>
|
|||
class AssetFileNameLabelingScheme : AssetLabelingScheme |
|||
{ |
|||
///<inheritdoc/>
|
|||
public override string Description => "Use file name with extension"; |
|||
|
|||
///<inheritdoc/>
|
|||
public override string GenerateLabel(UnityEngine.Object asset) |
|||
{ |
|||
string assetPath = LabelingEditor.GetAssetOrPrefabPath(asset); |
|||
var stringList = assetPath.Split(LabelingEditor.PathSeparators, StringSplitOptions.RemoveEmptyEntries) |
|||
.ToList(); |
|||
return stringList.Count > 0 ? stringList.Last() : null; |
|||
} |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Asset labeling scheme that outputs the given asset's folder name as its automatic label
|
|||
/// </summary>
|
|||
class CurrentOrParentsFolderNameLabelingScheme : AssetLabelingScheme |
|||
{ |
|||
///<inheritdoc/>
|
|||
public override string Description => "Use the asset's folder name"; |
|||
|
|||
///<inheritdoc/>
|
|||
public override string GenerateLabel(UnityEngine.Object asset) |
|||
{ |
|||
string assetPath = LabelingEditor.GetAssetOrPrefabPath(asset); |
|||
var stringList = assetPath.Split(LabelingEditor.PathSeparators, StringSplitOptions.RemoveEmptyEntries) |
|||
.ToList(); |
|||
return stringList.Count > 1 ? stringList[stringList.Count-2] : null; |
|||
m_LabelsList.DoLayoutList(); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 387b8732b87094321af57795df93aec4 |
|||
guid: 2e725508a34c40a0938c8d891b371980 |
|||
timeCreated: 1585933334 |
|
|||
using System; |
|||
using System.Collections; |
|||
using System.IO; |
|||
using UnityEditor; |
|||
using UnityEngine; |
|||
using UnityEngine.TestTools; |
|||
namespace GroundTruthTests |
|||
namespace GroundTruth |
|||
[TestFixture] |
|||
[Serializable] |
|||
public class DatasetCaptureEditorTests |
|||
public class SimulationManagerEditorTests |
|||
[SerializeField] |
|||
string expectedDatasetPath; |
|||
Assert.Throws<InvalidOperationException>(() => DatasetCapture.RegisterEgo("")); |
|||
Assert.Throws<InvalidOperationException>(() => SimulationManager.RegisterEgo("")); |
|||
Assert.Throws<InvalidOperationException>(() => DatasetCapture.RegisterAnnotationDefinition("")); |
|||
Assert.Throws<InvalidOperationException>(() => SimulationManager.RegisterAnnotationDefinition("")); |
|||
Assert.Throws<InvalidOperationException>(() => DatasetCapture.RegisterMetricDefinition("")); |
|||
} |
|||
[UnityTest] |
|||
public IEnumerator SimpleData_GeneratesFullDataset_OnExitPlaymode() |
|||
{ |
|||
yield return new EnterPlayMode(); |
|||
DatasetCapture.ResetSimulation(); |
|||
var ego = DatasetCapture.RegisterEgo("ego"); |
|||
var sensor = DatasetCapture.RegisterSensor(ego, "camera", "", 0, CaptureTriggerMode.Scheduled, 0.1f, 0); |
|||
sensor.ReportCapture("file.txt", new SensorSpatialData()); |
|||
expectedDatasetPath = DatasetCapture.OutputDirectory; |
|||
yield return new ExitPlayMode(); |
|||
FileAssert.Exists(Path.Combine(expectedDatasetPath, "sensors.json")); |
|||
} |
|||
[UnityTest] |
|||
public IEnumerator StepFunction_OverridesSimulationDeltaTime_AndRunsSensors() |
|||
{ |
|||
yield return new EnterPlayMode(); |
|||
DatasetCapture.ResetSimulation(); |
|||
var ego = DatasetCapture.RegisterEgo("ego"); |
|||
var sensor = DatasetCapture.RegisterSensor(ego, "camera", "", 0, CaptureTriggerMode.Scheduled, 2f, 0); |
|||
yield return null; |
|||
var timeBeforeStep = Time.time; |
|||
EditorApplication.isPaused = true; |
|||
EditorApplication.Step(); |
|||
Assert.True(Time.time - timeBeforeStep < .3f); |
|||
Assert.True(sensor.ShouldCaptureThisFrame); |
|||
yield return new ExitPlayMode(); |
|||
Assert.Throws<InvalidOperationException>(() => SimulationManager.RegisterMetricDefinition("")); |
|||
} |
|||
} |
|||
} |
|
|||
{ |
|||
"dependencies": { |
|||
"com.unity.burst": "1.4.6", |
|||
"com.unity.collections": "0.9.0-preview.6", |
|||
"com.unity.simulation.capture": "0.0.10-preview.22", |
|||
"com.unity.simulation.client": "0.0.10-preview.10", |
|||
"com.unity.simulation.core": "0.0.10-preview.22" |
|||
}, |
|||
"description": "Tools for generating large-scale data sets for perception-based machine learning training and validation", |
|||
"displayName": "Perception", |
|||
"name": "com.unity.perception", |
|||
"unity": "2019.4", |
|||
"version": "0.8.0-preview.3", |
|||
"samples": [ |
|||
{ |
|||
"displayName": "Tutorial Files", |
|||
"description": "These files accompany the Perception Tutorial, found at https://github.com/Unity-Technologies/com.unity.perception", |
|||
"path": "Samples~/Tutorial Files" |
|||
}, |
|||
{ |
|||
"displayName": "Human Pose Labeling and Randomization", |
|||
"description": "These files accompany the Human Pose Labeling and Randomization Tutorial, found at https://github.com/Unity-Technologies/com.unity.perception", |
|||
"path": "Samples~/Human Pose Labeling and Randomization" |
|||
} |
|||
] |
|||
"com.unity.entities": "0.8.0-preview.8", |
|||
"com.unity.simulation.capture": "0.0.10-preview.6", |
|||
"com.unity.simulation.core": "0.0.10-preview.8" |
|||
}, |
|||
"description": "Tools for authoring and executing autonomous vehicle simulations.", |
|||
"displayName": "Perception", |
|||
"name": "com.unity.perception", |
|||
"unity": "2019.3", |
|||
"version": "0.1.0-preview.3" |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: be3971a848968144e8d07d9136a5bf49 |
|||
NativeFormatImporter: |
|||
externalObjects: {} |
|||
mainObjectFileID: 0 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
%YAML 1.1 |
|||
%TAG !u! tag:unity3d.com,2011: |
|||
--- !u!114 &11400000 |
|||
MonoBehaviour: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 0} |
|||
m_Enabled: 1 |
|||
m_EditorHideFlags: 0 |
|||
m_Script: {fileID: 11500000, guid: bad10bec3eccd8e49a9d725b2c30f74c, type: 3} |
|||
m_Name: LabelingConfiguration |
|||
m_EditorClassIdentifier: |
|||
AutoAssignIds: 1 |
|||
StartingLabelId: 1 |
|||
LabelEntries: |
|||
- id: 1 |
|||
label: Box |
|||
value: 10000 |
|||
- id: 2 |
|||
label: Crate |
|||
value: 20000 |
|||
- id: 3 |
|||
label: Cube |
|||
value: 30000 |
|
|||
fileFormatVersion: 2 |
|||
guid: e74234fe725079e4aa7ecd74797ceb79 |
|||
NativeFormatImporter: |
|||
externalObjects: {} |
|||
mainObjectFileID: 0 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 19ba41d7c0026c3459d37c2fe90c55a0 |
|||
NativeFormatImporter: |
|||
externalObjects: {} |
|||
mainObjectFileID: 0 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
%YAML 1.1 |
|||
%TAG !u! tag:unity3d.com,2011: |
|||
--- !u!114 &11400000 |
|||
MonoBehaviour: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 0} |
|||
m_Enabled: 1 |
|||
m_EditorHideFlags: 0 |
|||
m_Script: {fileID: 11500000, guid: bad10bec3eccd8e49a9d725b2c30f74c, type: 3} |
|||
m_Name: ExampleLabelingConfiguration |
|||
m_EditorClassIdentifier: |
|||
AutoAssignIds: 1 |
|||
StartingLabelId: 1 |
|||
LabelEntries: |
|||
- id: 1 |
|||
label: Box |
|||
value: 10000 |
|||
- id: 2 |
|||
label: Cube |
|||
value: 20000 |
|||
- id: 3 |
|||
label: Crate |
|||
value: 30000 |
|
|||
# Getting Started with SynthDet |
|||
This will provide a step by step instructions on creating a new scene using the Perception features to create semantic data and image captures. These steps should work with both options for setup steps of using a existing project or creating a new project. The goal is to have a working scene by the end of these instructions that will provide you with a dataset, rgb images captures, and segmentic data. |
|||
|
|||
If you have not already done the setup steps for the project, click [here](Documentation~/SetupSteps.md) to start project setup. |
|||
|
|||
## Step 1: Create a new scene and camera |
|||
1. Create a new scene File-> New Scene |
|||
2. Save the Scene File-> Save and give it a name, i.e created scene name is PerceptionScene |
|||
3. Select the Main Camera and reset the Position transform to 0 |
|||
4. In the Hierarchy window select the main camera |
|||
1. In the inspector panel of the main camera select Add Component |
|||
2. Add a **Perception Camera** component |
|||
|
|||
<img src="images/MainCameraConfig.PNG" align="middle"/> |
|||
|
|||
## Step 2: Create labeled objects |
|||
1. In the Hierarchy window right click -> Go to 3D Object -> Select Cube |
|||
1. Create 3 Cubes |
|||
2. Change the names of the cubes to have 3 seperate names Cube, Box, Crate |
|||
3. Position the Cubes in front of the FOV of the main Camera, example image of the completed scene for reference down below |
|||
<img src="images/CompletedScene.PNG" align="middle"/> |
|||
2. For each object in the scene that was created, from the inspector panel add the script called **Labeling** |
|||
1. Click the **+** |
|||
2. In the text field add the name of the object i.e Crate |
|||
<img src="images/LabeledObject.PNG" align="middle"/> |
|||
3. In the Project panel right click -> Perception -> Labeling Configuration |
|||
4. Select the **Labeling Configuration** created in the project panel |
|||
1. Click the **+** |
|||
2. In the label text field add the same text that the Label script contains on the objects created in the scene (i.e Cube, Box, Crate) |
|||
3. Add a numerical value to the value field |
|||
1. Make sure the labels all have different values, for this example use values of 10,000 |
|||
<img src="images/LabelingConfigurationFinished.PNG" align="middle"/> |
|||
9. Select the Main Camera in the Hierarchy panel |
|||
1. In the Perception Camera script in the Labeling Configuration field add the Labeling Configuration script created in previous step |
|||
<img src="images/MainCameraConfig.PNG" align="middle"/> |
|||
|
|||
## Step 3: Checking local files |
|||
1. Press play in the editor and allow the scene to run for 10 seconds before ending playmode |
|||
2. In the console log you will see a Shutdown in Progress message that will show a file path to the location of the generated dataset |
|||
3. The file path is the Application Persistent Path + /Defaultcompany/UnityTestFramework/<Hash Key> |
|||
1. Example file path on a Windows PC : *C:/Users/<User Name>/AppData/LocalLow/DefaultCompany/UnityTestFramework\2e10ec21-9d97-4cee-b5a2-7e95e299afa4\RGB18f61842-ef8d-4b31-acb5-cb1da36fb7b1* |
|||
4. In the output path for the Labeling content you can verify the following data is present: |
|||
1. RGB captures |
|||
2. Semantic segmentation images |
|||
3. Logs |
|||
4. JSON Dataset |
|||
<img src="images/rgb_2.png" align="middle"/> |
|||
<img src="images/segmentation_2.png" align="middle"/> |
|
|||
_Note: This document is a work in progress_ |
|||
|
|||
# Labeling |
|||
Accurately labeling assets with a predefined taxonomy will inform training and testing of algorithms as to which objects in a dataset have importance. Example: assets labeled with “table” and “chair” will provide an algorithm with the information it needs to train on identifying these objects separately within a scene. |
|||
|
|||
You can add a Labeling component to individual GameModels within a scene although it is a good practice to create a prefab of a GameModel and apply the Labeling component to it. |
|||
The Labeling components contain properties that control the number of labels applied to the GameModel. “Classes” has a property named “size”, this identifies how many labels are applied to a GameModel. Default = 0 (no label). Setting “size” to 1 will expose an “Element 0” parameter and an input field allowing for a custom label as text or numbers (combination of both) that can be used to label the asset. |
|||
|
|||
Multiple labels can be used by setting “size” to 2 or more. These additional Elements (labels) can be used for any purpose in development. For example in SynthDet labels have a hierarchy where Element0 is the highest level label identifying an GameModel in a very general category. Subsequent categories become more focused in identifying what types and groups an object can be classified. The last Element is reserved for the specific name (or label) the asset is defined as. |
|||
|
|||
## Labeling Configuration |
|||
Semantic segmentation (and other metrics) require a labeling configuration file located here: |
|||
This file gives a list of all labels currently being used in the data set and what RGB value they are associated with. This file can be used as is or created by the developer. When a Semantic segmentation output is generated the per pixel RGB value can be used to identify the object for the algorithm. |
|||
|
|||
Note: the labeling configuration file is not validated and must be managed by the developer. |
|||
|
|||
## Best practices |
|||
Generally algorithm testing and training requires a single label on an asset for proper identification (“chair”, “table”, “door, “window”, etc.) In Unity SynthDet a labeling hierarchy is used to identify assets at a higher level and/or more granularly. |
|||
|
|||
Example |
|||
An asset representing a box of Rice Krispies cereal is labeled as: food\cereal\kellogs\ricekrispies |
|||
“food” - type |
|||
“cereal” - subtype |
|||
“kellogs” - main descriptor |
|||
“ricekrispies” - sub descriptor |
|||
|
|||
If the goal of the algorithm is to identify all objects in a scene that is “food” that label is available and can be used. Conversely if the goal is to identify only Rice Krispies cereal within a scene that label is also available. Depending on the goal of the algorithm any mix of labels in the hierarchy can be used at the discretion of the developer. |
|
|||
# About the Perception SDK |
|||
com.unity.perception provides a toolkit for generating large-scale datasets for perception-based machine learning training and validation. It is focused on a handful of camera-based use cases for now and will ultimately expand to other forms of sensors and machine learning tasks. |
|||
|
|||
# Technical details |
|||
## Requirements |
|||
|
|||
This version of _Perception_ is compatible Unity Editor 2019.3 and later |
|||
|
|||
## Package contents |
|||
|Ground Truth|Captures semantic segmentation, bounding boxes, and other forms of ground truth.| |
|||
|---|---| |
|||
|Labeling|MonoBehaviour which marks an object and its descendants with a set of labels| |
|||
|Labeling Configuration|Asset which defines a taxonomy of labels used for ground truth generation | |
|||
|Perception Camera|Captures RGB images and ground truth on a Unity Camera| |
|||
|---|---| |
|
|||
#if HDRP_PRESENT
|
|||
|
|||
using System; |
|||
using UnityEditor.Rendering.HighDefinition; |
|||
using UnityEngine.Perception.GroundTruth; |
|||
|
|||
namespace UnityEditor.Perception.GroundTruth |
|||
{ |
|||
[CustomPassDrawer(typeof(ObjectCountPass))] |
|||
public class ObjectCountPassEditor : BaseCustomPassDrawer |
|||
{ |
|||
protected override void Initialize(SerializedProperty customPass) |
|||
{ |
|||
AddProperty(customPass.FindPropertyRelative(nameof(GroundTruthPass.targetCamera))); |
|||
AddProperty(customPass.FindPropertyRelative(nameof(ObjectCountPass.SegmentationTexture))); |
|||
AddProperty(customPass.FindPropertyRelative(nameof(ObjectCountPass.LabelingConfiguration))); |
|||
base.Initialize(customPass); |
|||
} |
|||
} |
|||
} |
|||
#endif
|
|
|||
using System; |
|||
using Unity.Mathematics; |
|||
using UnityEditorInternal; |
|||
using UnityEngine; |
|||
using UnityEngine.Perception.GroundTruth; |
|||
|
|||
namespace UnityEditor.Perception.GroundTruth |
|||
{ |
|||
[CustomEditor(typeof(LabelingConfiguration))] |
|||
class LabelingConfigurationEditor : Editor |
|||
{ |
|||
ReorderableList m_LabelsList; |
|||
const float k_Margin = 5f; |
|||
|
|||
public void OnEnable() |
|||
{ |
|||
m_LabelsList = new ReorderableList(this.serializedObject, this.serializedObject.FindProperty(nameof(LabelingConfiguration.LabelEntries)), true, false, true, true); |
|||
m_LabelsList.elementHeight = EditorGUIUtility.singleLineHeight * 3 + k_Margin; |
|||
m_LabelsList.drawElementCallback = DrawElement; |
|||
m_LabelsList.onAddCallback += OnAdd; |
|||
m_LabelsList.onRemoveCallback += OnRemove; |
|||
m_LabelsList.onReorderCallbackWithDetails += OnReorder; |
|||
} |
|||
|
|||
void OnReorder(ReorderableList list, int oldIndex, int newIndex) |
|||
{ |
|||
if (!autoAssign) |
|||
return; |
|||
|
|||
AutoAssignIds(); |
|||
} |
|||
|
|||
void OnRemove(ReorderableList list) |
|||
{ |
|||
if (list.index != -1) |
|||
list.serializedProperty.DeleteArrayElementAtIndex(list.index); |
|||
|
|||
if (autoAssign) |
|||
AutoAssignIds(); |
|||
|
|||
this.serializedObject.ApplyModifiedProperties(); |
|||
EditorUtility.SetDirty(target); |
|||
} |
|||
|
|||
void OnAdd(ReorderableList list) |
|||
{ |
|||
int maxLabel = Int32.MinValue; |
|||
if (list.serializedProperty.arraySize == 0) |
|||
maxLabel = -1; |
|||
|
|||
for (int i = 0; i < list.serializedProperty.arraySize; i++) |
|||
{ |
|||
var item = list.serializedProperty.GetArrayElementAtIndex(i); |
|||
maxLabel = math.max(maxLabel, item.FindPropertyRelative(nameof(LabelEntry.id)).intValue); |
|||
} |
|||
var index = list.serializedProperty.arraySize; |
|||
list.serializedProperty.InsertArrayElementAtIndex(index); |
|||
var element = list.serializedProperty.GetArrayElementAtIndex(index); |
|||
var idProperty = element.FindPropertyRelative(nameof(LabelEntry.id)); |
|||
idProperty.intValue = maxLabel + 1; |
|||
var labelProperty = element.FindPropertyRelative(nameof(LabelEntry.label)); |
|||
labelProperty.stringValue = ""; |
|||
var valueProperty = element.FindPropertyRelative(nameof(LabelEntry.value)); |
|||
valueProperty.intValue = 0; |
|||
|
|||
if (autoAssign) |
|||
AutoAssignIds(); |
|||
|
|||
serializedObject.ApplyModifiedProperties(); |
|||
EditorUtility.SetDirty(target); |
|||
} |
|||
|
|||
void DrawElement(Rect rect, int index, bool isactive, bool isfocused) |
|||
{ |
|||
var element = m_LabelsList.serializedProperty.GetArrayElementAtIndex(index); |
|||
var idProperty = element.FindPropertyRelative(nameof(LabelEntry.id)); |
|||
var labelProperty = element.FindPropertyRelative(nameof(LabelEntry.label)); |
|||
var valueProperty = element.FindPropertyRelative(nameof(LabelEntry.value)); |
|||
using (var change = new EditorGUI.ChangeCheckScope()) |
|||
{ |
|||
var contentRect = new Rect(rect.position, new Vector2(rect.width, EditorGUIUtility.singleLineHeight)); |
|||
using (new EditorGUI.DisabledScope(autoAssign)) |
|||
{ |
|||
var newLabel = EditorGUI.IntField(contentRect, nameof(LabelEntry.id), idProperty.intValue); |
|||
if (change.changed) |
|||
{ |
|||
idProperty.intValue = newLabel; |
|||
if (autoAssign) |
|||
AutoAssignIds(); |
|||
} |
|||
} |
|||
} |
|||
using (var change = new EditorGUI.ChangeCheckScope()) |
|||
{ |
|||
var contentRect = new Rect(rect.position + new Vector2(0, EditorGUIUtility.singleLineHeight), new Vector2(rect.width, EditorGUIUtility.singleLineHeight)); |
|||
var newLabel = EditorGUI.TextField(contentRect, nameof(LabelEntry.label), labelProperty.stringValue); |
|||
if (change.changed) |
|||
{ |
|||
labelProperty.stringValue = newLabel; |
|||
} |
|||
} |
|||
|
|||
using (var change = new EditorGUI.ChangeCheckScope()) |
|||
{ |
|||
var contentRect = new Rect(rect.position + new Vector2(0, EditorGUIUtility.singleLineHeight * 2), new Vector2(rect.width, EditorGUIUtility.singleLineHeight)); |
|||
var newValue = EditorGUI.IntField(contentRect, nameof(LabelEntry.value), valueProperty.intValue); |
|||
if (change.changed) |
|||
valueProperty.intValue = newValue; |
|||
} |
|||
} |
|||
|
|||
bool autoAssign => serializedObject.FindProperty(nameof(LabelingConfiguration.AutoAssignIds)).boolValue; |
|||
|
|||
public override void OnInspectorGUI() |
|||
{ |
|||
serializedObject.Update(); |
|||
var autoAssignIdsProperty = serializedObject.FindProperty(nameof(LabelingConfiguration.AutoAssignIds)); |
|||
using (var change = new EditorGUI.ChangeCheckScope()) |
|||
{ |
|||
EditorGUILayout.PropertyField(autoAssignIdsProperty, new GUIContent("Auto Assign IDs")); |
|||
if (change.changed && autoAssignIdsProperty.boolValue) |
|||
AutoAssignIds(); |
|||
} |
|||
|
|||
if (autoAssignIdsProperty.boolValue) |
|||
{ |
|||
using (var change = new EditorGUI.ChangeCheckScope()) |
|||
{ |
|||
var startingLabelIdProperty = serializedObject.FindProperty(nameof(LabelingConfiguration.StartingLabelId)); |
|||
EditorGUILayout.PropertyField(startingLabelIdProperty, new GUIContent("Starting Label ID")); |
|||
if (change.changed) |
|||
AutoAssignIds(); |
|||
} |
|||
} |
|||
|
|||
m_LabelsList.DoLayoutList(); |
|||
this.serializedObject.ApplyModifiedProperties(); |
|||
} |
|||
|
|||
void AutoAssignIds() |
|||
{ |
|||
var serializedProperty = serializedObject.FindProperty(nameof(LabelingConfiguration.LabelEntries)); |
|||
var size = serializedProperty.arraySize; |
|||
if (size == 0) |
|||
return; |
|||
|
|||
var startingLabelId = (StartingLabelId)serializedObject.FindProperty(nameof(LabelingConfiguration.StartingLabelId)).enumValueIndex; |
|||
|
|||
var nextId = startingLabelId == StartingLabelId.One ? 1 : 0; |
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
serializedProperty.GetArrayElementAtIndex(i).FindPropertyRelative(nameof(LabelEntry.id)).intValue = nextId; |
|||
nextId++; |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using Unity.Entities; |
|||
using UnityEngine; |
|||
using UnityEngine.Experimental.Rendering; |
|||
using UnityEngine.Rendering; |
|||
|
|||
namespace UnityEngine.Perception.GroundTruth |
|||
{ |
|||
abstract class GroundTruthCrossPipelinePass : IGroundTruthGenerator |
|||
{ |
|||
public Camera targetCamera; |
|||
|
|||
bool m_IsActivated; |
|||
|
|||
protected GroundTruthCrossPipelinePass(Camera targetCamera) |
|||
{ |
|||
this.targetCamera = targetCamera; |
|||
} |
|||
|
|||
public virtual void Setup() |
|||
{ |
|||
if (targetCamera == null) |
|||
throw new InvalidOperationException("targetCamera may not be null"); |
|||
|
|||
// If we are forced to activate here we will get zeroes in the first frame.
|
|||
EnsureActivated(); |
|||
} |
|||
|
|||
public void Execute(ScriptableRenderContext renderContext, CommandBuffer cmd, Camera camera, CullingResults cullingResult) |
|||
{ |
|||
// CustomPasses are executed for each camera. We only want to run for the target camera
|
|||
if (camera != targetCamera) |
|||
return; |
|||
|
|||
ExecutePass(renderContext, cmd, camera, cullingResult); |
|||
} |
|||
|
|||
protected abstract void ExecutePass(ScriptableRenderContext renderContext, CommandBuffer cmd, Camera camera, CullingResults cullingResult); |
|||
|
|||
public void EnsureActivated() |
|||
{ |
|||
if (!m_IsActivated) |
|||
{ |
|||
var labelSetupSystem = World.DefaultGameObjectInjectionWorld?.GetExistingSystem<GroundTruthLabelSetupSystem>(); |
|||
labelSetupSystem?.Activate(this); |
|||
m_IsActivated = true; |
|||
} |
|||
} |
|||
|
|||
public void Cleanup() |
|||
{ |
|||
var labelSetupSystem = World.DefaultGameObjectInjectionWorld?.GetExistingSystem<GroundTruthLabelSetupSystem>(); |
|||
labelSetupSystem?.Deactivate(this); |
|||
} |
|||
|
|||
protected RendererListDesc CreateRendererListDesc(Camera camera, CullingResults cullingResult, string overrideMaterialPassName, int overrideMaterialPassIndex, Material overrideMaterial, LayerMask layerMask /*, PerObjectData perObjectData*/) |
|||
{ |
|||
var shaderPasses = new[] |
|||
{ |
|||
new ShaderTagId("Forward"), // HD Lit shader
|
|||
new ShaderTagId("ForwardOnly"), // HD Unlit shader
|
|||
new ShaderTagId("SRPDefaultUnlit"), // Cross SRP Unlit shader
|
|||
new ShaderTagId("UniversalForward"), // URP Forward
|
|||
new ShaderTagId("LightweightForward"), // LWRP Forward
|
|||
new ShaderTagId(overrideMaterialPassName), // The override material shader
|
|||
}; |
|||
|
|||
var stateBlock = new RenderStateBlock(0) |
|||
{ |
|||
depthState = new DepthState(true, CompareFunction.LessEqual), |
|||
}; |
|||
|
|||
var result = new RendererListDesc(shaderPasses, cullingResult, camera) |
|||
{ |
|||
rendererConfiguration = PerObjectData.None, |
|||
renderQueueRange = new RenderQueueRange { lowerBound = 0, upperBound = 5000 }, |
|||
sortingCriteria = SortingCriteria.CommonOpaque, |
|||
excludeObjectMotionVectors = false, |
|||
overrideMaterial = overrideMaterial, |
|||
overrideMaterialPassIndex = overrideMaterialPassIndex, |
|||
stateBlock = stateBlock, |
|||
layerMask = layerMask, |
|||
}; |
|||
return result; |
|||
} |
|||
|
|||
public static void DrawRendererList(ScriptableRenderContext renderContext, CommandBuffer cmd, RendererList rendererList) |
|||
{ |
|||
if (!rendererList.isValid) |
|||
throw new ArgumentException("Invalid renderer list provided to DrawRendererList"); |
|||
|
|||
// This is done here because DrawRenderers API lives outside command buffers so we need to make call this before doing any DrawRenders or things will be executed out of order
|
|||
renderContext.ExecuteCommandBuffer(cmd); |
|||
cmd.Clear(); |
|||
|
|||
if (rendererList.stateBlock == null) |
|||
renderContext.DrawRenderers(rendererList.cullingResult, ref rendererList.drawSettings, ref rendererList.filteringSettings); |
|||
else |
|||
{ |
|||
var renderStateBlock = rendererList.stateBlock.Value; |
|||
renderContext.DrawRenderers(rendererList.cullingResult, ref rendererList.drawSettings, ref rendererList.filteringSettings, ref renderStateBlock); |
|||
} |
|||
} |
|||
|
|||
public abstract void SetupMaterialProperties(MaterialPropertyBlock mpb, MeshRenderer meshRenderer, Labeling labeling, uint instanceId); |
|||
} |
|||
} |
|
|||
using Unity.Entities; |
|||
|
|||
namespace UnityEngine.Perception.GroundTruth |
|||
{ |
|||
/// <summary>
|
|||
/// Information regarding a Labeling instance. Generated by <see cref="GroundTruthLabelSetupSystem"/>
|
|||
/// </summary>
|
|||
public struct GroundTruthInfo : IComponentData |
|||
{ |
|||
/// <summary>
|
|||
/// The instanceId assigned to the <see cref="Labeling"/>
|
|||
/// </summary>
|
|||
public uint instanceId; |
|||
} |
|||
} |
|
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
using Unity.Entities; |
|||
|
|||
namespace UnityEngine.Perception.GroundTruth |
|||
{ |
|||
struct IdAssignmentParameters : IComponentData |
|||
{ |
|||
public uint idStart; |
|||
public uint idStep; |
|||
} |
|||
/// <summary>
|
|||
/// System which notifies the registered <see cref="IGroundTruthGenerator"/> about <see cref="Labeling"/> additions.
|
|||
/// </summary>
|
|||
public class GroundTruthLabelSetupSystem : ComponentSystem |
|||
{ |
|||
List<IGroundTruthGenerator> m_ActiveGenerators = new List<IGroundTruthGenerator>(); |
|||
ThreadLocal<MaterialPropertyBlock> m_MaterialPropertyBlocks = new ThreadLocal<MaterialPropertyBlock>(); |
|||
int m_CurrentObjectIndex = -1; |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnCreate() |
|||
{ |
|||
//These are here to inform the system runner the queries we are interested in. Without these calls, OnUpdate() might not be called
|
|||
GetEntityQuery(ComponentType.Exclude<GroundTruthInfo>(), ComponentType.ReadOnly<Labeling>()); |
|||
GetEntityQuery(ComponentType.ReadOnly<GroundTruthInfo>(), ComponentType.ReadOnly<Labeling>()); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnUpdate() |
|||
{ |
|||
var entityQuery = Entities.WithAll<IdAssignmentParameters>().ToEntityQuery(); |
|||
IdAssignmentParameters idAssignmentParameters; |
|||
if (entityQuery.CalculateEntityCount() == 1) |
|||
idAssignmentParameters = entityQuery.GetSingleton<IdAssignmentParameters>(); |
|||
else |
|||
idAssignmentParameters = new IdAssignmentParameters {idStart = 1, idStep = 1}; |
|||
|
|||
var entityCount = Entities.WithAll<Labeling, GroundTruthInfo>().ToEntityQuery().CalculateEntityCount(); |
|||
if (entityCount == 0) |
|||
m_CurrentObjectIndex = -1; |
|||
|
|||
Entities.WithNone<GroundTruthInfo>().ForEach((Entity e, Labeling labeling) => |
|||
{ |
|||
var objectIndex = (uint)Interlocked.Increment(ref m_CurrentObjectIndex); |
|||
var instanceId = idAssignmentParameters.idStart + objectIndex * idAssignmentParameters.idStep; |
|||
var gameObject = labeling.gameObject; |
|||
if (!m_MaterialPropertyBlocks.IsValueCreated) |
|||
m_MaterialPropertyBlocks.Value = new MaterialPropertyBlock(); |
|||
|
|||
InitGameObjectRecursive(gameObject, m_MaterialPropertyBlocks.Value, labeling, instanceId); |
|||
EntityManager.AddComponentData(e, new GroundTruthInfo |
|||
{ |
|||
instanceId = instanceId |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
void InitGameObjectRecursive(GameObject gameObject, MaterialPropertyBlock mpb, Labeling labeling, uint instanceId) |
|||
{ |
|||
var meshRenderer = gameObject.GetComponent<MeshRenderer>(); |
|||
if (meshRenderer != null) |
|||
{ |
|||
meshRenderer.GetPropertyBlock(mpb); |
|||
foreach (var pass in m_ActiveGenerators) |
|||
pass.SetupMaterialProperties(mpb, meshRenderer, labeling, instanceId); |
|||
|
|||
meshRenderer.SetPropertyBlock(mpb); |
|||
} |
|||
|
|||
for (var i = 0; i < gameObject.transform.childCount; i++) |
|||
{ |
|||
var child = gameObject.transform.GetChild(i).gameObject; |
|||
if (child.GetComponent<Labeling>() != null) |
|||
continue; |
|||
|
|||
InitGameObjectRecursive(child, mpb, labeling, instanceId); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Activates the given <see cref="IGroundTruthGenerator"/>. <see cref="IGroundTruthGenerator.SetupMaterialProperties"/>
|
|||
/// will be called for all <see cref="MeshRenderer"/> instances under each object containing a <see cref="Labeling"/> component.
|
|||
/// </summary>
|
|||
/// <param name="generator">The generator to register</param>
|
|||
public void Activate(IGroundTruthGenerator generator) |
|||
{ |
|||
m_ActiveGenerators.Add(generator); |
|||
Entities.ForEach((Labeling labeling, ref GroundTruthInfo info) => |
|||
{ |
|||
var gameObject = labeling.gameObject; |
|||
InitGameObjectRecursive(gameObject, m_MaterialPropertyBlocks.Value, labeling, info.instanceId); |
|||
}); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Deactivates the given <see cref="IGroundTruthGenerator"/>. It will no longer receive calls when <see cref="Labeling"/> instances are created.
|
|||
/// </summary>
|
|||
/// <param name="generator">The generator to deactivate</param>
|
|||
/// <returns>True if the <see cref="generator"/> was successfully removed. False if <see cref="generator"/> was not active.</returns>
|
|||
public bool Deactivate(IGroundTruthGenerator generator) |
|||
{ |
|||
return m_ActiveGenerators.Remove(generator); |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Unity.Profiling; |
|||
using UnityEngine; |
|||
using UnityEngine.Experimental.Rendering; |
|||
using UnityEngine.Rendering; |
|||
|
|||
namespace UnityEngine.Perception.GroundTruth |
|||
{ |
|||
class InstanceSegmentationCrossPipelinePass : GroundTruthCrossPipelinePass |
|||
{ |
|||
static readonly int k_SegmentationIdProperty = Shader.PropertyToID("_SegmentationId"); |
|||
const string k_SegmentationPassShaderName = "Perception/InstanceSegmentation"; |
|||
|
|||
static ProfilerMarker s_ExecuteMarker = new ProfilerMarker("SegmentationPass_Execute"); |
|||
|
|||
/// <summary>
|
|||
/// The LayerMask to apply when rendering objects.
|
|||
/// </summary>
|
|||
public LayerMask layerMask = -1; |
|||
|
|||
Shader m_SegmentationShader; |
|||
Material m_OverrideMaterial; |
|||
int m_NextObjectIndex; |
|||
|
|||
Dictionary<uint, uint> m_Ids; |
|||
|
|||
/// <summary>
|
|||
/// Create a new <see cref="InstanceSegmentationCrossPipelinePass"/> referencing the given
|
|||
/// </summary>
|
|||
/// <param name="targetCamera"></param>
|
|||
/// <exception cref="ArgumentNullException"></exception>
|
|||
public InstanceSegmentationCrossPipelinePass(Camera targetCamera) |
|||
: base(targetCamera) |
|||
{ |
|||
if (targetCamera == null) |
|||
throw new ArgumentNullException(nameof(targetCamera)); |
|||
|
|||
//Activating in the constructor allows us to get correct labeling in the first frame.
|
|||
EnsureActivated(); |
|||
} |
|||
|
|||
public override void Setup() |
|||
{ |
|||
base.Setup(); |
|||
m_SegmentationShader = Shader.Find(k_SegmentationPassShaderName); |
|||
var shaderVariantCollection = new ShaderVariantCollection(); |
|||
shaderVariantCollection.Add(new ShaderVariantCollection.ShaderVariant(m_SegmentationShader, PassType.ScriptableRenderPipeline)); |
|||
shaderVariantCollection.WarmUp(); |
|||
|
|||
m_OverrideMaterial = new Material(m_SegmentationShader); |
|||
} |
|||
|
|||
//Render all objects to our target RenderTexture using `overrideMaterial` to use our shader
|
|||
protected override void ExecutePass(ScriptableRenderContext renderContext, CommandBuffer cmd, Camera camera, CullingResults cullingResult) |
|||
{ |
|||
using (s_ExecuteMarker.Auto()) |
|||
{ |
|||
cmd.ClearRenderTarget(true, true, Color.clear); |
|||
var result = CreateRendererListDesc(camera, cullingResult, "FirstPass", 0, m_OverrideMaterial, layerMask); |
|||
|
|||
DrawRendererList(renderContext, cmd, RendererList.Create(result)); |
|||
} |
|||
} |
|||
|
|||
public override void SetupMaterialProperties(MaterialPropertyBlock mpb, MeshRenderer meshRenderer, Labeling labeling, uint instanceId) |
|||
{ |
|||
mpb.SetInt(k_SegmentationIdProperty, (int)instanceId); |
|||
#if PERCEPTION_DEBUG
|
|||
Debug.Log($"Assigning id. Frame {Time.frameCount} id {id}"); |
|||
#endif
|
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UnityEngine.Serialization; |
|||
|
|||
namespace UnityEngine.Perception.GroundTruth |
|||
{ |
|||
/// <summary>
|
|||
/// A definition for how a <see cref="Labeling"/> should be resolved to a single label and id for ground truth generation.
|
|||
/// </summary>
|
|||
[CreateAssetMenu(fileName = "LabelingConfiguration", menuName = "Perception/Labeling Configuration", order = 1)] |
|||
public class LabelingConfiguration : ScriptableObject |
|||
{ |
|||
/// <summary>
|
|||
/// Whether the inspector will auto-assign ids based on the id of the first element.
|
|||
/// </summary>
|
|||
public bool AutoAssignIds = true; |
|||
|
|||
/// <summary>
|
|||
/// Whether the inspector will start label ids at zero or one when <see cref="AutoAssignIds"/> is enabled.
|
|||
/// </summary>
|
|||
public StartingLabelId StartingLabelId = StartingLabelId.One; |
|||
|
|||
/// <summary>
|
|||
/// A sequence of <see cref="LabelEntry"/> which defines the labels relevant for this configuration and their values.
|
|||
/// </summary>
|
|||
[FormerlySerializedAs("LabelingConfigurations")] |
|||
[SerializeField] |
|||
public List<LabelEntry> LabelEntries = new List<LabelEntry>(); |
|||
|
|||
/// <summary>
|
|||
/// Attempts to find the matching index in <see cref="LabelEntries"/> for the given <see cref="Labeling"/>.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The matching index is the first class name in the given Labeling which matches an entry in <see cref="LabelEntries"/>.
|
|||
/// </remarks>
|
|||
/// <param name="labeling">The <see cref="Labeling"/> to match </param>
|
|||
/// <param name="labelEntry">When this method returns, contains the matching <see cref="LabelEntry"/>, or <code>default</code> if no match was found.</param>
|
|||
/// <returns>Returns true if a match was found. False if not.</returns>
|
|||
public bool TryGetMatchingConfigurationEntry(Labeling labeling, out LabelEntry labelEntry) |
|||
{ |
|||
return TryGetMatchingConfigurationEntry(labeling, out labelEntry, out int _); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Attempts to find the matching index in <see cref="LabelEntries"/> for the given <see cref="Labeling"/>.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The matching index is the first class name in the given Labeling which matches an entry in <see cref="LabelEntries"/>.
|
|||
/// </remarks>
|
|||
/// <param name="labeling">The <see cref="Labeling"/> to match </param>
|
|||
/// <param name="labelEntry">When this method returns, contains the matching <see cref="LabelEntry"/>, or <code>default</code> if no match was found.</param>
|
|||
/// <param name="labelEntryIndex">When this method returns, contains the index of the matching <see cref="LabelEntry"/>, or <code>-1</code> if no match was found.</param>
|
|||
/// <returns>Returns true if a match was found. False if not.</returns>
|
|||
public bool TryGetMatchingConfigurationEntry(Labeling labeling, out LabelEntry labelEntry, out int labelEntryIndex) |
|||
{ |
|||
foreach (var labelingClass in labeling.labels) |
|||
{ |
|||
for (var i = 0; i < LabelEntries.Count; i++) |
|||
{ |
|||
var entry = LabelEntries[i]; |
|||
if (string.Equals(entry.label, labelingClass)) |
|||
{ |
|||
labelEntry = entry; |
|||
labelEntryIndex = i; |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
labelEntryIndex = -1; |
|||
labelEntry = default; |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Structure defining a label configuration for <see cref="LabelingConfiguration"/>.
|
|||
/// </summary>
|
|||
[Serializable] |
|||
public struct LabelEntry |
|||
{ |
|||
/// <summary>
|
|||
/// The id associated with the label. Used to associate objects with labels in various forms of ground truth.
|
|||
/// </summary>
|
|||
public int id; |
|||
/// <summary>
|
|||
/// The label string
|
|||
/// </summary>
|
|||
public string label; |
|||
/// <summary>
|
|||
/// The value to use when generating semantic segmentation images.
|
|||
/// </summary>
|
|||
public int value; |
|||
|
|||
/// <summary>
|
|||
/// Creates a new LabelingConfigurationEntry with the given values.
|
|||
/// </summary>
|
|||
/// <param name="id">The id associated with the label. Used to associate objects with labels in various forms of ground truth.</param>
|
|||
/// <param name="label">The label string.</param>
|
|||
/// <param name="value">The value to use when generating semantic segmentation images.</param>
|
|||
public LabelEntry(int id, string label, int value) |
|||
{ |
|||
this.id = id; |
|||
this.label = label; |
|||
this.value = value; |
|||
} |
|||
} |
|||
} |
|
|||
#if HDRP_PRESENT
|
|||
|
|||
using Unity.Collections.LowLevel.Unsafe; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Unity.Collections; |
|||
using UnityEngine.Rendering.HighDefinition; |
|||
using UnityEngine.Rendering; |
|||
|
|||
namespace UnityEngine.Perception.GroundTruth |
|||
{ |
|||
/// <summary>
|
|||
/// CustomPass which computes object count for each label in the given LabelingConfiguration in the frame.
|
|||
/// Requires the texture produced by an InstanceSegmentationPass.
|
|||
/// </summary>
|
|||
public class ObjectCountPass : GroundTruthPass |
|||
{ |
|||
const int k_StartingObjectCount = 1 << 8; |
|||
public RenderTexture SegmentationTexture; |
|||
public LabelingConfiguration LabelingConfiguration; |
|||
|
|||
ComputeShader m_ComputeShader; |
|||
ComputeBuffer m_InstanceIdPresenceMask; |
|||
ComputeBuffer m_InstanceIdToClassId; |
|||
ComputeBuffer m_ClassCounts; |
|||
NativeList<int> m_InstanceIdToLabelIndexLookup; |
|||
HashSet<Camera> m_CamerasRendered = new HashSet<Camera>(); |
|||
bool m_IdBuffersNeedUpdating; |
|||
bool m_DidComputeLastFrame; |
|||
|
|||
public ObjectCountPass(Camera camera) : base(camera) |
|||
{ |
|||
} |
|||
|
|||
// ReSharper disable once UnusedMember.Global
|
|||
public ObjectCountPass() : base(null) |
|||
{ |
|||
} |
|||
|
|||
public override void SetupMaterialProperties(MaterialPropertyBlock mpb, MeshRenderer meshRenderer, Labeling labeling, uint instanceId) |
|||
{ |
|||
if (!m_InstanceIdToLabelIndexLookup.IsCreated) |
|||
{ |
|||
m_InstanceIdToLabelIndexLookup = new NativeList<int>(k_StartingObjectCount, Allocator.Persistent); |
|||
} |
|||
if (LabelingConfiguration.TryGetMatchingConfigurationEntry(labeling, out LabelEntry labelEntry, out var index)) |
|||
{ |
|||
if (m_InstanceIdToLabelIndexLookup.Length <= instanceId) |
|||
{ |
|||
m_InstanceIdToLabelIndexLookup.Resize((int)instanceId + 1, NativeArrayOptions.ClearMemory); |
|||
} |
|||
m_IdBuffersNeedUpdating = true; |
|||
m_InstanceIdToLabelIndexLookup[(int)instanceId] = index + 1; |
|||
} |
|||
} |
|||
|
|||
protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd) |
|||
{ |
|||
base.Setup(renderContext, cmd); |
|||
m_ComputeShader = Resources.Load<ComputeShader>("LabeledObjectHistogram"); |
|||
|
|||
var objectCount = k_StartingObjectCount; |
|||
UpdateIdBufferSizes(objectCount); |
|||
m_ClassCounts = new ComputeBuffer(LabelingConfiguration.LabelEntries.Count + 1, UnsafeUtility.SizeOf<uint>(), ComputeBufferType.Structured); |
|||
|
|||
RenderPipelineManager.endCameraRendering += OnEndCameraRendering; |
|||
} |
|||
|
|||
void OnEndCameraRendering(ScriptableRenderContext renderContext, Camera camera) |
|||
{ |
|||
} |
|||
|
|||
void UpdateIdBufferSizes(int objectCount) |
|||
{ |
|||
var presenceMaskSizeNeeded = objectCount; |
|||
if (m_InstanceIdPresenceMask == null || presenceMaskSizeNeeded > m_InstanceIdPresenceMask.count) |
|||
{ |
|||
m_InstanceIdPresenceMask?.Release(); |
|||
m_InstanceIdPresenceMask = new ComputeBuffer(presenceMaskSizeNeeded, UnsafeUtility.SizeOf<uint>(), ComputeBufferType.Structured); |
|||
} |
|||
|
|||
if (m_InstanceIdToClassId == null || m_InstanceIdToClassId.count < objectCount) |
|||
{ |
|||
m_InstanceIdToClassId?.Release(); |
|||
m_InstanceIdToClassId = new ComputeBuffer(objectCount, UnsafeUtility.SizeOf<uint>(), ComputeBufferType.Structured); |
|||
} |
|||
} |
|||
|
|||
protected override void ExecutePass(ScriptableRenderContext renderContext, CommandBuffer cmd, HDCamera hdCamera, CullingResults cullingResult) |
|||
{ |
|||
//If there are no objects to label, skip the pass
|
|||
if (!m_InstanceIdToLabelIndexLookup.IsCreated || m_InstanceIdToLabelIndexLookup.Length == 0) |
|||
{ |
|||
var counts = new NativeArray<uint>(LabelingConfiguration.LabelEntries.Count + 1, Allocator.Temp); |
|||
OnClassCountReadback(Time.frameCount, counts); |
|||
counts.Dispose(); |
|||
return; |
|||
} |
|||
|
|||
m_CamerasRendered.Add(hdCamera.camera); |
|||
|
|||
if (m_IdBuffersNeedUpdating) |
|||
{ |
|||
UpdateIdBufferSizes(m_InstanceIdToLabelIndexLookup.Capacity); |
|||
m_InstanceIdToClassId.SetData(m_InstanceIdToLabelIndexLookup.AsArray()); |
|||
} |
|||
|
|||
//The following section kicks off the four kernels in LabeledObjectHistogram.compute
|
|||
|
|||
//clear ClassCounts
|
|||
cmd.SetComputeBufferParam(m_ComputeShader, 1, "ClassCounts", m_ClassCounts); |
|||
cmd.DispatchCompute(m_ComputeShader, 1, m_ClassCounts.count, 1, 1); |
|||
|
|||
//clear InstanceIdPresenceMask
|
|||
cmd.SetComputeBufferParam(m_ComputeShader, 2, "InstanceIdPresenceMask", m_InstanceIdPresenceMask); |
|||
cmd.DispatchCompute(m_ComputeShader, 2, m_InstanceIdPresenceMask.count, 1, 1); |
|||
|
|||
//clear InstanceIdPresenceMask
|
|||
cmd.SetComputeTextureParam(m_ComputeShader, 0, "SegmentationTexture", SegmentationTexture); |
|||
cmd.SetComputeBufferParam(m_ComputeShader, 0, "InstanceIdPresenceMask", m_InstanceIdPresenceMask); |
|||
cmd.SetComputeIntParam(m_ComputeShader, "Width", SegmentationTexture.width); |
|||
cmd.SetComputeIntParam(m_ComputeShader, "Height", SegmentationTexture.height); |
|||
cmd.DispatchCompute(m_ComputeShader, 0, SegmentationTexture.width, SegmentationTexture.height, 1); |
|||
|
|||
//clear InstanceIdPresenceMask
|
|||
cmd.SetComputeBufferParam(m_ComputeShader, 3, "InstanceIdPresenceMask", m_InstanceIdPresenceMask); |
|||
cmd.SetComputeBufferParam(m_ComputeShader, 3, "InstanceIdToClassId", m_InstanceIdToClassId); |
|||
cmd.SetComputeBufferParam(m_ComputeShader, 3, "ClassCounts", m_ClassCounts); |
|||
cmd.DispatchCompute(m_ComputeShader, 3, m_InstanceIdToLabelIndexLookup.Length, 1, 1); |
|||
|
|||
var requestFrameCount = Time.frameCount; |
|||
cmd.RequestAsyncReadback(m_ClassCounts, request => OnClassCountReadback(requestFrameCount, request.GetData<uint>())); |
|||
} |
|||
|
|||
protected override void Cleanup() |
|||
{ |
|||
base.Cleanup(); |
|||
m_InstanceIdPresenceMask?.Dispose(); |
|||
m_InstanceIdPresenceMask = null; |
|||
m_InstanceIdToClassId?.Dispose(); |
|||
m_InstanceIdToClassId = null; |
|||
m_ClassCounts?.Dispose(); |
|||
m_ClassCounts = null; |
|||
WaitForAllRequests(); |
|||
|
|||
if (m_InstanceIdToLabelIndexLookup.IsCreated) |
|||
{ |
|||
m_InstanceIdToLabelIndexLookup.Dispose(); |
|||
m_InstanceIdToLabelIndexLookup = default; |
|||
} |
|||
} |
|||
|
|||
internal event Action<NativeSlice<uint>, IReadOnlyList<LabelEntry>, int> ClassCountsReceived; |
|||
|
|||
void OnClassCountReadback(int requestFrameCount, NativeArray<uint> counts) |
|||
{ |
|||
#if PERCEPTION_DEBUG
|
|||
StringBuilder sb = new StringBuilder(); |
|||
sb.AppendFormat("Histogram data. Frame {0}", requestFrameCount.ToString()); |
|||
for (int i = 0; i < LabelingConfiguration.LabelingConfigurations.Count; i++) |
|||
{ |
|||
sb.AppendFormat("{0}: {1}", LabelingConfiguration.LabelingConfigurations[i].label, |
|||
counts[i + 1].ToString()); |
|||
sb.AppendLine(); |
|||
} |
|||
Debug.Log(sb); |
|||
#endif
|
|||
|
|||
ClassCountsReceived?.Invoke(new NativeSlice<uint>(counts, 1), LabelingConfiguration.LabelEntries, requestFrameCount); |
|||
} |
|||
|
|||
public void WaitForAllRequests() |
|||
{ |
|||
var commandBuffer = CommandBufferPool.Get("LabelHistorgramCleanup"); |
|||
commandBuffer.WaitAllAsyncReadbackRequests(); |
|||
Graphics.ExecuteCommandBuffer(commandBuffer); |
|||
CommandBufferPool.Release(commandBuffer); |
|||
} |
|||
} |
|||
} |
|||
#endif
|
|
|||
using System; |
|||
using UnityEngine.Experimental.Rendering; |
|||
using UnityEngine.Rendering; |
|||
|
|||
namespace UnityEngine.Perception.GroundTruth |
|||
{ |
|||
/// <summary>
|
|||
/// Custom Pass which renders labeled images where each object labeled with a Labeling component is drawn with the
|
|||
/// value specified by the given LabelingConfiguration.
|
|||
/// </summary>
|
|||
class SemanticSegmentationCrossPipelinePass : GroundTruthCrossPipelinePass |
|||
{ |
|||
const string k_ShaderName = "Perception/SemanticSegmentation"; |
|||
static readonly int k_LabelingId = Shader.PropertyToID("LabelingId"); |
|||
|
|||
LabelingConfiguration m_LabelingConfiguration; |
|||
|
|||
//Serialize the shader so that the shader asset is included in player builds when the SemanticSegmentationPass is used.
|
|||
//Currently commented out and shaders moved to Resources folder due to serialization crashes when it is enabled.
|
|||
//See https://fogbugz.unity3d.com/f/cases/1187378/
|
|||
//[SerializeField]
|
|||
Shader m_ClassLabelingShader; |
|||
Material m_OverrideMaterial; |
|||
|
|||
public SemanticSegmentationCrossPipelinePass(Camera targetCamera, LabelingConfiguration labelingConfiguration) : base(targetCamera) |
|||
{ |
|||
this.m_LabelingConfiguration = labelingConfiguration; |
|||
} |
|||
|
|||
public override void Setup() |
|||
{ |
|||
base.Setup(); |
|||
m_ClassLabelingShader = Shader.Find(k_ShaderName); |
|||
var shaderVariantCollection = new ShaderVariantCollection(); |
|||
shaderVariantCollection.Add(new ShaderVariantCollection.ShaderVariant(m_ClassLabelingShader, PassType.ScriptableRenderPipeline)); |
|||
shaderVariantCollection.WarmUp(); |
|||
|
|||
m_OverrideMaterial = new Material(m_ClassLabelingShader); |
|||
} |
|||
|
|||
protected override void ExecutePass(ScriptableRenderContext renderContext, CommandBuffer cmd, Camera camera, CullingResults cullingResult) |
|||
{ |
|||
var renderList = CreateRendererListDesc(camera, cullingResult, "FirstPass", 0, m_OverrideMaterial, -1); |
|||
cmd.ClearRenderTarget(true, true, Color.clear); |
|||
DrawRendererList(renderContext, cmd, RendererList.Create(renderList)); |
|||
} |
|||
|
|||
public override void SetupMaterialProperties(MaterialPropertyBlock mpb, MeshRenderer meshRenderer, Labeling labeling, uint instanceId) |
|||
{ |
|||
var entry = new LabelEntry(); |
|||
foreach (var l in m_LabelingConfiguration.LabelEntries) |
|||
{ |
|||
if (labeling.labels.Contains(l.label)) |
|||
{ |
|||
entry = l; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
//Set the labeling ID so that it can be accessed in ClassSemanticSegmentationPass.shader
|
|||
mpb.SetInt(k_LabelingId, entry.value); |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using Unity.Entities; |
|||
|
|||
namespace UnityEngine.Perception.GroundTruth |
|||
{ |
|||
class SimulationManagementComponentSystem : ComponentSystem |
|||
{ |
|||
protected override void OnUpdate() |
|||
{ |
|||
SimulationManager.SimulationState?.Update(); |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using NUnit.Framework; |
|||
using Unity.Collections; |
|||
using Unity.Entities; |
|||
using UnityEngine; |
|||
using UnityEngine.Perception.GroundTruth; |
|||
using UnityEngine.TestTools; |
|||
|
|||
namespace GroundTruthTests |
|||
{ |
|||
[TestFixture] |
|||
public class BoundingBox2DTests : GroundTruthTestBase |
|||
{ |
|||
public class ProducesCorrectBoundingBoxesData |
|||
{ |
|||
public uint[] classCountsExpected; |
|||
public RenderedObjectInfo[] boundingBoxesExpected; |
|||
public uint[] data; |
|||
public BoundingBoxOrigin boundingBoxOrigin; |
|||
public int stride; |
|||
public string name; |
|||
public ProducesCorrectBoundingBoxesData(uint[] data, RenderedObjectInfo[] boundingBoxesExpected, uint[] classCountsExpected, int stride, BoundingBoxOrigin boundingBoxOrigin, string name) |
|||
{ |
|||
this.data = data; |
|||
this.boundingBoxesExpected = boundingBoxesExpected; |
|||
this.classCountsExpected = classCountsExpected; |
|||
this.stride = stride; |
|||
this.name = name; |
|||
this.boundingBoxOrigin = boundingBoxOrigin; |
|||
} |
|||
|
|||
public override string ToString() |
|||
{ |
|||
return name; |
|||
} |
|||
} |
|||
public static IEnumerable ProducesCorrectBoundingBoxesTestCases() |
|||
{ |
|||
yield return new ProducesCorrectBoundingBoxesData( |
|||
new uint[] |
|||
{ |
|||
1, 1, |
|||
1, 1 |
|||
}, new[] |
|||
{ |
|||
new RenderedObjectInfo() |
|||
{ |
|||
boundingBox = new Rect(0, 0, 2, 2), |
|||
instanceId = 1, |
|||
labelId = 1, |
|||
pixelCount = 4 |
|||
} |
|||
}, new uint[] |
|||
{ |
|||
1, |
|||
0 |
|||
}, |
|||
2, |
|||
BoundingBoxOrigin.BottomLeft, |
|||
"SimpleBox"); |
|||
yield return new ProducesCorrectBoundingBoxesData( |
|||
new uint[] |
|||
{ |
|||
1, 0, 2, |
|||
1, 0, 0 |
|||
}, new[] |
|||
{ |
|||
new RenderedObjectInfo() |
|||
{ |
|||
boundingBox = new Rect(0, 0, 1, 2), |
|||
instanceId = 1, |
|||
labelId = 1, |
|||
pixelCount = 2 |
|||
}, |
|||
new RenderedObjectInfo() |
|||
{ |
|||
boundingBox = new Rect(2, 0, 1, 1), |
|||
instanceId = 2, |
|||
labelId = 2, |
|||
pixelCount = 1 |
|||
} |
|||
}, new uint[] |
|||
{ |
|||
1, |
|||
1 |
|||
}, |
|||
3, |
|||
BoundingBoxOrigin.BottomLeft, |
|||
"WithGaps"); |
|||
yield return new ProducesCorrectBoundingBoxesData( |
|||
new uint[] |
|||
{ |
|||
1, 2, 1, |
|||
1, 2, 1 |
|||
}, new[] |
|||
{ |
|||
new RenderedObjectInfo() |
|||
{ |
|||
boundingBox = new Rect(0, 0, 3, 2), |
|||
instanceId = 1, |
|||
labelId = 1, |
|||
pixelCount = 4 |
|||
}, |
|||
new RenderedObjectInfo() |
|||
{ |
|||
boundingBox = new Rect(1, 0, 1, 2), |
|||
instanceId = 2, |
|||
labelId = 2, |
|||
pixelCount = 2 |
|||
} |
|||
}, new uint[] |
|||
{ |
|||
1, |
|||
1 |
|||
}, |
|||
3, |
|||
BoundingBoxOrigin.BottomLeft, |
|||
"Interleaved"); |
|||
yield return new ProducesCorrectBoundingBoxesData( |
|||
new uint[] |
|||
{ |
|||
0, 0, |
|||
0, 0, |
|||
0, 1 |
|||
}, new[] |
|||
{ |
|||
new RenderedObjectInfo() |
|||
{ |
|||
boundingBox = new Rect(1, 0, 1, 1), |
|||
instanceId = 1, |
|||
labelId = 1, |
|||
pixelCount = 1 |
|||
}, |
|||
}, new uint[] |
|||
{ |
|||
1, |
|||
0 |
|||
}, |
|||
2, |
|||
BoundingBoxOrigin.TopLeft, |
|||
"TopLeft"); |
|||
} |
|||
|
|||
[UnityTest] |
|||
public IEnumerator ProducesCorrectBoundingBoxes([ValueSource(nameof(ProducesCorrectBoundingBoxesTestCases))] ProducesCorrectBoundingBoxesData producesCorrectBoundingBoxesData) |
|||
{ |
|||
var label = "label"; |
|||
var label2 = "label2"; |
|||
var labelingConfiguration = ScriptableObject.CreateInstance<LabelingConfiguration>(); |
|||
|
|||
labelingConfiguration.LabelEntries = new List<LabelEntry> |
|||
{ |
|||
new LabelEntry |
|||
{ |
|||
id = 1, |
|||
label = label, |
|||
value = 500 |
|||
}, |
|||
new LabelEntry |
|||
{ |
|||
id = 2, |
|||
label = label2, |
|||
value = 500 |
|||
} |
|||
}; |
|||
|
|||
var renderedObjectInfoGenerator = new RenderedObjectInfoGenerator(labelingConfiguration); |
|||
var groundTruthLabelSetupSystem = World.DefaultGameObjectInjectionWorld.GetExistingSystem<GroundTruthLabelSetupSystem>(); |
|||
groundTruthLabelSetupSystem.Activate(renderedObjectInfoGenerator); |
|||
|
|||
//Put a plane in front of the camera
|
|||
AddTestObjectForCleanup(TestHelper.CreateLabeledPlane(.1f, label)); |
|||
AddTestObjectForCleanup(TestHelper.CreateLabeledPlane(.1f, label2)); |
|||
yield return null; |
|||
|
|||
var dataNativeArray = new NativeArray<uint>(producesCorrectBoundingBoxesData.data, Allocator.Persistent); |
|||
|
|||
renderedObjectInfoGenerator.Compute(dataNativeArray, producesCorrectBoundingBoxesData.stride, producesCorrectBoundingBoxesData.boundingBoxOrigin, out var boundingBoxes, out var classCounts, Allocator.Temp); |
|||
|
|||
CollectionAssert.AreEqual(producesCorrectBoundingBoxesData.boundingBoxesExpected, boundingBoxes.ToArray()); |
|||
CollectionAssert.AreEqual(producesCorrectBoundingBoxesData.classCountsExpected, classCounts.ToArray()); |
|||
|
|||
dataNativeArray.Dispose(); |
|||
boundingBoxes.Dispose(); |
|||
classCounts.Dispose(); |
|||
groundTruthLabelSetupSystem.Deactivate(renderedObjectInfoGenerator); |
|||
renderedObjectInfoGenerator.Dispose(); |
|||
} |
|||
} |
|||
} |
|
|||
%YAML 1.1 |
|||
%TAG !u! tag:unity3d.com,2011: |
|||
--- !u!1 &2608298934752318752 |
|||
GameObject: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
serializedVersion: 6 |
|||
m_Component: |
|||
- component: {fileID: 2608298934752318763} |
|||
- component: {fileID: 2608298934752318756} |
|||
- component: {fileID: 2608298934752318757} |
|||
- component: {fileID: 2608298934752318758} |
|||
- component: {fileID: 2608298934752318759} |
|||
m_Layer: 0 |
|||
m_Name: Main Camera |
|||
m_TagString: MainCamera |
|||
m_Icon: {fileID: 0} |
|||
m_NavMeshLayer: 0 |
|||
m_StaticEditorFlags: 0 |
|||
m_IsActive: 1 |
|||
--- !u!4 &2608298934752318763 |
|||
Transform: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 2608298934752318752} |
|||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} |
|||
m_LocalPosition: {x: 0, y: 1, z: -10} |
|||
m_LocalScale: {x: 1, y: 1, z: 1} |
|||
m_Children: [] |
|||
m_Father: {fileID: 0} |
|||
m_RootOrder: 0 |
|||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} |
|||
--- !u!20 &2608298934752318756 |
|||
Camera: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 2608298934752318752} |
|||
m_Enabled: 1 |
|||
serializedVersion: 2 |
|||
m_ClearFlags: 1 |
|||
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} |
|||
m_projectionMatrixMode: 1 |
|||
m_GateFitMode: 2 |
|||
m_FOVAxisMode: 0 |
|||
m_SensorSize: {x: 36, y: 24} |
|||
m_LensShift: {x: 0, y: 0} |
|||
m_FocalLength: 50 |
|||
m_NormalizedViewPortRect: |
|||
serializedVersion: 2 |
|||
x: 0 |
|||
y: 0 |
|||
width: 1 |
|||
height: 1 |
|||
near clip plane: 0.3 |
|||
far clip plane: 1000 |
|||
field of view: 60 |
|||
orthographic: 0 |
|||
orthographic size: 5 |
|||
m_Depth: -1 |
|||
m_CullingMask: |
|||
serializedVersion: 2 |
|||
m_Bits: 4294967295 |
|||
m_RenderingPath: -1 |
|||
m_TargetTexture: {fileID: 0} |
|||
m_TargetDisplay: 0 |
|||
m_TargetEye: 3 |
|||
m_HDR: 0 |
|||
m_AllowMSAA: 0 |
|||
m_AllowDynamicResolution: 0 |
|||
m_ForceIntoRT: 0 |
|||
m_OcclusionCulling: 1 |
|||
m_StereoConvergence: 10 |
|||
m_StereoSeparation: 0.022 |
|||
--- !u!81 &2608298934752318757 |
|||
AudioListener: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 2608298934752318752} |
|||
m_Enabled: 1 |
|||
--- !u!114 &2608298934752318758 |
|||
MonoBehaviour: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 2608298934752318752} |
|||
m_Enabled: 1 |
|||
m_EditorHideFlags: 0 |
|||
m_Script: {fileID: 11500000, guid: 23c1ce4fb46143f46bc5cb5224c934f6, type: 3} |
|||
m_Name: |
|||
m_EditorClassIdentifier: |
|||
m_Version: 6 |
|||
m_ObsoleteRenderingPath: 0 |
|||
m_ObsoleteFrameSettings: |
|||
overrides: 0 |
|||
enableShadow: 0 |
|||
enableContactShadows: 0 |
|||
enableShadowMask: 0 |
|||
enableSSR: 0 |
|||
enableSSAO: 0 |
|||
enableSubsurfaceScattering: 0 |
|||
enableTransmission: 0 |
|||
enableAtmosphericScattering: 0 |
|||
enableVolumetrics: 0 |
|||
enableReprojectionForVolumetrics: 0 |
|||
enableLightLayers: 0 |
|||
enableExposureControl: 1 |
|||
diffuseGlobalDimmer: 0 |
|||
specularGlobalDimmer: 0 |
|||
shaderLitMode: 0 |
|||
enableDepthPrepassWithDeferredRendering: 0 |
|||
enableTransparentPrepass: 0 |
|||
enableMotionVectors: 0 |
|||
enableObjectMotionVectors: 0 |
|||
enableDecals: 0 |
|||
enableRoughRefraction: 0 |
|||
enableTransparentPostpass: 0 |
|||
enableDistortion: 0 |
|||
enablePostprocess: 0 |
|||
enableOpaqueObjects: 0 |
|||
enableTransparentObjects: 0 |
|||
enableRealtimePlanarReflection: 0 |
|||
enableMSAA: 0 |
|||
enableAsyncCompute: 0 |
|||
runLightListAsync: 0 |
|||
runSSRAsync: 0 |
|||
runSSAOAsync: 0 |
|||
runContactShadowsAsync: 0 |
|||
runVolumeVoxelizationAsync: 0 |
|||
lightLoopSettings: |
|||
overrides: 0 |
|||
enableDeferredTileAndCluster: 0 |
|||
enableComputeLightEvaluation: 0 |
|||
enableComputeLightVariants: 0 |
|||
enableComputeMaterialVariants: 0 |
|||
enableFptlForForwardOpaque: 0 |
|||
enableBigTilePrepass: 0 |
|||
isFptlEnabled: 0 |
|||
clearColorMode: 0 |
|||
backgroundColorHDR: {r: 0.025, g: 0.07, b: 0.19, a: 0} |
|||
clearDepth: 1 |
|||
volumeLayerMask: |
|||
serializedVersion: 2 |
|||
m_Bits: 1 |
|||
volumeAnchorOverride: {fileID: 0} |
|||
antialiasing: 0 |
|||
SMAAQuality: 2 |
|||
dithering: 0 |
|||
stopNaNs: 0 |
|||
physicalParameters: |
|||
m_Iso: 200 |
|||
m_ShutterSpeed: 0.005 |
|||
m_Aperture: 16 |
|||
m_BladeCount: 5 |
|||
m_Curvature: {x: 2, y: 11} |
|||
m_BarrelClipping: 0.25 |
|||
m_Anamorphism: 0 |
|||
flipYMode: 0 |
|||
fullscreenPassthrough: 0 |
|||
allowDynamicResolution: 0 |
|||
customRenderingSettings: 0 |
|||
invertFaceCulling: 0 |
|||
probeLayerMask: |
|||
serializedVersion: 2 |
|||
m_Bits: 4294967295 |
|||
m_RenderingPathCustomFrameSettings: |
|||
bitDatas: |
|||
data1: 69730941533981 |
|||
data2: 4539628424926265344 |
|||
lodBias: 1 |
|||
lodBiasMode: 0 |
|||
lodBiasQualityLevel: 0 |
|||
maximumLODLevel: 0 |
|||
maximumLODLevelMode: 0 |
|||
maximumLODLevelQualityLevel: 0 |
|||
materialQuality: 0 |
|||
renderingPathCustomFrameSettingsOverrideMask: |
|||
mask: |
|||
data1: 0 |
|||
data2: 0 |
|||
defaultFrameSettings: 0 |
|||
--- !u!114 &2608298934752318759 |
|||
MonoBehaviour: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 2608298934752318752} |
|||
m_Enabled: 1 |
|||
m_EditorHideFlags: 0 |
|||
m_Script: {fileID: 11500000, guid: 26d6499a6bd256e47b859377446493a1, type: 3} |
|||
m_Name: |
|||
m_EditorClassIdentifier: |
|||
isGlobal: 1 |
|||
customPasses: |
|||
- id: 0 |
|||
- id: 1 |
|||
- id: 2 |
|||
injectionPoint: 0 |
|||
references: |
|||
version: 1 |
|||
00000000: |
|||
type: {class: InstanceSegmentationPass, ns: UnityEngine.SimViz.Sensors, asm: Unity.SimViz.GroundTruth} |
|||
data: |
|||
name: Custom Pass |
|||
enabled: 1 |
|||
targetColorBuffer: 1 |
|||
targetDepthBuffer: 1 |
|||
clearFlags: 0 |
|||
passFoldout: 0 |
|||
targetCamera: {fileID: 0} |
|||
layerMask: |
|||
serializedVersion: 2 |
|||
m_Bits: 4294967295 |
|||
targetTexture: {fileID: 8400000, guid: 6519b622da084c14ba19d257dbc156d8, type: 2} |
|||
reassignIds: 0 |
|||
idStart: 1 |
|||
idStep: 1 |
|||
00000001: |
|||
type: {class: SemanticSegmentationPass, ns: UnityEngine.SimViz.Sensors, asm: Unity.SimViz.GroundTruth} |
|||
data: |
|||
name: Custom Pass |
|||
enabled: 1 |
|||
targetColorBuffer: 1 |
|||
targetDepthBuffer: 1 |
|||
clearFlags: 0 |
|||
passFoldout: 0 |
|||
targetCamera: {fileID: 0} |
|||
targetTexture: {fileID: 8400000, guid: 7498338473af7ff4fbbfb55598b6d24e, type: 2} |
|||
labelingConfiguration: {fileID: 11400000, guid: 16a81d3f01f4f4345b113509e93fdab6, |
|||
type: 2} |
|||
00000002: |
|||
type: {class: LabelHistogramPass, ns: UnityEngine.SimViz.Sensors, asm: Unity.SimViz.GroundTruth} |
|||
data: |
|||
name: Custom Pass |
|||
enabled: 1 |
|||
targetColorBuffer: 1 |
|||
targetDepthBuffer: 1 |
|||
clearFlags: 0 |
|||
passFoldout: 0 |
|||
targetCamera: {fileID: 0} |
|||
SegmentationTexture: {fileID: 8400000, guid: 6519b622da084c14ba19d257dbc156d8, |
|||
type: 2} |
|||
LabelingConfiguration: {fileID: 11400000, guid: 16a81d3f01f4f4345b113509e93fdab6, |
|||
type: 2} |
|
|||
fileFormatVersion: 2 |
|||
guid: b423c67e7ddf25444b8b047b1e9c7735 |
|||
PrefabImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using NUnit.Framework; |
|||
using Unity.Collections; |
|||
#if UNITY_EDITOR
|
|||
#endif
|
|||
using UnityEngine; |
|||
using UnityEngine.Perception.GroundTruth; |
|||
using UnityEngine.TestTools; |
|||
using Object = UnityEngine.Object; |
|||
#if HDRP_PRESENT
|
|||
using UnityEngine.Experimental.Rendering; |
|||
using UnityEngine.Rendering.HighDefinition; |
|||
#endif
|
|||
|
|||
namespace GroundTruthTests |
|||
{ |
|||
//Graphics issues with OpenGL Linux Editor. https://jira.unity3d.com/browse/AISV-422
|
|||
[UnityPlatform(exclude = new[] {RuntimePlatform.LinuxEditor, RuntimePlatform.LinuxPlayer})] |
|||
[TestFixture] |
|||
class ObjectCountTests : GroundTruthTestBase |
|||
{ |
|||
[UnityTest] |
|||
public IEnumerator ProducesCorrectValuesWithChangingObjects() |
|||
{ |
|||
var label = "label"; |
|||
var labelingConfiguration = ScriptableObject.CreateInstance<LabelingConfiguration>(); |
|||
|
|||
labelingConfiguration.LabelEntries = new List<LabelEntry> |
|||
{ |
|||
new LabelEntry |
|||
{ |
|||
id = 1, |
|||
label = label, |
|||
value = 500 |
|||
} |
|||
}; |
|||
|
|||
var receivedResults = new List<(uint[] counts, LabelEntry[] labels, int frameCount)>(); |
|||
|
|||
var cameraObject = SetupCamera(labelingConfiguration, (counts, labels, frameCount) => |
|||
{ |
|||
receivedResults.Add((counts.ToArray(), labels.ToArray(), frameCount)); |
|||
}); |
|||
AddTestObjectForCleanup(cameraObject); |
|||
|
|||
//TestHelper.LoadAndStartRenderDocCapture(out EditorWindow gameView);
|
|||
var startFrameCount = Time.frameCount; |
|||
var expectedFramesAndCounts = new Dictionary<int, int>() |
|||
{ |
|||
{Time.frameCount , 0}, |
|||
{startFrameCount + 1, 1}, |
|||
{startFrameCount + 2, 1}, |
|||
{startFrameCount + 3, 2}, |
|||
{startFrameCount + 4, 1}, |
|||
{startFrameCount + 5, 1}, |
|||
}; |
|||
|
|||
yield return null; |
|||
//Put a plane in front of the camera
|
|||
var planeObject = TestHelper.CreateLabeledPlane(.1f, label); |
|||
yield return null; |
|||
Object.DestroyImmediate(planeObject); |
|||
planeObject = TestHelper.CreateLabeledPlane(.1f, label); |
|||
yield return null; |
|||
var planeObject2 = TestHelper.CreateLabeledPlane(.1f, label); |
|||
planeObject2.transform.Translate(.5f, 0, 0); |
|||
|
|||
yield return null; |
|||
Object.DestroyImmediate(planeObject); |
|||
yield return null; |
|||
yield return null; |
|||
|
|||
Object.DestroyImmediate(planeObject2); |
|||
#if HDRP_PRESENT
|
|||
//TODO: Remove this when DestroyImmediate properly calls Cleanup on the pass
|
|||
var labelHistogramPass = (ObjectCountPass)cameraObject.GetComponent<CustomPassVolume>().customPasses.First(p => p is ObjectCountPass); |
|||
labelHistogramPass.WaitForAllRequests(); |
|||
#endif
|
|||
//destroy the object to force all pending segmented image readbacks to finish and events to be fired.
|
|||
DestroyTestObject(cameraObject); |
|||
|
|||
//RenderDoc.EndCaptureRenderDoc(gameView);
|
|||
|
|||
foreach (var result in receivedResults) |
|||
{ |
|||
Assert.AreEqual(1, result.counts.Length); |
|||
Assert.AreEqual(1, result.labels.Length); |
|||
Assert.Contains(result.frameCount, expectedFramesAndCounts.Keys, "Received event with unexpected frameCount."); |
|||
|
|||
var expectedCount = expectedFramesAndCounts[result.frameCount]; |
|||
|
|||
var errorString = $"Wrong count in frame {result.frameCount - startFrameCount}. {string.Join(", ", receivedResults.Select(r => $"count: {r.counts[0]}"))}"; |
|||
Assert.AreEqual(expectedCount, result.counts[0], errorString); |
|||
|
|||
expectedFramesAndCounts.Remove(result.frameCount); |
|||
} |
|||
|
|||
CollectionAssert.IsEmpty(expectedFramesAndCounts); |
|||
} |
|||
|
|||
static GameObject SetupCamera(LabelingConfiguration labelingConfiguration, |
|||
Action<NativeSlice<uint>, IReadOnlyList<LabelEntry>, int> onClassCountsReceived) |
|||
{ |
|||
var cameraObject = new GameObject(); |
|||
cameraObject.SetActive(false); |
|||
var camera = cameraObject.AddComponent<Camera>(); |
|||
camera.orthographic = true; |
|||
camera.orthographicSize = 1; |
|||
|
|||
#if HDRP_PRESENT
|
|||
cameraObject.AddComponent<HDAdditionalCameraData>(); |
|||
var customPassVolume = cameraObject.AddComponent<CustomPassVolume>(); |
|||
customPassVolume.isGlobal = true; |
|||
var rt = new RenderTexture(128, 128, 1, GraphicsFormat.R8G8B8A8_UNorm); |
|||
rt.Create(); |
|||
var instanceSegmentationPass = new InstanceSegmentationPass() |
|||
{ |
|||
targetCamera = camera, |
|||
targetTexture = rt |
|||
}; |
|||
instanceSegmentationPass.name = nameof(instanceSegmentationPass); |
|||
instanceSegmentationPass.EnsureInit(); |
|||
customPassVolume.customPasses.Add(instanceSegmentationPass); |
|||
var objectCountPass = new ObjectCountPass(camera); |
|||
objectCountPass.SegmentationTexture = rt; |
|||
objectCountPass.LabelingConfiguration = labelingConfiguration; |
|||
objectCountPass.name = nameof(objectCountPass); |
|||
customPassVolume.customPasses.Add(objectCountPass); |
|||
|
|||
objectCountPass.ClassCountsReceived += onClassCountsReceived; |
|||
#endif
|
|||
#if URP_PRESENT
|
|||
var perceptionCamera = cameraObject.AddComponent<PerceptionCamera>(); |
|||
perceptionCamera.LabelingConfiguration = labelingConfiguration; |
|||
perceptionCamera.captureRgbImages = false; |
|||
perceptionCamera.produceBoundingBoxAnnotations = false; |
|||
perceptionCamera.produceObjectCountAnnotations = true; |
|||
perceptionCamera.classCountsReceived += onClassCountsReceived; |
|||
#endif
|
|||
cameraObject.SetActive(true); |
|||
return cameraObject; |
|||
} |
|||
} |
|||
} |
部分文件因为文件数量过多而无法显示
撰写
预览
正在加载...
取消
保存
Reference in new issue