浏览代码

find absolute path to pyrception-utils

/pyrception-integration
leopoldo-zugasti 3 年前
当前提交
6d7bdf5a
共有 33 个文件被更改,包括 1382 次插入1 次删除
  1. 4
      com.unity.perception/Editor/Pyrception/PyrceptionInstaller.cs
  2. 8
      com.unity.perception/Editor/Pyrception/pyrception-utils.meta
  3. 2
      com.unity.perception/Editor/Pyrception/pyrception-utils/.coveragerc
  4. 12
      com.unity.perception/Editor/Pyrception/pyrception-utils/.flake8
  5. 153
      com.unity.perception/Editor/Pyrception/pyrception-utils/.gitignore
  6. 29
      com.unity.perception/Editor/Pyrception/pyrception-utils/.pre-commit-config.yaml
  7. 4
      com.unity.perception/Editor/Pyrception/pyrception-utils/.pypirc
  8. 21
      com.unity.perception/Editor/Pyrception/pyrception-utils/.yamato/publish.yml
  9. 26
      com.unity.perception/Editor/Pyrception/pyrception-utils/.yamato/test.yml
  10. 60
      com.unity.perception/Editor/Pyrception/pyrception-utils/README.md
  11. 7
      com.unity.perception/Editor/Pyrception/pyrception-utils/README.md.meta
  12. 8
      com.unity.perception/Editor/Pyrception/pyrception-utils/disable.meta
  13. 8
      com.unity.perception/Editor/Pyrception/pyrception-utils/docs.meta
  14. 476
      com.unity.perception/Editor/Pyrception/pyrception-utils/docs/pyrception-utils.md
  15. 7
      com.unity.perception/Editor/Pyrception/pyrception-utils/docs/pyrception-utils.md.meta
  16. 8
      com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils.meta
  17. 8
      com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/__init__.py
  18. 7
      com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/__init__.py.meta
  19. 8
      com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/__pycache__.meta
  20. 48
      com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/cli.py
  21. 7
      com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/cli.py.meta
  22. 143
      com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/preview.py
  23. 7
      com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/preview.py.meta
  24. 271
      com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/pyrception.py
  25. 7
      com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/pyrception.py.meta
  26. 12
      com.unity.perception/Editor/Pyrception/pyrception-utils/requirements.txt
  27. 7
      com.unity.perception/Editor/Pyrception/pyrception-utils/requirements.txt.meta
  28. 18
      com.unity.perception/Editor/Pyrception/pyrception-utils/setup.py
  29. 7
      com.unity.perception/Editor/Pyrception/pyrception-utils/setup.py.meta

4
com.unity.perception/Editor/Pyrception/PyrceptionInstaller.cs


using System.Diagnostics;
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.Perception.GroundTruth;

static void SetupPyrception()
{
string path = Application.dataPath.Replace("/Assets", "").Replace("/", "\\");
string pyrceptionPath = "C:\\Users\\leopoldo.zugasti\\Desktop\\DatasetInsights\\Pyrception\\pyrception-utils-dev";
string pyrceptionPath = Path.GetFullPath("Packages/com.unity.perception/Editor/Pyrception/pyrception-utils");
UnityEngine.Debug.Log(pyrceptionPath);
string command =
$"pip install virtualenv && " +
$"cd {path} && " +

8
com.unity.perception/Editor/Pyrception/pyrception-utils.meta


fileFormatVersion: 2
guid: 349820744c44b0044b9c17fd7573e3ef
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

2
com.unity.perception/Editor/Pyrception/pyrception-utils/.coveragerc


[run]
source = pyrception_utils

12
com.unity.perception/Editor/Pyrception/pyrception-utils/.flake8


[flake8]
max-line-length = 100
ignore =
E133,
E203,
W503,
W504,
W605,
F541
exclude =
.git,
__pycache__,

153
com.unity.perception/Editor/Pyrception/pyrception-utils/.gitignore


# Project
scratch.py
# pytest-html
*.html
# test results folder
test-results/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# Mac
.DS_Store
# Jetbrains
.idea
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/

29
com.unity.perception/Editor/Pyrception/pyrception-utils/.pre-commit-config.yaml


# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
exclude: >
(?x)^(
.*_pb2.py|
.*_pb2_grpc.py
)$
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- id: check-merge-conflict
- repo: https://github.com/psf/black
rev: 20.8b1
hooks:
- id: black
- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.3
hooks:
- id: flake8
- repo: https://github.com/timothycrosley/isort
rev: 4.3.21
hooks:
- id: isort
args: ["-l", "88", "-m", "3", "-tc"]

4
com.unity.perception/Editor/Pyrception/pyrception-utils/.pypirc


[distutils]
index-servers = local
[local]
repository: https://artifactory-upload.prd.it.unity3d.com/artifactory/api/pypi/unity-pypi-local

21
com.unity.perception/Editor/Pyrception/pyrception-utils/.yamato/publish.yml


publish-wheel:
name: "Publish Python Wheels to Local PyPi"
agent:
type: Unity::VM
image: cds-ops/ubuntu-18.04-python3.8:stable
flavor: b1.large
commands:
- echo -n "username:" >> .pypirc
- echo -n " " >> .pypirc
- echo $IT_ARTIFACTORY_USER >> .pypirc
- echo -n "password:" >> .pypirc
- echo -n " " >> .pypirc
- echo $IT_ARTIFACTORY_PASSWORD >> .pypirc
- sudo cp .pypirc $HOME
- python3 setup.py sdist bdist_wheel upload -r local
dependencies:
- .yamato/test.yml#run-tests
triggers:
tags:
only:
- /v\d+\.\d+\.\d+(\.\d+)?/

26
com.unity.perception/Editor/Pyrception/pyrception-utils/.yamato/test.yml


run-tests:
name: "Per Commit pytests"
agent:
type: Unity::VM
image: cds-ops/ubuntu-18.04-python3.8:stable
flavor: b1.large
variables:
GOOGLE_APPLICATION_CREDENTIALS: gcloud-key.json
commands:
- mkdir test-results
- mkdir test-results/coverage
- mkdir test-results/pytest
- echo $GCR_CRED_JSON > gcloud-key.json
# The regular pip3 command is linked to Python 3.6 even though the default Python version for
# this VM is 3.8 *shrug*
- python3.8 -m pip install -r requirements.txt --index-url=https://artifactory.prd.it.unity3d.com/artifactory/api/pypi/pypi/simple
- /home/bokken/.local/bin/coverage run -m pytest --html=test-results/pytest/report.html --self-contained-html
- /home/bokken/.local/bin/coverage html --dir=test-results/coverage --title=pyrception-utils
triggers:
branches:
only:
- "/.*/"
artifacts:
logs:
paths:
- "test-results/**/*"

60
com.unity.perception/Editor/Pyrception/pyrception-utils/README.md


# Pyrception Utils
Pyrception Utils: A toolkit for managing [Unity Perception SDK datasets](https://github.com/Unity-Technologies/com.unity.perception).
[API Reference](docs/pyrception-utils.md)
## Dependencies
* python >= 3.7
* python virtual environment (optional but recommended)
## Installation
```bash
> git clone git@github.cds.internal.unity3d.com:unity/pyrception-utils.git
> cd pyrception-utils
> pip install -e .
```
## Dataset Preview Tool
The pyrception-utils package includes a perception dataset preview cli tool built in streamlit. You can use this tool as follows:
```bash
> pyrception-utils preview --data=<path_to_a_perception_dataset_enclosing_folder>
```
Here, <path_to_a_perception_dataset_enclosing_folder> is the path to the folder that contains one or more perception dataset folders, not
the path to a dataset folder. For example, on a mac, this would be:
```bash
> pyrception-utils preview --data=/Users/<username>/Library/Application\ Support/DefaultCompany/<ProjectName>
```
where <username> is your mac username and <ProjectName> is the Unity project name that uses the perception SDK to generate the
data.
## PyrceptionDataset
The *PyrceptionDataset* class is a simple iterator that can be used to serialize data generated from the perception SDK and used
in other frameworks such as PyTorch or Tensorflow. Checkout it out [here](pyrception_utils/pyrception.py).
## Developers
To install the pre commit hooks run
```bash
> pip install pre-commit
> pre-commit install
```
To run the pre-commit checks manually
```bash
> pre-commit run --all-files
```
# Converting to public repository
Any and all Unity software of any description (including components) (1) whose source is to be made available other than under a Unity source code license or (2) in respect of which a public announcement is to be made concerning its inner workings, may be licensed and released only upon the prior approval of Legal.
The process for that is to access, complete, and submit this [FORM](https://docs.google.com/forms/d/e/1FAIpQLSe3H6PARLPIkWVjdB_zMvuIuIVtrqNiGlEt1yshkMCmCMirvA/viewform).

7
com.unity.perception/Editor/Pyrception/pyrception-utils/README.md.meta


fileFormatVersion: 2
guid: 963368447d0e8014b9db204f1987a505
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
com.unity.perception/Editor/Pyrception/pyrception-utils/disable.meta


fileFormatVersion: 2
guid: b67d095df9c6e7b4cb24a47a30dc91cf
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
com.unity.perception/Editor/Pyrception/pyrception-utils/docs.meta


fileFormatVersion: 2
guid: a13a148b221bf6f41b34d561b6d2ab0b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

476
com.unity.perception/Editor/Pyrception/pyrception-utils/docs/pyrception-utils.md


# Table of Contents
* [pyrception\_utils](#pyrception_utils)
* [pyrception\_utils.cli](#pyrception_utils.cli)
* [preview](#pyrception_utils.cli.preview)
* [pyrception\_utils.preview](#pyrception_utils.preview)
* [list\_datasets](#pyrception_utils.preview.list_datasets)
* [frame\_selector\_ui](#pyrception_utils.preview.frame_selector_ui)
* [draw\_image\_with\_boxes](#pyrception_utils.preview.draw_image_with_boxes)
* [load\_perception\_dataset](#pyrception_utils.preview.load_perception_dataset)
* [preview\_dataset](#pyrception_utils.preview.preview_dataset)
* [preview\_app](#pyrception_utils.preview.preview_app)
* [pyrception\_utils.pyrception](#pyrception_utils.pyrception)
* [FileType](#pyrception_utils.pyrception.FileType)
* [glob](#pyrception_utils.pyrception.glob)
* [file\_number](#pyrception_utils.pyrception.file_number)
* [glob\_list](#pyrception_utils.pyrception.glob_list)
* [load\_json](#pyrception_utils.pyrception.load_json)
* [PyrceptionDatasetMetadata](#pyrception_utils.pyrception.PyrceptionDatasetMetadata)
* [\_\_init\_\_](#pyrception_utils.pyrception.PyrceptionDatasetMetadata.__init__)
* [PyrceptionDataset](#pyrception_utils.pyrception.PyrceptionDataset)
* [\_\_init\_\_](#pyrception_utils.pyrception.PyrceptionDataset.__init__)
* [\_\_getitem\_\_](#pyrception_utils.pyrception.PyrceptionDataset.__getitem__)
* [\_\_len\_\_](#pyrception_utils.pyrception.PyrceptionDataset.__len__)
* [pyrception\_utils.pyrception\_gcs](#pyrception_utils.pyrception_gcs)
* [FileType](#pyrception_utils.pyrception_gcs.FileType)
* [glob](#pyrception_utils.pyrception_gcs.glob)
* [glob\_list](#pyrception_utils.pyrception_gcs.glob_list)
* [load\_json](#pyrception_utils.pyrception_gcs.load_json)
* [PyrceptionGCSDataset](#pyrception_utils.pyrception_gcs.PyrceptionGCSDataset)
* [\_\_init\_\_](#pyrception_utils.pyrception_gcs.PyrceptionGCSDataset.__init__)
* [\_\_getitem\_\_](#pyrception_utils.pyrception_gcs.PyrceptionGCSDataset.__getitem__)
* [\_\_len\_\_](#pyrception_utils.pyrception_gcs.PyrceptionGCSDataset.__len__)
<a name="pyrception_utils"></a>
# pyrception\_utils
<a name="pyrception_utils.cli"></a>
# pyrception\_utils.cli
<a name="pyrception_utils.cli.preview"></a>
#### preview
```python
@subcommand(
[argument("--data", type=str, help="The path to the main perception data folder.")]
)
preview(args)
```
Previews the dataset in a streamlit app.
<a name="pyrception_utils.preview"></a>
# pyrception\_utils.preview
<a name="pyrception_utils.preview.list_datasets"></a>
#### list\_datasets
```python
list_datasets(path) -> List
```
Lists the datasets in a diretory.
**Arguments**:
- `path`: path to a directory that contains dataset folders
:type str:
**Returns**:
A list of dataset directories.
:rtype: List
<a name="pyrception_utils.preview.frame_selector_ui"></a>
#### frame\_selector\_ui
```python
frame_selector_ui(dataset: PyrceptionDataset) -> int
```
Frame selector streamlist widget to select which frame in the dataset to display
**Arguments**:
- `dataset`: the PyrceptionDataset
:type PyrceptionDataset:
**Returns**:
The image index
:rtype: int
<a name="pyrception_utils.preview.draw_image_with_boxes"></a>
#### draw\_image\_with\_boxes
```python
draw_image_with_boxes(image: Image, classes: Dict, labels: List, boxes: List[List], colors: Dict, header: str, description: str)
```
Draws an image in streamlit with labels and bounding boxes.
**Arguments**:
- `image`: the PIL image
:type PIL:
- `classes`: the class dictionary
:type Dict:
- `labels`: list of integer object labels for the frame
:type List:
- `boxes`: List of bounding boxes (as a List of coordinates) for the frame
:type List[List]:
- `colors`: class colors
:type Dict:
- `header`: Image header
:type str:
- `description`: Image description
:type str:
<a name="pyrception_utils.preview.load_perception_dataset"></a>
#### load\_perception\_dataset
```python
@st.cache(show_spinner=True, allow_output_mutation=True)
load_perception_dataset(path: str) -> Tuple
```
Loads the perception dataset in the cache and caches the random bounding box color scheme.
**Arguments**:
- `path`: Dataset path
:type str:
**Returns**:
A tuple with the colors and PyrceptionDataset object as (colors, dataset)
:rtype: Tuple
<a name="pyrception_utils.preview.preview_dataset"></a>
#### preview\_dataset
```python
preview_dataset(base_dataset_dir: str)
```
Adds streamlit components to the app to construct the dataset preview.
**Arguments**:
- `base_dataset_dir`: The directory that contains the perceptions datasets.
:type str:
<a name="pyrception_utils.preview.preview_app"></a>
#### preview\_app
```python
preview_app(args)
```
Starts the dataset preview app.
**Arguments**:
- `args`: Arguments for the app, such as dataset
:type args: Namespace
<a name="pyrception_utils.pyrception"></a>
# pyrception\_utils.pyrception
<a name="pyrception_utils.pyrception.FileType"></a>
## FileType Objects
```python
class FileType(Enum)
```
Enumerator for file types in the perception dataset. Based on
<a name="pyrception_utils.pyrception.glob"></a>
#### glob
```python
glob(data_root: str, pattern: str) -> Iterator[str]
```
Find all files in a directory, data_dir, that match the pattern.
**Arguments**:
- `data_root`: The path to the directory that contains the dataset.
:type str:
- `pattern`: The file pattern to match.
:type str:
**Returns**:
Returns an string iterator containing the paths to the matching files.
:rtype: Iterator[str]
<a name="pyrception_utils.pyrception.file_number"></a>
#### file\_number
```python
file_number(filename)
```
Key function to sort glob list.
**Arguments**:
- `filename`: POSIX path
:type filename:
**Returns**:
:rtype:
<a name="pyrception_utils.pyrception.glob_list"></a>
#### glob\_list
```python
glob_list(data_root: str, pattern: str) -> List
```
Find all files in a directory, data_dir, that match the pattern.
**Arguments**:
- `data_root`: The path to the directory that contains the dataset.
:type str:
- `pattern`: The file pattern to match.
:type str:
**Returns**:
Returns an string iterator containing the paths to the matching files.
:rtype: Iterator[str]
<a name="pyrception_utils.pyrception.load_json"></a>
#### load\_json
```python
load_json(file: str, key: Union[str, List]) -> Dict
```
Loads top level records from json file given key or list of keys.
**Arguments**:
- `file`: The json filename.
:type str:
- `key`: The top-level key or list of keys to load.
:type Union[str, List]:
**Returns**:
Returns a dictionary representing the json record
:rtype: Dict
<a name="pyrception_utils.pyrception.PyrceptionDatasetMetadata"></a>
## PyrceptionDatasetMetadata Objects
```python
class PyrceptionDatasetMetadata()
```
<a name="pyrception_utils.pyrception.PyrceptionDatasetMetadata.__init__"></a>
#### \_\_init\_\_
```python
| __init__(data_dir: str = None)
```
Creates a PyrceptionDataset object that can be used to iterate through the perception
dataset.
**Arguments**:
- `data_dir`: The path to the perception dataset.
:type str:
<a name="pyrception_utils.pyrception.PyrceptionDataset"></a>
## PyrceptionDataset Objects
```python
class PyrceptionDataset()
```
Pyrception class for reading and visualizing annotations generated by the perception SDK.
<a name="pyrception_utils.pyrception.PyrceptionDataset.__init__"></a>
#### \_\_init\_\_
```python
| __init__(metadata: PyrceptionDatasetMetadata = None, data_dir: str = None)
```
Creates a PyrceptionDataset object that can be used to iterate through the perception
dataset.
**Arguments**:
- `data_dir`: The path to the perception dataset.
:type str:
<a name="pyrception_utils.pyrception.PyrceptionDataset.__getitem__"></a>
#### \_\_getitem\_\_
```python
| __getitem__(index: int) -> Tuple
```
Iterator to get one frame at a time based on index.
**Arguments**:
- `index`: the index of the frame to retrieve
:type int:
**Returns**:
Returns a tuple containing the image and target metadata as (image, target)
:rtype: Tuple
<a name="pyrception_utils.pyrception.PyrceptionDataset.__len__"></a>
#### \_\_len\_\_
```python
| __len__() -> int
```
Returns the length of the perception dataset.
**Returns**:
Length of the dataset.
:rtype: int
<a name="pyrception_utils.pyrception_gcs"></a>
# pyrception\_utils.pyrception\_gcs
<a name="pyrception_utils.pyrception_gcs.FileType"></a>
## FileType Objects
```python
class FileType(Enum)
```
Enumerator for file types in the perception dataset. Based on
<a name="pyrception_utils.pyrception_gcs.glob"></a>
#### glob
```python
glob(data_root: str, pattern: str) -> Iterator[str]
```
Find all files in a directory, data_dir, that match the pattern.
**Arguments**:
- `data_root`: The path to the directory that contains the dataset.
:type str:
- `pattern`: The file pattern to match.
:type str:
**Returns**:
Returns an string iterator containing the paths to the matching files.
:rtype: Iterator[str]
<a name="pyrception_utils.pyrception_gcs.glob_list"></a>
#### glob\_list
```python
glob_list(fs: GCSFileSystem, data_root: str, pattern: str) -> List
```
Find all files in a directory, data_dir, that match the pattern.
**Arguments**:
- `fs`: the GCSFileSystem object
:type GCSFileSystem
- `data_root`: The path to the directory that contains the dataset.
:type str:
- `pattern`: The file pattern to match.
:type str:
**Returns**:
Returns an string iterator containing the paths to the matching files.
:rtype: Iterator[str]
<a name="pyrception_utils.pyrception_gcs.load_json"></a>
#### load\_json
```python
load_json(fs: GCSFileSystem, file: str, key: Union[str, List]) -> Dict
```
Loads top level records from json file given key or list of keys.
**Arguments**:
- `fs`: the GCSFileSystem object
:type GCSFileSystem
- `file`: The json filename.
:type str:
- `key`: The top-level key or list of keys to load.
:type Union[str, List]:
**Returns**:
Returns a dictionary representing the json record
:rtype: Dict
<a name="pyrception_utils.pyrception_gcs.PyrceptionGCSDataset"></a>
## PyrceptionGCSDataset Objects
```python
class PyrceptionGCSDataset()
```
Pyrception class for reading and visualizing annotations generated by the perception SDK.
<a name="pyrception_utils.pyrception_gcs.PyrceptionGCSDataset.__init__"></a>
#### \_\_init\_\_
```python
| __init__(project_id: str = None, dataset_bucket: str = None, dataset_folder: str = None)
```
Creates a PyrceptionDataset object that can be used to iterate through the perception
dataset.
**Arguments**:
- `dataset_bucket`: The path to the perception dataset.
:type str:
<a name="pyrception_utils.pyrception_gcs.PyrceptionGCSDataset.__getitem__"></a>
#### \_\_getitem\_\_
```python
| __getitem__(index: int) -> Tuple
```
Iterator to get one frame at a time based on index.
**Arguments**:
- `index`: the index of the frame to retrieve
:type int:
**Returns**:
Returns a tuple containing the image and target metadata as (image, target)
:rtype: Tuple
<a name="pyrception_utils.pyrception_gcs.PyrceptionGCSDataset.__len__"></a>
#### \_\_len\_\_
```python
| __len__() -> int
```
Returns the length of the perception dataset.
**Returns**:
Length of the dataset.
:rtype: int

7
com.unity.perception/Editor/Pyrception/pyrception-utils/docs/pyrception-utils.md.meta


fileFormatVersion: 2
guid: 6181ab488b9873a408a125ee551d92e1
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils.meta


fileFormatVersion: 2
guid: ae2ee9cedabe0224db1e741ec4c91044
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/__init__.py


from .pyrception import PyrceptionDataset, PyrceptionDatasetMetadata
#from .pyrception_gcs import PyrceptionGCSDataset
__all__ = [
"PyrceptionDataset",
"PyrceptionDatasetMetadata",
#"PyrceptionGCSDataset",
]

7
com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/__init__.py.meta


fileFormatVersion: 2
guid: ca81f7cb917bd604098c97ccf203e2b2
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/__pycache__.meta


fileFormatVersion: 2
guid: 64992e7744bce2f4c93a348e9dc64429
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

48
com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/cli.py


import argparse
import os
import streamlit.bootstrap
cli = argparse.ArgumentParser()
subparsers = cli.add_subparsers(dest="subcommand")
def argument(*name_or_flags, **kwargs):
return ([*name_or_flags], kwargs)
def subcommand(args=[], parent=subparsers):
def decorator(func):
parser = parent.add_parser(func.__name__, description=func.__doc__)
for arg in args:
parser.add_argument(*arg[0], **arg[1])
parser.set_defaults(func=func)
return decorator
@subcommand(
[argument("--data", type=str, help="The path to the main perception data folder.")]
)
def preview(args):
"""Previews the dataset in a streamlit app."""
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, "preview.py")
if args.data is None:
print("Data directory not specified!")
else:
args = [args.data]
# _config.set_option("server.headless", True)
streamlit.bootstrap.run(filename, "", args)
def main():
args = cli.parse_args()
if args.subcommand is None:
cli.print_help()
else:
args.func(args)
if __name__ == "__main__":
main()

7
com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/cli.py.meta


fileFormatVersion: 2
guid: e85c6e72c61fdc84db1888b18f4394de
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

143
com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/preview.py


import argparse
import os
from typing import Dict, List, Tuple
import numpy as np
import streamlit as st
from PIL import ImageFont
from PIL.Image import Image
from PIL.ImageDraw import ImageDraw
from pyrception_utils import PyrceptionDataset
def list_datasets(path) -> List:
"""
Lists the datasets in a diretory.
:param path: path to a directory that contains dataset folders
:type str:
:return: A list of dataset directories.
:rtype: List
"""
datasets = []
for item in os.listdir(path):
if os.path.isdir(os.path.join(path, item)) and item != "Unity":
datasets.append(item)
return datasets
def frame_selector_ui(dataset: PyrceptionDataset) -> int:
"""
Frame selector streamlist widget to select which frame in the dataset to display
:param dataset: the PyrceptionDataset
:type PyrceptionDataset:
:return: The image index
:rtype: int
"""
st.sidebar.markdown("# Image set")
num_images = len(dataset)
image_index = st.sidebar.slider("Image number", 0, num_images - 1)
return image_index
def draw_image_with_boxes(
image: Image,
classes: Dict,
labels: List,
boxes: List[List],
colors: Dict,
header: str,
description: str,
):
"""
Draws an image in streamlit with labels and bounding boxes.
:param image: the PIL image
:type PIL:
:param classes: the class dictionary
:type Dict:
:param labels: list of integer object labels for the frame
:type List:
:param boxes: List of bounding boxes (as a List of coordinates) for the frame
:type List[List]:
:param colors: class colors
:type Dict:
:param header: Image header
:type str:
:param description: Image description
:type str:
"""
image_draw = ImageDraw(image)
# draw bounding boxes
font = ImageFont.truetype("C:\Windows\Fonts\Arial.ttf", 15)
for label, box in zip(labels, boxes):
class_name = classes[label]
image_draw.rectangle(box, outline=colors[class_name], width=2)
image_draw.text(
(box[0], box[1]), class_name, font=font, fill=colors[class_name]
)
st.subheader(header)
st.markdown(description)
st.image(image, use_column_width=True)
@st.cache(show_spinner=True, allow_output_mutation=True)
def load_perception_dataset(path: str) -> Tuple:
"""
Loads the perception dataset in the cache and caches the random bounding box color scheme.
:param path: Dataset path
:type str:
:return: A tuple with the colors and PyrceptionDataset object as (colors, dataset)
:rtype: Tuple
"""
dataset = PyrceptionDataset(data_dir=path)
classes = dataset.classes
colors = {name: tuple(np.random.randint(128, 255, size=3)) for name in classes}
return colors, dataset
def preview_dataset(base_dataset_dir: str):
"""
Adds streamlit components to the app to construct the dataset preview.
:param base_dataset_dir: The directory that contains the perceptions datasets.
:type str:
"""
st.markdown("# Synthetic Dataset Preview\n ## Unity Technologies ")
dataset_name = st.sidebar.selectbox(
"Please select a dataset...", list_datasets(base_dataset_dir)
)
if dataset_name is not None:
colors, dataset = load_perception_dataset(
os.path.join(base_dataset_dir, dataset_name)
)
classes = dataset.classes
image_index = frame_selector_ui(dataset)
image, target = dataset[image_index]
labels = target["labels"]
boxes = target["boxes"]
draw_image_with_boxes(
image, classes, labels, boxes, colors, "Synthetic Image Preview", ""
)
def preview_app(args):
"""
Starts the dataset preview app.
:param args: Arguments for the app, such as dataset
:type args: Namespace
"""
dataset_dir = args.data
if dataset_dir is not None:
st.sidebar.title("Pyrception Dataset Preview")
preview_dataset(dataset_dir)
else:
raise ValueError("Please specify the path to the main dataset directory!")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("data", type=str)
args = parser.parse_args()
preview_app(args)

7
com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/preview.py.meta


fileFormatVersion: 2
guid: 0aaccb7c618c14341872aa56f3ccc894
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

271
com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/pyrception.py


import json
import os
import pathlib
import re
from collections import namedtuple
from enum import Enum
from typing import Dict, Iterator, List, Tuple, Union
from PIL import Image
class FileType(Enum):
"""
Enumerator for file types in the perception dataset. Based on
"""
BINARY = "binary"
REFERENCE = "reference"
METRIC = "metric"
CAPTURE = "capture"
MetadataFile = namedtuple("File", "file pattern filetype")
DATASET_METADATA = {
"annotation_definitions": MetadataFile(
"**/annotation_definitions.json",
r"(?:\w|-|/)*annotation_definitions.json",
FileType.REFERENCE,
),
"captures": MetadataFile(
"**/captures_*.json",
r"(?:\w|-|/)*captures_[0-9]+.json",
FileType.CAPTURE,
),
"egos": MetadataFile("**/egos.json", r"(?:\w|-|/)*egos.json", FileType.REFERENCE),
"metric_definitions": MetadataFile(
"**/metric_definitions.json",
r"(?:\w|-|/)*metric_definitions.json",
FileType.REFERENCE,
),
"metrics": MetadataFile(
"**/metrics_*.json", r"(?:\w|-|/)*metrics_[0-9]+.json", FileType.METRIC
),
"sensors": MetadataFile(
"**/sensors.json", r"(?:\w|-|/)*sensors.json", FileType.REFERENCE
),
"metadata": MetadataFile(
"**/metadata.json", r"(?:\w|-|/)*metadata.json", FileType.REFERENCE
),
}
# File globbing based on https://github.com/Unity-Technologies/datasetinsights/blob/master
# /datasetinsights/datasets/unity_perception/tables.py
def glob(data_root: str, pattern: str) -> Iterator[str]:
"""
Find all files in a directory, data_dir, that match the pattern.
:param data_root: The path to the directory that contains the dataset.
:type str:
:param pattern: The file pattern to match.
:type str:
:return: Returns an string iterator containing the paths to the matching files.
:rtype: Iterator[str]
"""
path = pathlib.Path(data_root)
for file_path in path.glob(pattern):
yield file_path
def file_number(filename):
"""
Key function to sort glob list.
:param filename: POSIX path
:type filename:
:return:
:rtype:
"""
result = re.split("_|\.", str(filename))[-2]
return int(result)
def glob_list(data_root: str, pattern: str) -> List:
"""
Find all files in a directory, data_dir, that match the pattern.
:param data_root: The path to the directory that contains the dataset.
:type str:
:param pattern: The file pattern to match.
:type str:
:return: Returns an string iterator containing the paths to the matching files.
:rtype: Iterator[str]
"""
path = pathlib.Path(data_root)
file_list = []
for file_path in sorted(path.glob(pattern), key=file_number):
file_list.append(file_path)
return file_list
# TODO add version checking
def load_json(file: str, key: Union[str, List]) -> Dict:
"""
Loads top level records from json file given key or list of keys.
:param file: The json filename.
:type str:
:param key: The top-level key or list of keys to load.
:type Union[str, List]:
:return: Returns a dictionary representing the json record
:rtype: Dict
"""
data = json.load(open(file, "r"))
if isinstance(key, str):
return data[key]
elif isinstance(key, List):
return {k: data[k] for k in key}
class PyrceptionDatasetMetadata:
DATA = "captures"
META = "metadata"
ANNOTATION_META = "annotation_definitions"
DATASET_INFO = ["dataset_size", "per_file_size", "image_width", "image_height"]
DATA_PATTERN = DATASET_METADATA[DATA].file
META_PATTERN = DATASET_METADATA[META].file
ANN_PATTERN = DATASET_METADATA[ANNOTATION_META].file
def __init__(self, data_dir: str = None):
"""
Creates a PyrceptionDataset object that can be used to iterate through the perception
dataset.
:param data_dir: The path to the perception dataset.
:type str:
"""
self.image_size = None
self.data_dir = data_dir
self.data = []
self.annotations = []
if self.data_dir is None:
raise ValueError("You must specify the path to a perception sdk dataset.")
# Load annotation metadata file set
self.data_files = glob_list(self.data_dir, self.DATA_PATTERN)
self.data = None
# Load metadata info from metadata file
for metadata_file in glob(self.data_dir, self.META_PATTERN):
self.dataset_info = load_json(metadata_file, self.DATASET_INFO)
# Load dataset info and annotation definitions file
for annotation_file in glob(self.data_dir, self.ANN_PATTERN):
self.annotations.extend(load_json(annotation_file, self.ANNOTATION_META))
# Set dataset info
self.length = self.dataset_info["dataset_size"]
self.file_mod_factor = self.dataset_info["per_file_size"]
# Extract the class labels
self.classes = []
for label in self.annotations[0]["spec"]:
self.classes.append(label["label_name"])
# Set the number of classes
self.num_classes = len(self.classes)
# Set the image size
self.image_size = (
self.dataset_info["image_height"],
self.dataset_info["image_width"],
3,
)
class PyrceptionDataset:
"""
Pyrception class for reading and visualizing annotations generated by the perception SDK.
"""
def __init__(
self, metadata: PyrceptionDatasetMetadata = None, data_dir: str = None
):
"""
Creates a PyrceptionDataset object that can be used to iterate through the perception
dataset.
:param data_dir: The path to the perception dataset.
:type str:
"""
if metadata:
self.metadata = metadata
elif not metadata and data_dir:
self.metadata = PyrceptionDatasetMetadata(data_dir)
else:
raise ValueError(
"You must specify either PyrceptionDatasetMetadata or a data directory"
)
self.last_file_index = None
def __getitem__(self, index: int) -> Tuple:
"""
Iterator to get one frame at a time based on index.
:param index: the index of the frame to retrieve
:type int:
:return: Returns a tuple containing the image and target metadata as (image, target)
:rtype: Tuple
"""
if index > self.metadata.length - 1:
raise IndexError("Index of out bounds.")
sub_index = self.__load_subset(index)
try:
image = Image.open(
os.path.join(self.metadata.data_dir, self.data[sub_index]["filename"])
).convert("RGB")
except IndexError:
print(self.data)
raise IndexError(f"Index is :{index} Subindex is:{sub_index}")
image_ann = self.data[sub_index]
boxes = []
labels = []
for value in image_ann["annotations"][0]["values"]:
box = [
value["x"],
value["y"],
value["x"] + value["width"],
value["y"] + value["height"],
]
label = value["label_id"]
boxes.append(box)
labels.append(label)
# assumes that the image id naming convention is
# RGB<uuid>/rgb_<image_id>.png
image_id = self.data[sub_index]["filename"][44:-4]
target = {"image_id": image_id, "labels": labels, "boxes": boxes}
return image, target
def __len__(self) -> int:
"""
Returns the length of the perception dataset.
:return: Length of the dataset.
:rtype: int
"""
return self.metadata.length
def __load_subset(self, index):
file_index = index // self.metadata.file_mod_factor
sub_index = index % self.metadata.file_mod_factor
if self.last_file_index != file_index:
self.data = load_json(
self.metadata.data_files[file_index], self.metadata.DATA
)
self.last_file_index = file_index
return sub_index
@property
def num_classes(self):
return self.metadata.num_classes
@property
def classes(self):
return self.metadata.classes

7
com.unity.perception/Editor/Pyrception/pyrception-utils/pyrception_utils/pyrception.py.meta


fileFormatVersion: 2
guid: 9b0e3ea90970bc842bfaac0686404020
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

12
com.unity.perception/Editor/Pyrception/pyrception-utils/requirements.txt


Pillow>=8.1.0
streamlit==0.75.0
google-cloud-storage==1.19.0
gcsfs==0.7.1
flake8==3.8.3
isort==4.3.21
black==20.8b1
pre-commit==2.11.1
pytest==6.2.2
pytest-html==3.1.1
pytest-datadir==1.3.1
coverage==5.5

7
com.unity.perception/Editor/Pyrception/pyrception-utils/requirements.txt.meta


fileFormatVersion: 2
guid: f32923841fe5d994bbbfbade1325cba5
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

18
com.unity.perception/Editor/Pyrception/pyrception-utils/setup.py


from setuptools import find_packages, setup
# TODO: add versions for packages
setup(
name="pyrception-utils",
version="0.1.1",
description="Pyrception-Utils: A toolkit for managing Unity Perception SDK datasets.",
author="Unity Technologies",
packages=find_packages(),
python_requires=">=3.7",
install_requires=[
"Pillow>=8.1.0",
"streamlit==0.75.0",
"google-cloud-storage==1.19.0",
"gcsfs==0.7.1",
],
entry_points={"console_scripts": ["pyrception-utils=pyrception_utils.cli:main"]},
)

7
com.unity.perception/Editor/Pyrception/pyrception-utils/setup.py.meta


fileFormatVersion: 2
guid: 81355802e00c9b44191c76325bfa5ad3
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存