diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 47840bab..00000000 --- a/.coveragerc +++ /dev/null @@ -1,13 +0,0 @@ -[run] -branch = True -source = src - -[report] -exclude_lines = - if self.debug: - pragma: no cover - raise NotImplementedError - if __name__ == .__main__.: -ignore_errors = True -omit = - tests/* \ No newline at end of file diff --git a/.gitignore b/.gitignore index 481d6a68..fe4e5bd1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,9 @@ env __pycache__ *.pyc .DS_Store +MANIFEST +*.egg-info +dist/ +.pypirc +.remote-sync.json +links.txt diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index 9eb3a1b5..00000000 --- a/.pylintrc +++ /dev/null @@ -1,424 +0,0 @@ -# This file was mostly generated with pylint --generate-rcfile. To see changes -# from the default values, search for "DEFAULT" in this file. - -[MASTER] - -# Specify a configuration file. -#rcfile= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Add files or directories to the blacklist. They should be base names, not -# paths. -ignore=CVS - -# Add files or directories matching the regex patterns to the blacklist. The -# regex matches against base names, not paths. -ignore-patterns= - -# Pickle collected data for later comparisons. -persistent=yes - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins= - -# Use multiple processes to speed up Pylint. -jobs=1 - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code -extension-pkg-whitelist= - -# Allow optimization of some AST trees. This will activate a peephole AST -# optimizer, which will apply various small optimizations. For instance, it can -# be used to obtain the result of joining multiple strings with the addition -# operator. Joining a lot of strings can lead to a maximum recursion error in -# Pylint and this flag can prevent that. It has one side effect, the resulting -# AST will be different than the one from reality. This option is deprecated -# and it will be removed in Pylint 2.0. -optimize-ast=no - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -#enable= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -# DEFAULT: without fixme,invalid-name,no-self-use -# RATIONALE: (fixme) It generates warnings for TODOs. -# RATIONALE: (invalid-name) It rejects class-level constants and short names. -# RATIONALE: (no-self-use) @staticmethod is discouraged by Google style. -disable=backtick,reduce-builtin,nonzero-method,long-suffix,file-builtin,indexing-exception,buffer-builtin,standarderror-builtin,apply-builtin,delslice-method,unicode-builtin,suppressed-message,zip-builtin-not-iterating,intern-builtin,old-octal-literal,old-division,range-builtin-not-iterating,useless-suppression,print-statement,filter-builtin-not-iterating,cmp-builtin,coerce-builtin,input-builtin,setslice-method,execfile-builtin,long-builtin,raising-string,getslice-method,cmp-method,coerce-method,next-method-called,raw_input-builtin,oct-method,import-star-module-level,unichr-builtin,round-builtin,parameter-unpacking,map-builtin-not-iterating,unpacking-in-except,dict-view-method,dict-iter-method,hex-method,old-raise-syntax,basestring-builtin,metaclass-assignment,using-cmp-argument,no-absolute-import,xrange-builtin,old-ne-operator,reload-builtin,fixme,invalid-name,no-self-use - - -[REPORTS] - -# Set the output format. Available formats are text, parseable, colorized, msvs -# (visual studio) and html. You can also give a reporter class, eg -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Put messages in a separate file for each module / package specified on the -# command line instead of printing them on stdout. Reports (if any) will be -# written in a file name "pylint_global.[txt|html]". This option is deprecated -# and it will be removed in Pylint 2.0. -files-output=no - -# Tells whether to display a full report or only the messages -reports=yes - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details -#msg-template= - - -[SPELLING] - -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -spelling-dict= - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to indicated private dictionary in -# --spelling-private-dict-file option instead of raising a message. -spelling-store-unknown-words=no - - -[FORMAT] - -# Maximum number of characters on a single line. -max-line-length=100 - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - -# List of optional constructs for which whitespace checking is disabled. `dict- -# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. -# `trailing-comma` allows a space between comma and closing bracket: (a, ). -# `empty-line` allows space-only lines. -no-space-check=trailing-comma,dict-separator - -# Maximum number of lines in a module -max-module-lines=1000 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format= - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME,XXX,TODO - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging - - -[TYPECHECK] - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis. It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules=configargparse,google,grpc,numpy,oauth2client,RPi.GPIO,scipy,googlesamples - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=optparse.Values,thread._local,_thread._local - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members=.*Response.* - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - - -[SIMILARITIES] - -# Minimum lines number of a similarity. -min-similarity-lines=4 - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=no - - -[BASIC] - -# Good variable names which should always be accepted, separated by a comma -good-names=i,j,k,ex,Run,_ - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -property-classes=abc.abstractproperty - -# Regular expression matching correct variable names -variable-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for variable names -variable-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct constant names -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Naming hint for constant names -const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Regular expression matching correct class attribute names -class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Naming hint for class attribute names -class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Regular expression matching correct inline iteration names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Naming hint for inline iteration names -inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ - -# Regular expression matching correct function names -function-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for function names -function-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct class names -class-rgx=[A-Z_][a-zA-Z0-9]+$ - -# Naming hint for class names -class-name-hint=[A-Z_][a-zA-Z0-9]+$ - -# Regular expression matching correct attribute names -attr-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for attribute names -attr-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct argument names -argument-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for argument names -argument-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Naming hint for module names -module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Regular expression matching correct method names -method-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for method names -method-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match function or class names that do -# not require a docstring. -# DEFAULT: ^_ -# RATIONALE: Docstring for main would duplicate file docstring. -no-docstring-rgx=^_|^main$ - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -# DEFAULT: -1 -# RATIONALE: Lots of short methods, where docstrings would be repetitive. -docstring-min-length=10 - - -[ELIF] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - - -[VARIABLES] - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=(_+[a-zA-Z0-9]*?$)|dummy - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -# DEFAULT: none -# RATIONALE: Provided by gettext. -additional-builtins=_ - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_,_cb - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six.moves,future.builtins - - -[CLASSES] - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict,_fields,_replace,_source,_make - - -[DESIGN] - -# Maximum number of arguments for function / method -# DEFAULT: 5 -# RATIONALE: Keyword arguments make this manageable. -max-args=10 - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.* - -# Maximum number of locals for function / method body -max-locals=15 - -# Maximum number of return / yield for function / method body -max-returns=6 - -# Maximum number of branch for function / method body -max-branches=12 - -# Maximum number of statements in function / method body -max-statements=50 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of attributes for a class (see R0902). -max-attributes=7 - -# Minimum number of public methods for a class (see R0903). -# DEFAULT: 2 -# RATIONALE: Classes can have docstrings, namedtuples can't. -min-public-methods=0 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of boolean expressions in a if statement -max-bool-expr=5 - - -[IMPORTS] - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=optparse - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library=audioop - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=Exception diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 373991c3..00000000 --- a/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: python -python: -- 3.4 - -before_install: -- sudo apt-get update -qq -- sudo apt-get install -y python3-numpy python3-scipy - -install: -- pip3 install pyflakes coverage pycodestyle -- pip3 install -r requirements.txt - -script: -- pycodestyle --max-line-length=100 --exclude=*_pb2.py . -- nosetests --with-coverage - -after_success: -- bash <(curl -s https://codecov.io/bash) - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 07603f52..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,33 +0,0 @@ -# How to contribute - -We'd love to accept your patches and contributions to this project. There are -just a few small guidelines you need to follow. - -## Scope of contributions - -This project consists of the support libraries (audio, gRPC, etc) required for AIY Projects, as well as simple examples to experiment with and build upon. - -Please limit pull requests to bug fixes or improvements to code or documentation clarity. -We're not accepting pull requests that add new commands to keep this project as simple as possible. -If you've added new commands and you'd like to publish your fork for others to use, you can post on [hackster.io](https://www.hackster.io/) or other channels. - -## Contributor License Agreement - -Contributions to this project must be accompanied by a Contributor License -Agreement. You (or your employer) retain the copyright to your contribution, -this simply gives us permission to use and redistribute your contributions as -part of the project. Head over to to see -your current agreements on file or to sign a new one. - -You generally only need to submit a CLA once, so if you've already submitted one -(even if it was for a different project), you probably don't need to do it -again. - -## Code reviews - -All submissions, including submissions by project members, require review. We -use GitHub pull requests for this purpose. Consult [GitHub Help] for more -information on using pull requests. - -[GitHub Help]: https://help.github.com/articles/about-pull-requests/ - diff --git a/HACKING.md b/HACKING.md deleted file mode 100644 index aadfb96b..00000000 --- a/HACKING.md +++ /dev/null @@ -1,85 +0,0 @@ -# Setting up the image - -We recommend using [the images](https://aiyprojects.withgoogle.com/voice) we -provide. Those images are based on [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), -with a few customizations and are tested on the Raspberry Pi 3. If you prefer -to setup Raspbian yourself, there are some manual steps you need to take. - -## Installing the dependencies - -First, make sure you have `git` installed and clone this repository in -`~/AIY-projects-python`: - -```shell -sudo apt-get install git -cd -git clone https://github.com/google/aiyprojects-raspbian.git AIY-projects-python -``` - -Then, install the project dependencies and setup the services: - -``` shell -cd ~/AIY-projects-python -scripts/install-deps.sh -sudo scripts/install-services.sh -``` - -## Configuring the Voice HAT driver - -To use the Voice HAT, your kernel needs to be 4.9 or later. This is available -on Raspbian 2017-07-05 and later. You'll also need to configure ALSA: - -``` shell -sudo scripts/configure-driver.sh -sudo reboot -``` - -After your Pi has rebooted with the driver enabled, run: - -``` -cd ~/AIY-projects-python -sudo scripts/install-alsa-config.sh -env/bin/python checkpoints/check_audio.py -sudo reboot -``` - -Don't skip running `check_audio.py` before rebooting, as it has an important -effect on the state of ALSA, the sound architecture. - -## Get cloud credentials - -To access the cloud services you need to register a project and generate -credentials for cloud APIs. This is documented in the -[setup instructions](https://aiyprojects.withgoogle.com/voice#users-guide-1-1--connect-to-google-cloud-platform) on the -webpage. - -## Making code changes - -If you edit the code on a different computer, you can deploy it to your -Raspberry Pi by running: - -``` shell -make deploy -``` - -## Running automatically - -You can find sample scripts in the `src` directory showing how to use the -Assistant SDK. - -To execute any of these scripts on the Raspberry Pi, login to it and run -(replacing the filename with the script you want to run): - -``` shell -cd ~/AIY-projects-python -source env/bin/activate -python3 src/examples/voice/assistant_library_demo.py -``` - -If you want the voice recognizer service to run automatically when the Pi -boots, you need to have a file in the `src` directory named `main.py`. You can -make a copy of one of the example scripts and rename it. Then run this command: - -``` shell -sudo systemctl enable voice-recognizer.service -``` diff --git a/LICENSE b/LICENSE.txt similarity index 100% rename from LICENSE rename to LICENSE.txt diff --git a/Makefile b/Makefile deleted file mode 100644 index 5b72648c..00000000 --- a/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -PI ?= raspberrypi.local - -SHORTCUTS = $(wildcard shortcuts/*.desktop) - -check: - PYTHONPATH=$$PWD/src python3 -m unittest discover tests - -deploy_scripts: - git ls-files | rsync -avz --exclude=".*" --exclude="*.desktop" --files-from - . pi@$(PI):~/AIY-projects-python - -deploy_shortcuts: - scp $(SHORTCUTS) pi@$(PI):~/Desktop - -deploy: deploy_scripts deploy_shortcuts diff --git a/README.md b/README.md index d272dbf4..4d69cbca 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,239 @@ - +# AIY Voice Only -This repository contains an easy-to-use API for the AIY Vision Kit and -AIY Voice Kit. -You can use it for face detection and object recognition, or use it to create -voice commands with simple while loops - have a look at the -[demos](https://github.com/google/aiyprojects-raspbian/tree/aiyprojects/src/examples). -Documentation is at the [AIY Projects site](https://aiyprojects.withgoogle.com). +[Google AIY Voice Kit](https://aiyprojects.withgoogle.com/voice) is a cool +project. But it locks you into its custom hardware. I have separated its +software to work on Raspberry Pi (3B and 3B+) independently, just using a normal +speaker and microphone. -For guidelines on contributing, look at [CONTRIBUTING.md](CONTRIBUTING.md). -If you're using Raspbian instead of Google's provided image, read -[HACKING.md](HACKING.md) for information on getting started. +The following instructions aim at: -For returning users: -The code for all AIY kits is in the `aiyprojects` branch, and is included in -images starting with aiyprojects-2017-12-18.img. The previous `voicekit` branch -contains code just for the Voice Kit, and the `master` branch contains the -original, deprecated Voice Recognizer demo. +**Raspberry Pi (3B, 3B+)** +**Raspbian Stretch** +**Python 3** -# Support +Additionally, you need: -If you're having trouble assembling your kit or running the demos, -try the [AIY Forums](https://www.raspberrypi.org/forums/viewforum.php?f=114). +- a **Speaker** to plug into Raspberry Pi's headphone jack +- a **USB Microphone** -If you've found a bug in the AIY API or demos, you can look at the -[known issues](https://github.com/google/aiyprojects-raspbian/issues) or create -a new one, or even fix it yourself and send us a pull request. +**Plug them in.** Let's go. -If you've found a problem with the Assistant (for example, crashes in the -library or incorrect responses), you can try -[the G+ community](https://plus.google.com/communities/117537996116836200696), -[Stack Overflow](https://stackoverflow.com/questions/tagged/google-assistant-sdk), -or [the assistant-sdk-python repo](https://github.com/googlesamples/assistant-sdk-python/). +## Find your speaker and mic -If you've had a problem after updating the source code, try downloading the -latest AIY image from the website, or alternatively run the following commands -in the dev terminal: +Locate your speaker in the list of playback hardware devices. Normally, it is at +**card 0, device 0**, as indicated by the sample output below. ``` -rm -r env -./scripts/install-deps.sh +$ aplay -l + +**** List of PLAYBACK Hardware Devices **** +card 0: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA] + Subdevices: 8/8 + Subdevice #0: subdevice #0 + Subdevice #1: subdevice #1 + Subdevice #2: subdevice #2 + Subdevice #3: subdevice #3 + Subdevice #4: subdevice #4 + Subdevice #5: subdevice #5 + Subdevice #6: subdevice #6 + Subdevice #7: subdevice #7 +card 0: ALSA [bcm2835 ALSA], device 1: bcm2835 ALSA [bcm2835 IEC958/HDMI] + Subdevices: 1/1 + Subdevice #0: subdevice #0 +``` + +Locate your USB microphone in the list of capture hardware devices. Normally, it +is at **card 1, device 0**, as indicated by the sample output below. + +``` +$ arecord -l + +**** List of CAPTURE Hardware Devices **** +card 1: Device [USB PnP Audio Device], device 0: USB Audio [USB Audio] + Subdevices: 1/1 + Subdevice #0: subdevice #0 +``` + +*Your hardware's number might be different from mine. Adapt accordingly.* + +## Make them the defaults + +Create a new file named `.asoundrc` in the home directory (`/home/pi`). Put in +the following contents. Adjust the `card,device` number if needed. + +``` +pcm.!default { + type asym + capture.pcm "mic" + playback.pcm "speaker" +} +pcm.mic { + type plug + slave { + pcm "hw:1,0" # card number, device number + } +} +pcm.speaker { + type plug + slave { + pcm "hw:0,0" # card number, device number + } +} +``` + +## Make sure sound output to headphone jack + +Sound may be output via HDMI or headphone jack. We want to use the headphone +jack. + +Enter `sudo raspi-config`. Select **Advanced Options**, then **Audio**. Choose +**Force 3.5mm (headphone) jack**. + +## Turn up the volume + +A lot of times when sound applications seem to fail, it is because we forget to +turn up the volume. + +Volume adjustment can be done with `alsamixer`. This program makes use of some +function keys (`F1`, `F2`, etc). For function keys to function properly on +PuTTY, we need to change some settings (click on the top-left corner of the +PuTTY window, then select **Change Settings ...**): + +1. Go to **Terminal** / **Keyboard** +2. Look for section **The Function keys and keypad** +3. Select **Xterm R6** +4. Press button **Apply** + +Now, we are ready to turn up the volume, for both the speaker and the mic: + +``` +$ alsamixer +``` +`F6` to select between sound cards +`F3` to select playback volume (for speaker) +`F4` to select capture volume (for mic) +`⬆` `⬇` arrow keys to adjust +`Esc` to exit + +*If you unplug the USB microphone at any moment, all volume settings +(including that of the speaker) may be reset. Make sure to check the volume +again.* + +Hardware all set, let's test them. + +## Test the speaker + +``` +$ speaker-test -t wav +``` + +Press `Ctrl-C` when done. + +## Record a WAV file + ``` +$ arecord --format=S16_LE --duration=5 --rate=16000 --file-type=wav out.wav +``` + +## Play a WAV file + +``` +$ aplay out.wav +``` + +## Register for Google Assistant or Google Cloud Speech + +Although we are not using Google's hardware, there is no escaping from its +software. We still rely on Google Assistant or Google Cloud Speech API to +perform voice recognition. To use these cloud services, you have to go through a +series of registration steps: + +- [Configure Google Assistant API](https://developers.google.com/assistant/sdk/guides/library/python/embed/config-dev-project-and-account) +- [Configure Google Cloud Speech API](https://aiyprojects.withgoogle.com/voice#makers-guide-3-1--change-to-the-cloud-speech-api) + +Which one to use depends on what you need. **Google Assistant** can recognize +speech *and* talk back intelligently, but supports fewer languages. **Google +Cloud Speech** only recognizes speech (no talk-back), but supports far more +languages. + +Here is a summary of the steps for using **Google Assistant**, as of 2019-11-27. +Always pay attention to the **Project ID** on top of the page to make sure you +are in the right project. + +1. Create a Project + +2. Enable Google Assistant API + +3. Configure OAuth consent screen (must fill in **Support email**) + +4. Enable activity controls + +5. Register device model, Download credentials file (check `project_id`) + +6. Install system dependencies: + ``` + $ sudo apt-get install portaudio19-dev libffi-dev libssl-dev + ``` + +7. Install Python packages: + ``` + $ sudo pip3 install --upgrade pip setuptools wheel + $ sudo pip3 install google-assistant-library==1.0.1 \ + google-assistant-grpc==0.2.0 \ + google-assistant-sdk[samples]==0.5.1 \ + google-auth-oauthlib[tool] \ + google-cloud-speech + ``` + On Raspbian Buster, you likely have to downgrade to `google-assistant-library==1.0.0` + for it to work. + +8. Use `google-oauthlib-tool` to authenticate: + ``` + $ google-oauthlib-tool --scope https://www.googleapis.com/auth/assistant-sdk-prototype \ + --save --headless --client-secrets /path/to/client_secret_client-id.json + ``` + +9. Use [`googlesamples-assistant-devicetool`](https://developers.google.com/assistant/sdk/reference/device-registration/device-tool) + to register your Raspberry Pi. A few useful commands may be: + ``` + $ googlesamples-assistant-devicetool --project-id register-device \ + --model \ + --device \ + --client-type LIBRARY + + $ googlesamples-assistant-devicetool --project-id list --model + + $ googlesamples-assistant-devicetool --project-id list --device + ``` + +## How to use this library + +I used to have it uploaded to PYPI for easy installation. But Google Assistant +is changing too rapidly. I find it more informing to download and try to +integrate it manually: + +1. Download the `aiy` directory + +2. Set environment variable `PYTHONPATH` so Python can find the `aiy` package + +3. You may have to install the Pico text-to-speech engine, `libttspico-utils`, + to allow it to generate speech dynamically (If `apt-get install libttspico-utils` + doesn't work, manually download and install deb packages `libttspico-data`, + `libttspico0`, and `libttspico-utils` separately) + +The best way to experience the software is to try it. +**[Let's go to the examples.](https://github.com/nickoala/aiy-voice-only/tree/aiyprojects/examples/voice)** + +## Changes to original library + +Here is an outline of the changes I have made to the original [AIY Voice +Kit](https://github.com/google/aiyprojects-raspbian) source code: + +1. No Vision stuff: The AIY project actually includes the [Vision +Kit](https://aiyprojects.withgoogle.com/vision) and associated software, which +are of no concern to this project. I have removed those. + +2. No Voice Hat stuff: This project does not rely on the Voice Hat. The +`aiy.board` module has been removed. + +3. The class `Led` and `Button` have been moved to the `aiy.util` module. diff --git a/src/aiy/__init__.py b/aiy/__init__.py similarity index 100% rename from src/aiy/__init__.py rename to aiy/__init__.py diff --git a/src/aiy/_drivers/_buzzer.py b/aiy/_buzzer.py similarity index 99% rename from src/aiy/_drivers/_buzzer.py rename to aiy/_buzzer.py index 3f09c2c8..35b2e8d2 100644 --- a/src/aiy/_drivers/_buzzer.py +++ b/aiy/_buzzer.py @@ -30,7 +30,7 @@ def HzToPeriodUsec(freq_hz): return USEC / freq_hz -class PWMController(object): +class PWMController: """Controller that simplifies the interface to pwm-soft Linux driver. Simple usage: diff --git a/src/aiy/_apis/__init__.py b/aiy/assistant/__init__.py similarity index 100% rename from src/aiy/_apis/__init__.py rename to aiy/assistant/__init__.py diff --git a/src/aiy/assistant/auth_helpers.py b/aiy/assistant/auth_helpers.py similarity index 83% rename from src/aiy/assistant/auth_helpers.py rename to aiy/assistant/auth_helpers.py index b1adac64..c0f2757f 100644 --- a/src/aiy/assistant/auth_helpers.py +++ b/aiy/assistant/auth_helpers.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Auth helpers for Google Assistant API.""" +"""Authentication helper for the Google Assistant API.""" import json import logging @@ -127,6 +127,25 @@ def _try_to_get_credentials(client_secrets): def get_assistant_credentials(credentials_file=None): + """ + Retreives the OAuth credentials required to access the Google Assistant API. + + If you're using :mod:`aiy.assistant.library`, you must call this function and pass the result + to the :class:`~aiy.assistant.library.Assistant` constructor. + + If you're using :mod:`aiy.assistant.grpc`, you do not need this function because the + :class:`~aiy.assistant.grpc.AssistantServiceClient` calls this during initialization (using the + credentials file at ``~/assistant.json``). + + Args: + credentials_file: Absolute path to your JSON credentials file. + If None, it looks for the file at ``~/assistant.json``. + To get a credentials file, `follow these instructions + `_. + + Returns: + The device OAuth credentials, as a ``google.oauth2.credentials.Credentials`` object. + """ if not credentials_file: credentials_file = _ASSISTANT_CREDENTIALS_FILE return _try_to_get_credentials(credentials_file) diff --git a/src/aiy/assistant/device_helpers.py b/aiy/assistant/device_helpers.py similarity index 100% rename from src/aiy/assistant/device_helpers.py rename to aiy/assistant/device_helpers.py diff --git a/aiy/assistant/grpc.py b/aiy/assistant/grpc.py new file mode 100644 index 00000000..b4574796 --- /dev/null +++ b/aiy/assistant/grpc.py @@ -0,0 +1,277 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Enables a conversation with the Google Assistant, using the `Google Assistant Service`_, which +connects to the Google Assistant using a streaming endpoint over gRPC. + +This gRPC service is typically more complicated to set up, compared to the Google Assistant +Library, but this API takes care of all the complexity for you. So you simply create an instance +of :class:`AssistantServiceClient`, then start the Google Assistant by calling +:meth:`~AssistantServiceClient.conversation`. + +This API provides only an interface to initiate a conversation with the Google Assistant. It +speaks and prints all responses for you—it does not allow you to handle the response events or +create custom commands. +For an example, see :github:`src/examples/voice/assistant_grpc_demo.py`. + +If you want to integrate custom device commands with the Google Assistant using the gRPC interface, +instead use the `Google Assistant Service`_ directly. For an example, see `this gRPC sample +`_. +Or instead of interacting with the Google Assistant, you can use :mod:`aiy.cloudspeech` +to convert your voice commands into text that triggers your actions. +""" + +import array +import logging +import math +import os +import sys + +os.environ['GRPC_POLL_STRATEGY'] = 'epoll1' +import google.auth.transport.grpc +import google.auth.transport.requests +import google.oauth2.credentials + +from google.assistant.embedded.v1alpha2 import embedded_assistant_pb2 +from google.assistant.embedded.v1alpha2 import embedded_assistant_pb2_grpc + +from aiy.assistant import auth_helpers, device_helpers +from aiy.util import Led +from aiy.voice.audio import AudioFormat, Recorder, BytesPlayer + +logger = logging.getLogger(__name__) + +ASSISTANT_API_ENDPOINT = 'embeddedassistant.googleapis.com' +END_OF_UTTERANCE = embedded_assistant_pb2.AssistResponse.END_OF_UTTERANCE +DIALOG_FOLLOW_ON = embedded_assistant_pb2.DialogStateOut.DIALOG_FOLLOW_ON +CLOSE_MICROPHONE = embedded_assistant_pb2.DialogStateOut.CLOSE_MICROPHONE +PLAYING = embedded_assistant_pb2.ScreenOutConfig.PLAYING +DEFAULT_GRPC_DEADLINE = 60 * 3 + 5 +AUDIO_SAMPLE_RATE_HZ = 16000 +AUDIO_FORMAT=AudioFormat(sample_rate_hz=AUDIO_SAMPLE_RATE_HZ, + num_channels=1, + bytes_per_sample=2) + +def _normalize_audio_buffer(buf, volume_percentage, sample_width=2): + assert sample_width == 2 + scale = math.pow(2, 1.0 * volume_percentage / 100) - 1 + arr = array.array('h', buf) + for i in range(0, len(arr)): + arr[i] = int(arr[i] * scale) + return arr.tobytes() + +# https://developers.google.com/assistant/sdk/reference/rpc/ +class AssistantServiceClient: + """ + Provides a simplified interface for the `EmbeddedAssistant + `_. + + Args: + language_code: Language expected from the user, in IETF BCP 47 syntax (default is "en-US"). + See the `list of supported languages + `_. + volume_percentage: Volume level of the audio output. Valid values are 1 to 100 + (corresponding to 1% to 100%). + """ + def __init__(self, language_code='en-US', volume_percentage=100): + self._volume_percentage = volume_percentage # Mutable state. + self._conversation_state = None # Mutable state. + self._language_code = language_code + + ## + credentials = auth_helpers.get_assistant_credentials() + device_model_id, device_id = device_helpers.get_ids_for_service(credentials) + + logger.info('device_model_id: %s', device_model_id) + logger.info('device_id: %s', device_id) + + http_request = google.auth.transport.requests.Request() + try: + credentials.refresh(http_request) + except Exception as e: + raise RuntimeError('Error loading credentials: %s', e) + + api_endpoint = ASSISTANT_API_ENDPOINT + grpc_channel = google.auth.transport.grpc.secure_authorized_channel( + credentials, http_request, api_endpoint) + logger.info('Connecting to %s', api_endpoint) + ## + + self._assistant = embedded_assistant_pb2_grpc.EmbeddedAssistantStub(grpc_channel) + self._device_config = embedded_assistant_pb2.DeviceConfig( + device_model_id=device_model_id, + device_id=device_id) + + @property + def volume_percentage(self): + """ + Volume level of the audio output. Valid values are 1 to 100 (corresponding to 1% to 100%). + """ + return self._volume_percentage + + def _recording_started(self): + logger.info('Recording started.') + + def _recording_stopped(self): + logger.info('Recording stopped.') + + def _playing_started(self): + logger.info('Playing started.') + + def _playing_stopped(self): + logger.info('Playing stopped.') + + def _requests(self, recorder): + audio_in_config = embedded_assistant_pb2.AudioInConfig( + encoding='LINEAR16', + sample_rate_hertz=AUDIO_SAMPLE_RATE_HZ) + + audio_out_config = embedded_assistant_pb2.AudioOutConfig( + encoding='LINEAR16', + sample_rate_hertz=AUDIO_SAMPLE_RATE_HZ, + volume_percentage=self._volume_percentage) + + dialog_state_in = embedded_assistant_pb2.DialogStateIn( + conversation_state=self._conversation_state, + language_code=self._language_code) + + config = embedded_assistant_pb2.AssistConfig( + audio_in_config=audio_in_config, + audio_out_config=audio_out_config, + device_config=self._device_config, + dialog_state_in=dialog_state_in) + + yield embedded_assistant_pb2.AssistRequest(config=config) + + for chunk in recorder.record(AUDIO_FORMAT, + chunk_duration_sec=0.1, + on_start=self._recording_started, + on_stop=self._recording_stopped): + yield embedded_assistant_pb2.AssistRequest(audio_in=chunk) + + + def _assist(self, recorder, play, deadline): + continue_conversation = False + + for response in self._assistant.Assist(self._requests(recorder), deadline): + if response.event_type == END_OF_UTTERANCE: + logger.info('End of audio request detected.') + recorder.done() + + # Process 'speech_results'. + if response.speech_results: + logger.info('You said: "%s".', + ' '.join(r.transcript for r in response.speech_results)) + # Process 'audio_out'. + if response.audio_out.audio_data: + recorder.done() # Just in case. + play(_normalize_audio_buffer(response.audio_out.audio_data, + self._volume_percentage)) + + # Process 'dialog_state_out'. + if response.dialog_state_out.conversation_state: + conversation_state = response.dialog_state_out.conversation_state + logger.debug('Updating conversation state.') + self._conversation_state = conversation_state # Mutable state change. + + volume_percentage = response.dialog_state_out.volume_percentage + if volume_percentage: + logger.info('Setting volume to %s%%', volume_percentage) + self._volume_percentage = volume_percentage # Mutable state change. + + supplemental_display_text = response.dialog_state_out.supplemental_display_text + if supplemental_display_text: + logger.info('Assistant said: "%s"', supplemental_display_text) + + microphone_mode = response.dialog_state_out.microphone_mode + if microphone_mode == DIALOG_FOLLOW_ON: + continue_conversation = True + logger.info('Expecting follow-on query from user.') + elif microphone_mode == CLOSE_MICROPHONE: + continue_conversation = False + logger.info('Not expecting follow-on query from user.') + + return continue_conversation + + def conversation(self, deadline=DEFAULT_GRPC_DEADLINE): + """ + Starts a conversation with the Google Assistant. + + The device begins listening for your query or command and will wait indefinitely. + Once it completes a query/command, it returns to listening for another. + + Args: + deadline: The amount of time (in milliseconds) to wait for each gRPC request to + complete before terminating. + """ + keep_talking = True + while keep_talking: + playing = False + with Recorder() as recorder, BytesPlayer() as player: + play = player.play(AUDIO_FORMAT) + + def wrapped_play(data): + nonlocal playing + if not playing: + self._playing_started() + playing = True + play(data) + + try: + keep_talking = self._assist(recorder, wrapped_play, deadline) + finally: + play(None) # Signal end of sound stream. + recorder.done() # Signal stop recording. + + if playing: + self._playing_stopped() + +class AssistantServiceClientWithLed(AssistantServiceClient): + """ + Same as :class:`AssistantServiceClient` but this also turns the + Voice Kit's button LED on and off in response to the conversation. + + Args: + led: An instance of :class:`~aiy.util.Led`. + language_code: Language expected from the user, in IETF BCP 47 syntax (default is "en-US"). + See the `list of supported languages`_. + volume_percentage: Volume level of the audio output. Valid values are 1 to 100 + (corresponding to 1% to 100%). + """ + def _update_led(self, state, brightness): + self._led.state = state + self._led.brightness = brightness + + def __init__(self, led, language_code='en-US', volume_percentage=100): + super().__init__(language_code, volume_percentage) + + self._led = led + self._update_led(Led.ON, 0.1) + + def _recording_started(self): + super()._recording_started() + self._update_led(Led.ON, 1.0) + + def _recording_stopped(self): + self._update_led(Led.ON, 0.1) + super()._recording_stopped() + + def _playing_started(self): + super()._playing_started() + self._update_led(Led.PULSE_SLOW, 1.0) + + def _playing_stopped(self): + self._update_led(Led.ON, 0.1) + super()._playing_stopped() diff --git a/aiy/assistant/library.py b/aiy/assistant/library.py new file mode 100644 index 00000000..056917ab --- /dev/null +++ b/aiy/assistant/library.py @@ -0,0 +1,86 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Facilitates access to the `Google Assistant Library`_, which provides APIs to initiate +conversations with the Google Assistant and create custom device commands commands. + +This includes a wrapper for the ``Assistant`` class only. You must import all other Google +Assistant classes directly from the |code| :assistant:`google.assistant.library<>`\ |endcode| module +to handle each of the response events. + +.. note:: + + Hotword detection (such as "Okay Google") is not supported with the Raspberry Pi Zero + (only with Raspberry Pi 2/3). If you're using a Pi Zero, you must instead use the button or + another type of trigger to initiate a conversation with the Google Assistant. + +.. py:class:: Assistant(credentials) + + Bases: |code| :assistant:`google.assistant.library.Assistant`\ |endcode| + + A wrapper for the |code| :assistant:`Assistant`\ |endcode| class that handles + model and device registration based on the project name in your OAuth credentials + (``assistant.json``) file. + + All the ``Assistant`` APIs are available through this class, such as + |code| :assistant:`start()`\ |endcode| to start the + Assistant, and |code| :assistant:`start_conversation() + `\ |endcode| to start + a conversation, but they are not documented here. Instead refer to the + `Google Assistant Library for Python documentation + `_. + + To get started, you must call :meth:`~aiy.assistant.auth_helpers.get_assistant_credentials` + and pass the result to the ``Assistant`` constructor. For example:: + + from google.assistant.library.event import EventType + from aiy.assistant import auth_helpers + from aiy.assistant.library import Assistant + + credentials = auth_helpers.get_assistant_credentials() + with Assistant(credentials) as assistant: + for event in assistant.start(): + process_event(event) + + For more example code, see :github:`src/examples/voice/assistant_library_demo.py`. + + :param credentials: The Google OAuth2 credentials for the device. Get this from + :meth:`~aiy.assistant.auth_helpers.get_assistant_credentials`. +""" + +import google.assistant.library + +from aiy.assistant import device_helpers + +class Assistant(google.assistant.library.Assistant): + """Client for the Google Assistant Library. + + Similar to google.assistant.library.Assistant, but handles device + registration. + """ + + def __init__(self, credentials): + self._credentials = credentials + self._model_id = device_helpers.register_model_id(credentials) + + super().__init__(credentials, self._model_id) + + def start(self): + events = super().start() + + device_helpers.register_device_id( + self._credentials, self._model_id, self.device_id, "SDK_LIBRARY") + + return events diff --git a/aiy/cloudspeech.py b/aiy/cloudspeech.py new file mode 100644 index 00000000..d8bcd573 --- /dev/null +++ b/aiy/cloudspeech.py @@ -0,0 +1,166 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +APIs that simplify interaction with the `Google Cloud Speech-to-Text service +`_ so you can convert voice commands into actions. +To use this service, you must have a Google Cloud account and a corresponding credentials file. +For more information, see `these setup instructions +`_. + +For an example, see :github:`src/examples/voice/cloudspeech_demo.py`. + +.. note:: + + These APIs are designed for the Voice Kit, but have no dependency on the Voice + HAT/Bonnet specifically. However, they do require some type of sound card + attached to the Raspberry Pi that can be detected by the ALSA subsystem. +""" + +import os +import logging + +os.environ['GRPC_POLL_STRATEGY'] = 'epoll1' +from google.cloud import speech +from google.oauth2 import service_account + +from aiy.voice.audio import AudioFormat, Recorder + +END_OF_SINGLE_UTTERANCE = speech.types.StreamingRecognizeResponse.END_OF_SINGLE_UTTERANCE +AUDIO_SAMPLE_RATE_HZ = 16000 +AUDIO_FORMAT=AudioFormat(sample_rate_hz=AUDIO_SAMPLE_RATE_HZ, + num_channels=1, + bytes_per_sample=2) + +logger = logging.getLogger(__name__) + +# https://cloud.google.com/speech-to-text/docs/reference/rpc/google.cloud.speech.v1 +class CloudSpeechClient: + """ + A simplified version of the Google Cloud ``SpeechClient`` class. + + Args: + service_accout_file: Absolute path to your JSON account credentials file. + If None, it looks for the file at ``~/cloud_speech.json``. + To get a credentials file, `these setup instructions`_. + """ + def __init__(self, service_accout_file=None): + if service_accout_file is None: + service_accout_file = os.path.expanduser('~/cloud_speech.json') + + credentials = service_account.Credentials.from_service_account_file(service_accout_file) + self._client = speech.SpeechClient(credentials=credentials) + + def _make_config(self, language_code, hint_phrases): + return speech.types.RecognitionConfig( + encoding=speech.types.RecognitionConfig.LINEAR16, + sample_rate_hertz=AUDIO_SAMPLE_RATE_HZ, + language_code=language_code, + speech_contexts=[speech.types.SpeechContext(phrases=hint_phrases)]) + + def recognize_bytes(self, data, language_code='en-US', hint_phrases=None): + """ + Performs speech-to-text for a single utterance using the given data source. + Once it detects the user is done speaking, it stops listening and delivers the top + result as text. + + Args: + data: The audio data source. Must be encoded with a sample rate of 16000Hz. + language_code: Language expected from the user, in IETF BCP 47 syntax (default is + "en-US"). See the `list of Cloud's supported languages + `_. + hint_phrase: A list of strings containing words and phrases that may be expected from + the user. These hints help the speech recognizer identify them in the dialog and + improve the accuracy of your results. + + Returns: + The text transcription of the user's dialog. + """ + streaming_config=speech.types.StreamingRecognitionConfig( + config=self._make_config(language_code, hint_phrases), + single_utterance=True) + responses = self._client.streaming_recognize( + config=streaming_config, + requests=[speech.types.StreamingRecognizeRequest(audio_content=data)]) + + for response in responses: + for result in response.results: + if result.is_final: + return result.alternatives[0].transcript + + return None + + def recognize(self, language_code='en-US', hint_phrases=None): + """ + Performs speech-to-text for a single utterance using the default ALSA soundcard driver. + Once it detects the user is done speaking, it stops listening and delivers the top + result as text. + + By default, this method calls :meth:`start_listening` and :meth:`stop_listening` as the + recording begins and ends, respectively. + + Args: + language_code: Language expected from the user, in IETF BCP 47 syntax (default is + "en-US"). See the `list of Cloud's supported languages`_. + hint_phrase: A list of strings containing words and phrases that may be expected from + the user. These hints help the speech recognizer identify them in the dialog and + improve the accuracy of your results. + + Returns: + The text transcription of the user's dialog. + """ + streaming_config=speech.types.StreamingRecognitionConfig( + config=self._make_config(language_code, hint_phrases), + single_utterance=True) + + with Recorder() as recorder: + chunks = recorder.record(AUDIO_FORMAT, + chunk_duration_sec=0.1, + on_start=self.start_listening, + on_stop=self.stop_listening) + + requests = (speech.types.StreamingRecognizeRequest(audio_content=data) for data in chunks) + responses = self._client.streaming_recognize(config=streaming_config, requests=requests) + + for response in responses: + if response.speech_event_type == END_OF_SINGLE_UTTERANCE: + recorder.done() + + for result in response.results: + if result.is_final: + return result.alternatives[0].transcript + + return None + + def start_listening(self): + """ + By default, this simply prints "Start listening" to the log. + + This method is provided as a convenience method that you can override in a derived class to + do something else that indicates the status to the user, such as change the LED state. + + Called by :meth:`recognize` when recording begins. + """ + logger.info('Start listening.') + + def stop_listening(self): + """ + By default, this simply prints "Stop listening" to the log. + + This method is provided as a convenience method that you can override in a derived class to + do something else that indicates the status to the user, such as change the LED state. + + Called by :meth:`recognize` when recording ends. + """ + logger.info('Stop listening.') diff --git a/src/aiy/toneplayer.py b/aiy/toneplayer.py similarity index 95% rename from src/aiy/toneplayer.py rename to aiy/toneplayer.py index 0a1f2cdc..33902caa 100644 --- a/src/aiy/toneplayer.py +++ b/aiy/toneplayer.py @@ -12,16 +12,21 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Simple melodic music player for the piezo buzzer.""" +""" +A simple melodic music player for the piezo buzzer. +This API is designed for the Vision Kit, but has no dependency on the Vision +Bonnet, so may be used without it. It only requires a piezo buzzer connected to +:any:`aiy.pins.BUZZER_GPIO_PIN`. +""" -import time import re +import time -from aiy._drivers._buzzer import PWMController +from ._buzzer import PWMController -class Rest(object): +class Rest: """Simple internal class to represent a musical rest note. Used in part with the TonePlayer class, this object represents a period of @@ -84,7 +89,7 @@ def __str__(self): return self.name + str(self.octave) -class TonePlayer(object): +class TonePlayer: """Class to play a simplified music notation via a PWMController. This class makes use of a very simple music notation to play simple musical @@ -100,7 +105,7 @@ class TonePlayer(object): w: whole note h: half note q: quarter note (the default -- if you don't specify the length, we - assume quarter) + assume quarter) e: eighth note s: sixteenth note diff --git a/src/aiy/trackplayer.py b/aiy/trackplayer.py similarity index 98% rename from src/aiy/trackplayer.py rename to aiy/trackplayer.py index 0ea588d6..4e544407 100644 --- a/src/aiy/trackplayer.py +++ b/aiy/trackplayer.py @@ -12,18 +12,24 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Tracker-based music player for the piezo buzzer.""" +""" +A tracker-based music player for the piezo buzzer. + +This API is designed for the Vision Kit, but has no dependency on the Vision +Bonnet, so may be used without it. It only requires a piezo buzzer connected to +:any:`aiy.pins.BUZZER_GPIO_PIN`. +""" import math import re import time -from aiy._drivers._buzzer import PWMController -from aiy.toneplayer import Note +from .toneplayer import Note +from ._buzzer import PWMController -class Command(object): +class Command: """Base class for all commands.""" def apply(self, player, controller, note, tick_delta): @@ -244,7 +250,7 @@ def parse(klass, *args): return klass(), 0 -class TrackPlayer(object): +class TrackPlayer: """Plays a tracker-like song.""" def __init__(self, gpio, speed=3, debug=False): @@ -359,7 +365,7 @@ def play(self): controller.set_frequency(0) -class TrackLoader(object): +class TrackLoader: """Simple track module loader. This class, given a filename and a gpio will load and parse in the given diff --git a/aiy/util.py b/aiy/util.py new file mode 100644 index 00000000..61540da7 --- /dev/null +++ b/aiy/util.py @@ -0,0 +1,203 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import itertools +import queue +import threading +import time + +from collections import namedtuple + +from RPi import GPIO + +class Button: + """ An interface for the button connected to the AIY board's + button connector.""" + @staticmethod + def _trigger(event_queue, callback): + try: + while True: + event_queue.get_nowait().set() + except queue.Empty: + pass + + if callback: + callback() + + def _run(self): + when_pressed = 0.0 + pressed = False + while not self._done.is_set(): + now = time.monotonic() + if now - when_pressed > self._debounce_time: + if GPIO.input(self._channel) == self._expected: + if not pressed: + pressed = True + when_pressed = now + self._trigger(self._pressed_queue, self._pressed_callback) + else: + if pressed: + pressed = False + self._trigger(self._released_queue, self._released_callback) + self._done.wait(0.05) + + def __init__(self, channel, edge='falling', pull_up_down='up', + debounce_time=0.08): + if pull_up_down not in ('up', 'down'): + raise ValueError('Must be "up" or "down"') + + if edge not in ('falling', 'rising'): + raise ValueError('Must be "falling" or "rising"') + + self._channel = channel + GPIO.setmode(GPIO.BCM) + GPIO.setup(channel, GPIO.IN, + pull_up_down={'up': GPIO.PUD_UP, 'down': GPIO.PUD_DOWN}[pull_up_down]) + + self._pressed_callback = None + self._released_callback = None + + self._debounce_time = debounce_time + self._expected = True if edge == 'rising' else False + + self._pressed_queue = queue.Queue() + self._released_queue = queue.Queue() + + self._done = threading.Event() + self._thread = threading.Thread(target=self._run) + self._thread.start() + + def close(self): + """Internal method to clean up the object when done.""" + self._done.set() + self._thread.join() + GPIO.cleanup(self._channel) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, exc_tb): + self.close() + + def _when_pressed(self, callback): + self._pressed_callback = callback + when_pressed = property(None, _when_pressed) + """A function to run when the button is pressed.""" + + def _when_released(self, callback): + self._released_callback = callback + when_released = property(None, _when_released) + """A function to run when the button is released.""" + + def wait_for_press(self, timeout=None): + """Pauses the script until the button is pressed or the timeout is reached. + + Args: + timeout: Seconds to wait before proceeding. By default, this is ``None``, + which means wait indefinitely.""" + event = threading.Event() + self._pressed_queue.put(event) + return event.wait(timeout) + + def wait_for_release(self, timeout=None): + """Pauses the script until the button is released or the timeout is reached. + + Args: + timeout: Seconds to wait before proceeding. By default, this is ``None``, + which means wait indefinitely.""" + event = threading.Event() + self._released_queue.put(event) + return event.wait(timeout) + + +class Led: + Config = namedtuple('Config', ['duty_cycles', 'pause']) + + OFF = Config(duty_cycles=lambda: [0], pause=1.0) + ON = Config(duty_cycles=lambda: [100], pause=1.0) + BLINK = Config(duty_cycles=lambda: [0, 100], pause=0.5) + BLINK_3 = Config(duty_cycles=lambda: [0, 100] * 3 + [0, 0], + pause=0.25) + BEACON = Config(duty_cycles=lambda: itertools.chain([30] * 100, + [100] * 8, + range(100, 30, -5)), + pause=0.05) + BEACON_DARK = Config(duty_cycles=lambda: itertools.chain([0] * 100, + range(0, 30, 3), + range(30, 0, -3)), + pause=0.05) + DECAY = Config(duty_cycles=lambda: range(100, 0, -2), + pause=0.05) + PULSE_SLOW = Config(duty_cycles=lambda: itertools.chain(range(0, 100, 2), + range(100, 0, -2)), + pause=0.1) + PULSE_QUICK = Config(duty_cycles=lambda: itertools.chain(range(0, 100, 5), + range(100, 0, -5)), + pause=0.05) + + def _run(self): + while True: + try: + state = self._queue.get_nowait() + if state is None: + break + it = itertools.cycle(state.duty_cycles()) + except queue.Empty: + pass + + self._pwm.ChangeDutyCycle(int(self._brightness * next(it))) + self._updated.wait(state.pause) + self._updated.clear() + + def __init__(self, channel): + self._brightness = 1.0 # Read and written atomically. + self._channel = channel + self._queue = queue.Queue(maxsize=1) + self._queue.put(self.OFF) + self._updated = threading.Event() + + GPIO.setmode(GPIO.BCM) + GPIO.setup(channel, GPIO.OUT) + self._pwm = GPIO.PWM(channel, 100) + self._pwm.start(0) + + self._thread = threading.Thread(target=self._run) + self._thread.start() + + def close(self): + self._queue.put(None) + self._thread.join() + self._pwm.stop() + GPIO.cleanup(self._channel) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, exc_tb): + self.close() + + @property + def brightness(self): + return self._brightness + + @brightness.setter + def brightness(self, value): + if value < 0.0 or value > 1.0: + raise ValueError('Brightness must be between 0.0 and 1.0.') + self._brightness = value + + def _set_state(self, state): + self._queue.put(state) + self._updated.set() + state = property(None, _set_state) diff --git a/src/aiy/_drivers/__init__.py b/aiy/voice/__init__.py similarity index 100% rename from src/aiy/_drivers/__init__.py rename to aiy/voice/__init__.py diff --git a/aiy/voice/audio.py b/aiy/voice/audio.py new file mode 100644 index 00000000..0b46b3cd --- /dev/null +++ b/aiy/voice/audio.py @@ -0,0 +1,425 @@ +""" +APIs to record and play audio files. + +.. note:: + + These APIs are designed for the Voice Kit, but have no dependency on the Voice + HAT/Bonnet specifically. However, many of the APIs require some type of sound card + attached to the Raspberry Pi that can be detected by the ALSA subsystem. + +.. module:: aiy.voice.audio + +Recording +--------- + +.. autofunction:: arecord + +.. autofunction:: record_file + +.. autofunction:: record_file_async + +.. autoclass:: Recorder + :members: + :undoc-members: + :show-inheritance: + + +Playback +-------- + +.. autofunction:: aplay + +.. autofunction:: play_raw + +.. autofunction:: play_raw_async + +.. autofunction:: play_wav + +.. autofunction:: play_wav_async + +.. autoclass:: BytesPlayer + :members: + :undoc-members: + :show-inheritance: + :inherited-members: + +.. autoclass:: FilePlayer + :members: + :undoc-members: + :show-inheritance: + :inherited-members: + + +Audio format +------------ + +.. autofunction:: wave_set_format + +.. autofunction:: wave_get_format + +.. autoclass:: AudioFormat + :members: + :undoc-members: + :show-inheritance: + +""" + +import contextlib +import subprocess +import threading +import itertools +import wave + +from collections import namedtuple + +SUPPORTED_FILETYPES = ('wav', 'raw', 'voc', 'au') + + +class AudioFormat(namedtuple('AudioFormat', + ['sample_rate_hz', 'num_channels', 'bytes_per_sample'])): + @property + def bytes_per_second(self): + return self.sample_rate_hz * self.num_channels * self.bytes_per_sample + +AudioFormat.CD = AudioFormat(sample_rate_hz=44100, num_channels=2, bytes_per_sample=2) + + +def wave_set_format(wav_file, fmt): + """ + Sets the format for the given WAV file, using the given :class:`AudioFormat`. + + Args: + wav_file: A :class:`wave.Wave_write` object. + fmt: A :class:`AudioFormat` object. + """ + wav_file.setnchannels(fmt.num_channels) + wav_file.setsampwidth(fmt.bytes_per_sample) + wav_file.setframerate(fmt.sample_rate_hz) + + +def wave_get_format(wav_file): + """ + Returns the :class:`AudioFormat` corresponding to the WAV file provided. + + Args: + wav_file: A :class:`wave.Wave_read` object. + """ + return AudioFormat(sample_rate_hz=wav_file.getframerate(), + num_channels=wav_file.getnchannels(), + bytes_per_sample=wav_file.getsampwidth()) + + +def arecord(fmt, filetype='raw', filename=None, device='default'): + """Returns an ``arecord`` command-line command. + + Args: + fmt: The audio format; an instance of :class:`AudioFormat`. + filetype: The type of file. Must be either 'wav', 'raw', 'voc', or 'au'. + filename: The audio file to play. + device: The PCM device name. Leave as ``default`` to use the default ALSA soundcard. + """ + if fmt is None: + raise ValueError('Format must be specified for recording.') + + if filetype not in SUPPORTED_FILETYPES: + raise ValueError('File type must be %s.' % ', '.join(SUPPORTED_FILETYPES)) + + cmd = ['arecord', '-q', + '-D', device, + '-t', filetype, + '-c', str(fmt.num_channels), + '-f', 's%d' % (8 * fmt.bytes_per_sample), + '-r', str(fmt.sample_rate_hz)] + + if filename is not None: + cmd.append(filename) + + return cmd + + +def aplay(fmt, filetype='raw', filename=None, device='default'): + """Returns an ``aplay`` command-line command. + + Args: + fmt: The audio format; an instance of :class:`AudioFormat`. + filetype: The type of file. Must be either 'wav', 'raw', 'voc', or 'au'. + filename: The audio file to play. + device: The PCM device name. Leave as ``default`` to use the default ALSA soundcard. + """ + if filetype == 'raw' and fmt is None: + raise ValueError('Format must be specified for raw data.') + + cmd = ['aplay', '-q', + '-D', device, + '-t', filetype] + + if fmt is not None: + cmd.extend(['-c', str(fmt.num_channels), + '-f', 's%d' % (8 * fmt.bytes_per_sample), + '-r', str(fmt.sample_rate_hz)]) + + if filename is not None: + cmd.append(filename) + + return cmd + +def record_file_async(fmt, filename, filetype, device='default'): + """ + Records an audio file, asynchronously. To stop the recording, terminate the returned + :class:`~subprocess.Popen` object. + + Args: + fmt: The audio format; an instance of :class:`AudioFormat`. + filename: The file where the recording should be saved. + filetype: The type of file. Must be either 'wav', 'raw', 'voc', or 'au'. + device: The PCM device name. Leave as ``default`` to use the default ALSA soundcard. + + Returns: + The :class:`~subprocess.Popen` object for the subprocess in which audio is recording. + """ + if filename is None: + raise ValueError('Filename must be specified.') + + if filetype is None: + raise ValueError('Filetype must be specified.') + + cmd = arecord(fmt, filetype=filetype, filename=filename, device=device) + return subprocess.Popen(cmd) + + +def record_file(fmt, filename, filetype, wait, device='default'): + """ + Records an audio file (blocking). The length of the recording is determined by a + blocking ``wait`` function that you provide. When your ``wait`` function finishes, + so does this function and the recording. + + For an example, see :github:`src/examples/voice/voice_recorder.py`. + + Args: + fmt: The audio format; an instance of :class:`AudioFormat`. + filename: The file where the recording should be saved. + filetype: The type of file. Must be either 'wav', 'raw', 'voc', or 'au'. + wait: A blocking function that determines the length of the recording (and thus the + length of time that this function is blocking). + device: The PCM device name. Leave as ``default`` to use the default ALSA soundcard. + """ + if wait is None: + raise ValueError('Wait callback must be specified.') + + process = record_file_async(fmt, filename, filetype, device) + try: + wait() + finally: + process.terminate() + process.wait() + + +def play_wav_async(filename_or_data): + """ + Plays a WAV file or data asynchronously. + + Args: + filename_or_data: The WAV file or bytes to play. + + Returns: + The :class:`~subprocess.Popen` object for the subprocess in which audio is playing. + """ + if isinstance(filename_or_data, (bytes, bytearray)): + cmd = aplay(fmt=None, filetype='wav', filename=None) + process = subprocess.Popen(cmd, stdin=subprocess.PIPE) + process.stdin.write(filename_or_data) + return process + + if isinstance(filename_or_data, str): + cmd = aplay(fmt=None, filetype='wav', filename=filename_or_data) + return subprocess.Popen(cmd) + + raise ValueError('Must be filename or byte-like object') + + +def play_wav(filename_or_data): + """ + Plays a WAV file or data (blocking). + + Args: + filename_or_data: The WAV file or bytes to play. + """ + play_wav_async(filename_or_data).wait() + + +def play_raw_async(fmt, filename_or_data): + """ + Plays raw audio data asynchronously. + + Args: + fmt: The audio format; an instance of :class:`AudioFormat`. + filename_or_data: The file or bytes to play. + + Returns: + The :class:`~subprocess.Popen` object for the subprocess in which audio is playing. + """ + if isinstance(filename_or_data, (bytes, bytearray)): + cmd = aplay(fmt=fmt, filetype='raw') + process = subprocess.Popen(cmd, stdin=subprocess.PIPE) + process.stdin.write(filename_or_data) + return process + + if isinstance(filename_or_data, str): + cmd = aplay(fmt=fmt, filetype='raw', filename=filename_or_data) + return subprocess.Popen(cmd) + + raise ValueError('Must be filename or byte-like object') + + +def play_raw(fmt, filename_or_data): + """ + Plays raw audio data (blocking). + + Args: + fmt: The audio format; an instance of :class:`AudioFormat`. + filename_or_data: The file or bytes to play. + """ + play_raw_async(fmt, filename_or_data).wait() + + +class Recorder: + + def __init__(self, ): + self._process = None + self._done = threading.Event() + self._started = threading.Event() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, exc_tb): + self.join() + + def record(self, fmt, chunk_duration_sec, device='default', + num_chunks=None, + on_start=None, on_stop=None, filename=None): + """ + Records audio with the ALSA soundcard driver, via ``arecord``. + + Args: + fmt: The audio format; an instance of :class:`AudioFormat`. + chunk_duration_sec: The duration of each audio chunk, in seconds (may be float). + device: The PCM device name. Leave as ``default`` to use the default ALSA soundcard. + num_chunks: The number of chunks to record. Leave as ``None`` to instead record + indefinitely, until you call :meth:`~Recorder.done`. + on_start: A function callback to call when recording starts. + on_stop: A function callback to call when recording stops. + filename: A filename to use if you want to save the recording as a WAV file. + Yields: + A chunk of audio data. Each chunk size = ``chunk_duraction_sec * fmt.bytes_per_second`` + """ + + chunk_size = int(chunk_duration_sec * fmt.bytes_per_second) + cmd = arecord(fmt=fmt, device=device) + + wav_file = None + if filename: + wav_file = wave.open(filename, 'wb') + wave_set_format(wav_file, fmt) + + self._process = subprocess.Popen(cmd, stdout=subprocess.PIPE) + self._started.set() + if on_start: + on_start() + try: + for _ in (range(num_chunks) if num_chunks else itertools.count()): + if self._done.is_set(): + break + data = self._process.stdout.read(chunk_size) + if not data: + break + if wav_file: + wav_file.writeframes(data) + yield data + finally: + self._process.stdout.close() + if on_stop: + on_stop() + if wav_file: + wav_file.close() + + def done(self): + """ + Stops the recording that started via :meth:`~Recorder.record`. + """ + self._done.set() + + def join(self): + self._started.wait() + self._process.wait() + + + +class Player: + def __init__(self): + self._process = None + self._started = threading.Event() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, exc_tb): + self.join() + + def _popen(self, cmd, **kwargs): + self._process = subprocess.Popen(cmd, **kwargs) + self._started.set() + return self._process + + def join(self): + self._started.wait() + self._process.wait() + + +class FilePlayer(Player): + """ + Plays audio from a file. + """ + def play_raw(self, fmt, filename, device='default'): + """ + Plays a raw audio file. + + Args: + fmt: The audio format; an instance of :class:`AudioFormat`. + filename: The audio file to play. + device: The PCM device name. Leave as ``default`` to use the default ALSA soundcard. + """ + self._popen(aplay(fmt=fmt, filetype='raw', filename=filename, device=device)) + + + def play_wav(self, filename, device='default'): + """ + Plays a WAV file. + + Args: + filename: The WAV file to play. + device: The PCM device name. Leave as ``default`` to use the default ALSA soundcard. + """ + self._popen(aplay(fmt=None, filetype='wav', filename=filename, device=device)) + +class BytesPlayer(Player): + """ + Plays audio from a given byte data source. + """ + def play(self, fmt, device='default'): + """ + Args: + fmt: The audio format; an instance of :class:`AudioFormat`. + device: The PCM device name. Leave as ``default`` to use the default ALSA soundcard. + + Returns: + A closure with an inner function ``push()`` that accepts the byte data. + """ + process = self._popen(aplay(fmt=fmt, filetype='raw', device=device), stdin=subprocess.PIPE) + + def push(data): + if data: + process.stdin.write(data) + else: + process.stdin.close() + return push diff --git a/aiy/voice/tts.py b/aiy/voice/tts.py new file mode 100644 index 00000000..458a0fef --- /dev/null +++ b/aiy/voice/tts.py @@ -0,0 +1,72 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +An API that performs text-to-speech. + +You can also use this to perform text-to-speech from the command line:: + + python ~/AIY-projects-python/src/aiy/voice/tts.py "hello world" + +""" + +import argparse +import os +import subprocess +import tempfile + +RUN_DIR = '/run/user/%d' % os.getuid() + +def say(text, lang='en-US', volume=60, pitch=130, speed=100, device='default'): + """ + Speaks the provided text. + + Args: + text: The text you want to speak. + lang: The language to use. Supported languages are: + en-US, en-GB, de-DE, es-ES, fr-FR, it-IT. + volume: Volume level for the converted audio. The normal volume level is + 100. Valid volume levels are between 0 (no audible output) and 500 (increasing the + volume by a factor of 5). Values higher than 100 might result in degraded signal + quality due to saturation effects (clipping) and is not recommended. To instead adjust + the volume output of your device, enter ``alsamixer`` at the command line. + pitch: The pitch level for the voice. The normal pitch level is 100, the allowed values lie + between 50 (one octave lower) and 200 (one octave higher). + speed: The speed of the voice. The normal speed level is 100, the allowed values lie + between 20 (slowing down by a factor of 5) and 500 (speeding up by a factor of 5). + device: The PCM device name. Leave as ``default`` to use the default ALSA soundcard. + """ + data = "%s" % \ + (volume, pitch, speed, text) + with tempfile.NamedTemporaryFile(suffix='.wav', dir=RUN_DIR) as f: + cmd = 'pico2wave --wave %s --lang %s "%s" && aplay -q -D %s %s' % \ + (f.name, lang, data, device, f.name) + subprocess.check_call(cmd, shell=True) + + +def _main(): + parser = argparse.ArgumentParser(description='Text To Speech (pico2wave)') + parser.add_argument('--lang', default='en-US') + parser.add_argument('--volume', type=int, default=60) + parser.add_argument('--pitch', type=int, default=130) + parser.add_argument('--speed', type=int, default=100) + parser.add_argument('--device', default='default') + parser.add_argument('text', help='path to disk image file ') + args = parser.parse_args() + say(args.text, lang=args.lang, volume=args.volume, pitch=args.pitch, speed=args.speed, + device=args.device) + + +if __name__ == '__main__': + _main() diff --git a/checkpoints/check_audio.py b/checkpoints/check_audio.py deleted file mode 100755 index 8f677a23..00000000 --- a/checkpoints/check_audio.py +++ /dev/null @@ -1,184 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Check that the voiceHAT audio input and output are both working.""" - - -import fileinput -import os -import re -import subprocess -import sys -import tempfile -import textwrap -import traceback - -import aiy.audio # noqa -from aiy._drivers._hat import get_aiy_device_name - -AIY_PROJECTS_DIR = os.path.dirname(os.path.dirname(__file__)) - -CARDS_PATH = '/proc/asound/cards' -CARDS_ID = { - "Voice Hat": "googlevoicehat", - "Voice Bonnet": "aiy-voicebonnet", -} - -STOP_DELAY = 1.0 - -TEST_SOUND_PATH = '/usr/share/sounds/alsa/Front_Center.wav' - -RECORD_DURATION_SECONDS = 3 - - -def get_sound_cards(): - """Read a dictionary of ALSA cards from /proc, indexed by number.""" - cards = {} - - with open(CARDS_PATH) as f: # pylint: disable=invalid-name - for line in f.read().splitlines(): - try: - index = int(line.strip().split()[0]) - except (IndexError, ValueError): - continue - - cards[index] = line - - return cards - - -def ask(prompt): - """Get a yes or no answer from the user.""" - ans = input(prompt + ' (y/n) ') - - while not ans or ans[0].lower() not in 'yn': - ans = input('Please enter y or n: ') - - return ans[0].lower() == 'y' - - -def check_voicehat_present(): - """Check that the voiceHAT audio driver is present.""" - card_id = CARDS_ID[get_aiy_device_name()] - return any(card_id in card for card in get_sound_cards().values()) - - -def check_voicehat_is_first_card(): - """Check that the voiceHAT is the first card on the system.""" - cards = get_sound_cards() - card_id = CARDS_ID[get_aiy_device_name()] - return 0 in cards and card_id in cards[0] - - -def check_asoundrc_is_not_bad(): - """Check that ~/.asoundrc is absent or has the AIY config.""" - asoundrc = os.path.expanduser('~/.asoundrc') - if not os.path.exists(asoundrc): - return True - - with open(os.path.join(AIY_PROJECTS_DIR, 'scripts', 'asound.conf')) as f: - wanted_contents = f.read() - with open(asoundrc) as f: - contents = f.read() - - return contents == wanted_contents - - -def check_speaker_works(): - """Check the speaker makes a sound.""" - print('Playing a test sound...') - aiy.audio.play_wave(TEST_SOUND_PATH) - - return ask('Did you hear the test sound?') - - -def check_mic_works(): - """Check the microphone records correctly.""" - temp_file, temp_path = tempfile.mkstemp(suffix='.wav') - os.close(temp_file) - - try: - input("When you're ready, press enter and say 'Testing, 1 2 3'...") - print('Recording...') - aiy.audio.record_to_wave(temp_path, RECORD_DURATION_SECONDS) - print('Playing back recorded audio...') - aiy.audio.play_wave(temp_path) - finally: - try: - os.unlink(temp_path) - except FileNotFoundError: - pass - - return ask('Did you hear your own voice?') - - -def do_checks(): - """Run all audio checks and print status.""" - if not check_voicehat_present(): - print(textwrap.fill( - """Failed to find the voiceHAT soundcard. Refer to HACKING.md for -how to setup the voiceHAT driver: https://git.io/v99yK""")) - return - - if not check_voicehat_is_first_card(): - print(textwrap.fill( - """The voiceHAT not the first sound device, so the voice recognizer -may be unable to find it. Please try removing other sound drivers.""")) - return - - try: - if not check_speaker_works(): - print(textwrap.fill( - """There may be a problem with your speaker. Check that it's -connected properly.""")) - return - except BrokenPipeError: - # aplay crashed - check if ~/.asoundrc is the culprit - if not check_asoundrc_is_not_bad(): - print(textwrap.fill( - """~/.asoundrc exists, and it doesn't have the expected -contents. Try deleting it with `rm ~/.asoundrc`.""")) - else: - print("aplay crashed - try checking your ALSA config.") - return - - if not check_mic_works(): - print(textwrap.fill( - """There may be a problem with your microphone. Check that it's -connected properly.""")) - return - - print('The audio seems to be working.') - - -def enable_audio_driver(): - print("Enabling audio driver for VoiceKit.") - configure_driver = os.path.join(AIY_PROJECTS_DIR, 'scripts', 'configure-driver.sh') - subprocess.check_call(['sudo', configure_driver]) - - -def main(): - if get_aiy_device_name() == 'Voice Hat': - enable_audio_driver() - do_checks() - - -if __name__ == '__main__': - try: - main() - input('Press Enter to close...') - except Exception: # pylint: disable=W0703 - traceback.print_exc() - input('Press Enter to close...') diff --git a/checkpoints/check_cloud.py b/checkpoints/check_cloud.py deleted file mode 100755 index 6e301e96..00000000 --- a/checkpoints/check_cloud.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Check that the Cloud Speech API can be used.""" - -import json -import os -import os.path -import sys -import traceback - -sys.path.append(os.path.realpath(os.path.join(__file__, '..', '..')) + '/src/') - -import aiy._apis._speech # noqa - -OLD_CREDENTIALS_FILE = os.path.expanduser('~/credentials.json') -NEW_CREDENTIALS_FILE = os.path.expanduser('~/cloud_speech.json') -if os.path.exists(OLD_CREDENTIALS_FILE): - # Legacy fallback: old location of credentials. - CREDENTIALS_PATH = OLD_CREDENTIALS_FILE -else: - CREDENTIALS_PATH = NEW_CREDENTIALS_FILE - -ROOT_PATH = os.path.realpath(os.path.join(__file__, '..', '..')) -PYTHON3 = ROOT_PATH + '/env/bin/python3' -SPEECH_PY = ROOT_PATH + '/src/aiy/_apis/_speech.py' -SPEECH_PY_ENV = { - 'VIRTUAL_ENV': ROOT_PATH + '/env', - 'PATH': ROOT_PATH + '/env/bin:' + os.getenv('PATH'), -} -TEST_AUDIO = ROOT_PATH + '/checkpoints/test_hello.raw' -RECOGNIZED_TEXT = 'hello' - - -def check_credentials_valid(): - """Check the credentials are JSON service credentials.""" - try: - obj = json.load(open(CREDENTIALS_PATH)) - except ValueError: - return False - - return 'type' in obj and obj['type'] == 'service_account' - - -def check_speech_reco(): - """Try to test the speech recognition code from AIY APIs.""" - print('Testing the Google Cloud Speech API...') - req = aiy._apis._speech.CloudSpeechRequest(CREDENTIALS_PATH) - with open(TEST_AUDIO, 'rb') as f: - while True: - chunk = f.read(64000) - if not chunk: - break - req.add_data(chunk) - req.end_audio() - output = req.do_request() - - if RECOGNIZED_TEXT in output: - return True - - print('Speech recognition failed or output not as expected:') - print(output) - print('Expected:', RECOGNIZED_TEXT) - return False - - -def main(): - """Run all checks and print status.""" - if not os.path.exists(CREDENTIALS_PATH): - print( - """Please follow these instructions to get Google Cloud credentials: -https://cloud.google.com/speech/docs/getting-started#set_up_your_project -and save them to""", CREDENTIALS_PATH) - return - - if not check_credentials_valid(): - print( - CREDENTIALS_PATH, """is not valid, please check that you have downloaded JSON -service credentials.""") - return - - if not check_speech_reco(): - print('Failed to test the Cloud Speech API. Please see error above.') - return - - print("Everything's set up to use the Google Cloud.") - - -if __name__ == '__main__': - try: - main() - input('Press Enter to close...') - except Exception: - traceback.print_exc() - input('Press Enter to close...') diff --git a/checkpoints/check_wifi.py b/checkpoints/check_wifi.py deleted file mode 100755 index 3ec89702..00000000 --- a/checkpoints/check_wifi.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Check that the WiFi is working.""" - -import socket -import subprocess -import traceback - -WPA_CONF_PATH = '/etc/wpa_supplicant/wpa_supplicant.conf' -GOOGLE_SERVER_ADDRESS = ('speech.googleapis.com', 443) - - -def check_wifi_is_configured(): - """Check wpa_supplicant.conf has at least one network configured.""" - output = subprocess.check_output(['sudo', 'cat', WPA_CONF_PATH]).decode('utf-8') - - return 'network=' in output - - -def check_wifi_is_connected(): - """Check wlan0 has an IP address.""" - output = subprocess.check_output(['ifconfig', 'wlan0']).decode('utf-8') - - return 'inet ' in output - - -def check_can_reach_google_server(): - """Check the API server is reachable on port 443.""" - print("Trying to contact Google's servers...") - try: - sock = socket.create_connection(GOOGLE_SERVER_ADDRESS, timeout=10) - sock.close() - return True - except Exception: # pylint: disable=W0703 - return False - - -def main(): - """Run all checks and print status.""" - print('Checking the WiFi connection...') - - if not check_wifi_is_configured(): - print('Please click the WiFi icon at the top right to set up a WiFi network.') - return - - if not check_wifi_is_connected(): - print( - """You are not connected to WiFi. Please click the WiFi icon at the top right -to check your settings.""") - return - - if not check_can_reach_google_server(): - print( - """Failed to reach Google servers. Please check that your WiFi network is -connected to the internet.""") - return - - print('The WiFi connection seems to be working.') - - -if __name__ == '__main__': - try: - main() - input('Press Enter to close...') - except Exception: - traceback.print_exc() - input('Press Enter to close...') diff --git a/checkpoints/test_hello.raw b/checkpoints/test_hello.raw deleted file mode 100644 index 42538f81..00000000 Binary files a/checkpoints/test_hello.raw and /dev/null differ diff --git a/examples/button_led.py b/examples/button_led.py new file mode 100644 index 00000000..b22df6f7 --- /dev/null +++ b/examples/button_led.py @@ -0,0 +1,16 @@ +from aiy.util import Led, Button + +def main(): + print('LED is ON while button is pressed (Ctrl-C for exit).') + with Led(channel=17) as led, Button(channel=27) as button: + while True: + button.wait_for_press() + print('ON') + led.state = Led.ON + button.wait_for_release() + print('OFF') + led.state = Led.OFF + + +if __name__ == '__main__': + main() diff --git a/src/examples/vision/buzzer/buzzer_demo.py b/examples/buzzer/buzzer_demo.py old mode 100755 new mode 100644 similarity index 100% rename from src/examples/vision/buzzer/buzzer_demo.py rename to examples/buzzer/buzzer_demo.py diff --git a/src/examples/vision/buzzer/buzzer_tracker_demo.py b/examples/buzzer/buzzer_tracker_demo.py old mode 100755 new mode 100644 similarity index 100% rename from src/examples/vision/buzzer/buzzer_tracker_demo.py rename to examples/buzzer/buzzer_tracker_demo.py diff --git a/src/examples/vision/buzzer/congratulations.track b/examples/buzzer/congratulations.track similarity index 100% rename from src/examples/vision/buzzer/congratulations.track rename to examples/buzzer/congratulations.track diff --git a/src/examples/vision/buzzer/dramatic.track b/examples/buzzer/dramatic.track similarity index 100% rename from src/examples/vision/buzzer/dramatic.track rename to examples/buzzer/dramatic.track diff --git a/src/examples/vision/buzzer/laughing.track b/examples/buzzer/laughing.track similarity index 100% rename from src/examples/vision/buzzer/laughing.track rename to examples/buzzer/laughing.track diff --git a/src/examples/vision/buzzer/sadtrombone.track b/examples/buzzer/sadtrombone.track similarity index 100% rename from src/examples/vision/buzzer/sadtrombone.track rename to examples/buzzer/sadtrombone.track diff --git a/src/examples/vision/buzzer/tetris.track b/examples/buzzer/tetris.track similarity index 100% rename from src/examples/vision/buzzer/tetris.track rename to examples/buzzer/tetris.track diff --git a/examples/voice/README.md b/examples/voice/README.md new file mode 100644 index 00000000..79451845 --- /dev/null +++ b/examples/voice/README.md @@ -0,0 +1,84 @@ +# Google Assistant and Cloud Speech Examples + +To fully experience the interactions, you need an **LED** (+resistor) and a +**button**. The LED is for conveying the machine's "state of mind". The button +is to trigger the machine to listen, for cases where you don't want it to be +bothered by noises. Not all examples require a button. + +I suggest you try the examples in the following order: + +1. **assistant_library_demo.py** + + **Required credential file:** `/home/pi/assistant.json` + + **LED:** short end to ground, long end to GPIO 17 + + **Run:** `python3 assistant_library_demo.py` + + **Usage:** Say "OK, Google", ask it a question, then listen to its responses. + Notice how the LED changes. + +2. **assistant_library_with_local_commands_demo.py** + + **Required credential file:** `/home/pi/assistant.json` + + **LED:** short end to ground, long end to GPIO 17 + + **Run:** `python3 assistant_library_with_local_commands_demo.py` + + **Usage:** Say "OK, Google", converse as before, or say one of these commands: + + - "Power off": supposed to shutdown the pi, but I have commented out the + actual shutdown system call + + - "Reboot": supposed to reboot the pi, but I have commented out the actual + reboot system call + + - "IP address": tells the internal IP address + + These commands use the `aiy.voice.tts` module (which in turn uses the Pico + text-to-speech engine) to generate verbal responses. You can obviously hear + the difference. + + `sudo apt-get install libttspico-utils` to install Pico if you haven't done + so already. + +3. **assistant_grpc_demo.py** + + **Required credential file:** `/home/pi/assistant.json` + + **LED:** short end to ground, long end to GPIO 17 + + **Button:** one end to ground, one end to GPIO 27 + + **Run:** `python3 assistant_grpc_demo.py --language en-US`. If you don't + supply the language, it assumes the Pi's default language, which may not be + supported. + + **Usage:** Press the button before speaking. Ask some questions. + +4. **cloudspeech_demo.py** + + This one uses Google Cloud Speech, only able to recognize speech, but + provide no verbal response. + + **Required credential file:** `/home/pi/cloud_speech.json` + + **LED:** short end to ground, long end to GPIO 17 + + **Run:** `python3 cloudspeech_demo.py` + + **Usage:** Say something to see it translate, or say one of the commands and + notice how the LED changes: + + - "Turn on the light" + + - "Turn off the light" + + - "Blink the light" + + Say "Goodbye" to exit. + + **Cantonese**: `python3 cloudspeech_demo.py --language yue-Hant-HK` and try + to modify the code to make it respond to 開燈, 熄燈, 關燈, 閃燈, 眨燈, 拜拜, + 再見. diff --git a/examples/voice/assistant_grpc_demo.py b/examples/voice/assistant_grpc_demo.py new file mode 100644 index 00000000..d4e29970 --- /dev/null +++ b/examples/voice/assistant_grpc_demo.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""A demo of the Google Assistant GRPC recognizer.""" + +import argparse +import locale +import logging +import signal +import sys + +from aiy.assistant.grpc import AssistantServiceClientWithLed +from aiy.util import Led, Button + +def volume(string): + value = int(string) + if value < 0 or value > 100: + raise argparse.ArgumentTypeError('Volume must be in [0...100] range.') + return value + +def locale_language(): + language, _ = locale.getdefaultlocale() + return language + +def main(): + logging.basicConfig(level=logging.DEBUG) + signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit(0)) + + parser = argparse.ArgumentParser(description='Assistant service example.') + parser.add_argument('--language', default=locale_language()) + parser.add_argument('--volume', type=volume, default=100) + args = parser.parse_args() + + with Led(channel=17) as led, Button(channel=27) as button: + assistant = AssistantServiceClientWithLed(led=led, + volume_percentage=args.volume, + language_code=args.language) + while True: + logging.info('Press button to start conversation...') + button.wait_for_press() + logging.info('Conversation started!') + assistant.conversation() + +if __name__ == '__main__': + main() diff --git a/src/examples/voice/assistant_library_demo.py b/examples/voice/assistant_library_demo.py old mode 100755 new mode 100644 similarity index 57% rename from src/examples/voice/assistant_library_demo.py rename to examples/voice/assistant_library_demo.py index 1d079b62..46f1af76 --- a/src/examples/voice/assistant_library_demo.py +++ b/examples/voice/assistant_library_demo.py @@ -13,60 +13,58 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Run a recognizer using the Google Assistant Library. +"""Activates the Google Assistant with hotword detection, using the Google Assistant Library. The Google Assistant Library has direct access to the audio API, so this Python -code doesn't need to record audio. Hot word detection "OK, Google" is supported. +code doesn't need to record audio. -It is available for Raspberry Pi 2/3 only; Pi Zero is not supported. +.. note: + + This example depends on hotword detection (such as "Okay Google") to activate the Google + Assistant, which is supported only with Raspberry Pi 2/3. If you're using a Pi Zero, this + code won't work. Instead, you must use the button or another type of trigger, as shown + in assistant_library_with_button_demo.py. """ import logging import platform import sys -import aiy.assistant.auth_helpers -from aiy.assistant.library import Assistant -import aiy.voicehat from google.assistant.library.event import EventType -logging.basicConfig( - level=logging.INFO, - format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s" -) +from aiy.assistant import auth_helpers +from aiy.assistant.library import Assistant +from aiy.util import Led +def process_event(led, event): + logging.info(event) -def process_event(event): - status_ui = aiy.voicehat.get_status_ui() if event.type == EventType.ON_START_FINISHED: - status_ui.status('ready') - if sys.stdout.isatty(): - print('Say "OK, Google" then speak, or press Ctrl+C to quit...') + led.state = Led.BEACON_DARK # Ready. + logging.info('Say "OK, Google" then speak, or press Ctrl+C to quit...') elif event.type == EventType.ON_CONVERSATION_TURN_STARTED: - status_ui.status('listening') + led.state = Led.ON # Listening. elif event.type == EventType.ON_END_OF_UTTERANCE: - status_ui.status('thinking') + led.state = Led.PULSE_QUICK # Thinking. elif (event.type == EventType.ON_CONVERSATION_TURN_FINISHED or event.type == EventType.ON_CONVERSATION_TURN_TIMEOUT or event.type == EventType.ON_NO_RESPONSE): - status_ui.status('ready') + led.state = Led.BEACON_DARK elif event.type == EventType.ON_ASSISTANT_ERROR and event.args and event.args['is_fatal']: sys.exit(1) def main(): - if platform.machine() == 'armv6l': - print('Cannot run hotword demo on Pi Zero!') - exit(-1) + logging.basicConfig(level=logging.INFO) - credentials = aiy.assistant.auth_helpers.get_assistant_credentials() - with Assistant(credentials) as assistant: + credentials = auth_helpers.get_assistant_credentials() + with Led(channel=17) as led, Assistant(credentials) as assistant: for event in assistant.start(): - process_event(event) + process_event(led, event) if __name__ == '__main__': diff --git a/src/examples/voice/assistant_library_with_local_commands_demo.py b/examples/voice/assistant_library_with_local_commands_demo.py old mode 100755 new mode 100644 similarity index 68% rename from src/examples/voice/assistant_library_with_local_commands_demo.py rename to examples/voice/assistant_library_with_local_commands_demo.py index 837f7a8a..f40c1afd --- a/src/examples/voice/assistant_library_with_local_commands_demo.py +++ b/examples/voice/assistant_library_with_local_commands_demo.py @@ -26,43 +26,35 @@ import subprocess import sys -import aiy.assistant.auth_helpers -from aiy.assistant.library import Assistant -import aiy.audio -import aiy.voicehat from google.assistant.library.event import EventType -logging.basicConfig( - level=logging.INFO, - format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s" -) - +from aiy.assistant import auth_helpers +from aiy.assistant.library import Assistant +from aiy.util import Led +from aiy.voice import tts def power_off_pi(): - aiy.audio.say('Good bye!') - subprocess.call('sudo shutdown now', shell=True) + tts.say('Good bye!') + # subprocess.call('sudo shutdown now', shell=True) def reboot_pi(): - aiy.audio.say('See you in a bit!') - subprocess.call('sudo reboot', shell=True) + tts.say('See you in a bit!') + # subprocess.call('sudo reboot', shell=True) def say_ip(): ip_address = subprocess.check_output("hostname -I | cut -d' ' -f1", shell=True) - aiy.audio.say('My IP address is %s' % ip_address.decode('utf-8')) + tts.say('My IP address is %s' % ip_address.decode('utf-8')) -def process_event(assistant, event): - status_ui = aiy.voicehat.get_status_ui() +def process_event(assistant, led, event): + logging.info(event) if event.type == EventType.ON_START_FINISHED: - status_ui.status('ready') - if sys.stdout.isatty(): - print('Say "OK, Google" then speak, or press Ctrl+C to quit...') - + led.state = Led.BEACON_DARK # Ready. + print('Say "OK, Google" then speak, or press Ctrl+C to quit...') elif event.type == EventType.ON_CONVERSATION_TURN_STARTED: - status_ui.status('listening') - + led.state = Led.ON # Listening. elif event.type == EventType.ON_RECOGNIZING_SPEECH_FINISHED and event.args: print('You said:', event.args['text']) text = event.args['text'].lower() @@ -75,28 +67,23 @@ def process_event(assistant, event): elif text == 'ip address': assistant.stop_conversation() say_ip() - elif event.type == EventType.ON_END_OF_UTTERANCE: - status_ui.status('thinking') - + led.state = Led.PULSE_QUICK # Thinking. elif (event.type == EventType.ON_CONVERSATION_TURN_FINISHED or event.type == EventType.ON_CONVERSATION_TURN_TIMEOUT or event.type == EventType.ON_NO_RESPONSE): - status_ui.status('ready') - + led.state = Led.BEACON_DARK # Ready. elif event.type == EventType.ON_ASSISTANT_ERROR and event.args and event.args['is_fatal']: sys.exit(1) def main(): - if platform.machine() == 'armv6l': - print('Cannot run hotword demo on Pi Zero!') - exit(-1) + logging.basicConfig(level=logging.INFO) - credentials = aiy.assistant.auth_helpers.get_assistant_credentials() - with Assistant(credentials) as assistant: + credentials = auth_helpers.get_assistant_credentials() + with Led(channel=17) as led, Assistant(credentials) as assistant: for event in assistant.start(): - process_event(assistant, event) + process_event(assistant, led, event) if __name__ == '__main__': diff --git a/examples/voice/cloudspeech_demo.py b/examples/voice/cloudspeech_demo.py new file mode 100644 index 00000000..8e941f91 --- /dev/null +++ b/examples/voice/cloudspeech_demo.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""A demo of the Google CloudSpeech recognizer.""" +import argparse +import locale +import logging + +from aiy.util import Led +from aiy.cloudspeech import CloudSpeechClient + + +def get_hints(language_code): + if language_code.startswith('en_'): + return ('turn on the light', + 'turn off the light', + 'blink the light', + 'goodbye') + return None + +def locale_language(): + language, _ = locale.getdefaultlocale() + return language + +def main(): + logging.basicConfig(level=logging.DEBUG) + + parser = argparse.ArgumentParser(description='Assistant service example.') + parser.add_argument('--language', default=locale_language()) + args = parser.parse_args() + + logging.info('Initializing for language %s...', args.language) + hints = get_hints(args.language) + client = CloudSpeechClient() + with Led(channel=17) as led: + while True: + if hints: + logging.info('Say something, e.g. %s.' % ', '.join(hints)) + else: + logging.info('Say something.') + text = client.recognize(language_code=args.language, + hint_phrases=hints) + if text is None: + logging.info('You said nothing.') + continue + + logging.info('You said: "%s"' % text) + text = text.lower() + if 'turn on the light' in text: + led.state = Led.ON + elif 'turn off the light' in text: + led.state = Led.OFF + elif 'blink the light' in text: + led.state = Led.BLINK + elif 'goodbye' in text: + break + +if __name__ == '__main__': + main() diff --git a/examples/voice/voice_recorder.py b/examples/voice/voice_recorder.py new file mode 100644 index 00000000..ef564a7c --- /dev/null +++ b/examples/voice/voice_recorder.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import time +import threading + +from aiy.util import Button +from aiy.voice.audio import AudioFormat, play_wav, record_file, Recorder + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--filename', '-f', default='recording.wav') + args = parser.parse_args() + + with Button(channel=27) as button: + print('Press button to start recording.') + button.wait_for_press() + + done = threading.Event() + button.when_pressed = done.set + + def wait(): + start = time.monotonic() + while not done.is_set(): + duration = time.monotonic() - start + print('Recording: %.02f seconds [Press button to stop]' % duration) + time.sleep(0.5) + + record_file(AudioFormat.CD, filename=args.filename, wait=wait, filetype='wav') + print('Press button to play recorded sound.') + button.wait_for_press() + + print('Playing...') + play_wav(args.filename) + print('Done.') + +if __name__ == '__main__': + main() diff --git a/make_dpkg.sh b/make_dpkg.sh deleted file mode 100755 index 0a8f07da..00000000 --- a/make_dpkg.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -# set -x -set -e - -SCRIPT_DIR=$(dirname $(readlink -f $0)) -WORK_DIR=$(mktemp -d) - - -mkdir -p ${WORK_DIR}/aiy-projects-python-0.1/opt/aiy/ -git worktree add --detach ${WORK_DIR}/aiy-projects-python-0.1/debian origin/debian -git worktree add --detach ${WORK_DIR}/aiy-projects-python-0.1/projects-python origin/aiyprojects - -# Copy aiyprojects and set remote to github. -AIY_PYTHON_DIR=${WORK_DIR}/aiy-projects-python-0.1/projects-python -rm -f ${AIY_PYTHON_DIR}/.git -if [ -d ${AIY_PYTHON_DIR}/.git ]; then - rsync -rL --exclude=.git/shallow ${SCRIPT_DIR}/.git ${AIY_PYTHON_DIR} -else - cp -r ${SCRIPT_DIR}/../.git/modules/aiy-projects-python ${AIY_PYTHON_DIR}/.git -fi -ls -la ${AIY_PYTHON_DIR}/.git/ -sed -i '/\tworktree =/d' ${AIY_PYTHON_DIR}/.git/config -git -C ${AIY_PYTHON_DIR} checkout aiyprojects -for BRANCH in $(git -C ${AIY_PYTHON_DIR} branch | sed 's/\*//'); do - if [[ "$BRANCH" != "aiyprojects" ]]; then - git -C ${AIY_PYTHON_DIR} branch -D ${BRANCH} - fi -done -git -C ${AIY_PYTHON_DIR} remote remove origin | true -git -C ${AIY_PYTHON_DIR} remote add origin \ - https://github.com/google/aiyprojects-raspbian - -pushd ${WORK_DIR}/aiy-projects-python-0.1 -tar cf ${WORK_DIR}/aiy-projects-python_0.1.orig.tar.xz projects-python -# tar tf ${WORK_DIR}/aiy-projects-python_0.1.orig.tar.xz -find . - -debuild --no-lintian -us -uc - -cp ${WORK_DIR}/aiy-projects-python_0.1-0_all.deb ${SCRIPT_DIR} -rm -rf ${WORK_DIR} -popd -git worktree prune diff --git a/po/de.po b/po/de.po deleted file mode 100644 index db130ddf..00000000 --- a/po/de.po +++ /dev/null @@ -1,127 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: voice-recognizer-1.0\n" -"POT-Creation-Date: 2017-04-21 14:33+CEST\n" -"PO-Revision-Date: 2017-02-16 09:26+0100\n" -"Last-Translator: Stefan Sauer \n" -"Language-Team: \n" -"Language: de\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: pygettext.py 1.5\n" -"X-Generator: Poedit 1.5.4\n" - -#: src/action.py:172 -msgid "Volume at %d %%." -msgstr "Lautstärke auf %d %%." - -#: src/action.py:202 -msgid "ip address" -msgstr "IP Adresse" - -#: src/action.py:204 -msgid "I do not have an ip address assigned to me." -msgstr "Ich habe keine IP Adresse zugewiesen bekommen." - -#: src/action.py:206 -msgid "volume up" -msgstr "Lautstärke hoch" - -#: src/action.py:207 -msgid "volume down" -msgstr "Lautstärke runter" - -#: src/action.py:208 -msgid "max volume" -msgstr "volle Lautstärke" - -#: src/action.py:210 src/action.py:211 -msgid "repeat after me" -msgstr "sprich mir nach" - -#: src/action.py:225 -msgid "We've been friends since we were both starter projects" -msgstr "Da wir beide ganz neu sind, verstehen wir uns prima." - -#: src/action.py:229 -msgid "clap" -msgstr "klatsche" - -#: src/action.py:229 -msgid "clap clap" -msgstr "klatsch klatsch" - -#: src/action.py:230 -msgid "She taught me everything I know." -msgstr "Sie hat mir alles im Leben beigebracht." - -#: src/action.py:231 -msgid "hello" -msgstr "Hallo" - -#: src/action.py:231 -msgid "hello to you too" -msgstr "Hallo auch zu dir" - -#: src/action.py:232 -msgid "tell me a joke" -msgstr "Erzähl mir einen Witz" - -#: src/action.py:233 -msgid "What do you call an alligator in a vest? An investigator." -msgstr "Was hat vier Beine und kann fliegen? Zwei Vögel." - -#: src/action.py:234 -msgid "three laws of robotics" -msgstr "" - -#: src/action.py:235 -msgid "" -"The laws of robotics are\n" -"0: A robot may not injure a human being or, through inaction, allow a human\n" -"being to come to harm.\n" -"1: A robot must obey orders given it by human beings except where such " -"orders\n" -"would conflict with the First Law.\n" -"2: A robot must protect its own existence as long as such protection does " -"not\n" -"conflict with the First or Second Law." -msgstr "" - -#: src/action.py:242 -msgid "A galaxy far, far, just kidding. I'm from Seattle." -msgstr "" -"Aus einer weit, weit entfernten Galaxie, Ach Quatsch ich komm aus Seattle." - -#: src/action.py:242 -msgid "where are you from" -msgstr "Woher kommst du" - -#: src/action.py:243 -msgid "A machine has no name" -msgstr "Eine Maschine hat keinen Namen." - -#: src/action.py:243 -msgid "your name" -msgstr "dein Name" - -#: src/action.py:245 -msgid "time" -msgstr "Zeit" - -#: src/main.py:279 -msgid "Unexpected error. Try again or check the logs." -msgstr "Unerwarteter Fehler. Probiere nocheinmal oder kontrolliere die Logs." - -#: src/main.py:292 -msgid "I don’t know how to answer that." -msgstr "Das weis ich nicht." - -#: src/main.py:295 -msgid "Could you try that again?" -msgstr "Bitte probiere es nocheinmal." diff --git a/po/de/LC_MESSAGES/voice-recognizer.mo b/po/de/LC_MESSAGES/voice-recognizer.mo deleted file mode 100644 index 0226877a..00000000 Binary files a/po/de/LC_MESSAGES/voice-recognizer.mo and /dev/null differ diff --git a/po/voice-recognizer.pot b/po/voice-recognizer.pot deleted file mode 100644 index 2bce8ab8..00000000 --- a/po/voice-recognizer.pot +++ /dev/null @@ -1,124 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR ORGANIZATION -# FIRST AUTHOR , YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2017-04-21 14:33+CEST\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: pygettext.py 1.5\n" - - -#: src/action.py:172 -msgid "Volume at %d %%." -msgstr "" - -#: src/action.py:202 -msgid "ip address" -msgstr "" - -#: src/action.py:204 -msgid "I do not have an ip address assigned to me." -msgstr "" - -#: src/action.py:206 -msgid "volume up" -msgstr "" - -#: src/action.py:207 -msgid "volume down" -msgstr "" - -#: src/action.py:208 -msgid "max volume" -msgstr "" - -#: src/action.py:210 src/action.py:211 -msgid "repeat after me" -msgstr "" - -#: src/action.py:225 -msgid "We've been friends since we were both starter projects" -msgstr "" - -#: src/action.py:229 -msgid "clap" -msgstr "" - -#: src/action.py:229 -msgid "clap clap" -msgstr "" - -#: src/action.py:230 -msgid "She taught me everything I know." -msgstr "" - -#: src/action.py:231 -msgid "hello" -msgstr "" - -#: src/action.py:231 -msgid "hello to you too" -msgstr "" - -#: src/action.py:232 -msgid "tell me a joke" -msgstr "" - -#: src/action.py:233 -msgid "What do you call an alligator in a vest? An investigator." -msgstr "" - -#: src/action.py:234 -msgid "three laws of robotics" -msgstr "" - -#: src/action.py:235 -msgid "" -"The laws of robotics are\n" -"0: A robot may not injure a human being or, through inaction, allow a human\n" -"being to come to harm.\n" -"1: A robot must obey orders given it by human beings except where such orders\n" -"would conflict with the First Law.\n" -"2: A robot must protect its own existence as long as such protection does not\n" -"conflict with the First or Second Law." -msgstr "" - -#: src/action.py:242 -msgid "A galaxy far, far, just kidding. I'm from Seattle." -msgstr "" - -#: src/action.py:242 -msgid "where are you from" -msgstr "" - -#: src/action.py:243 -msgid "A machine has no name" -msgstr "" - -#: src/action.py:243 -msgid "your name" -msgstr "" - -#: src/action.py:245 -msgid "time" -msgstr "" - -#: src/main.py:279 -msgid "Unexpected error. Try again or check the logs." -msgstr "" - -#: src/main.py:292 -msgid "I don’t know how to answer that." -msgstr "" - -#: src/main.py:295 -msgid "Could you try that again?" -msgstr "" - diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 01d7d1d8..00000000 --- a/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -google-assistant-grpc==0.1.0 -google-cloud-speech==0.30.0 -google-auth-oauthlib==0.2.0 -pyasn1==0.4.2 -grpcio==1.7.0 diff --git a/scripts/asound.conf b/scripts/asound.conf deleted file mode 100755 index 951ddade..00000000 --- a/scripts/asound.conf +++ /dev/null @@ -1,30 +0,0 @@ -options snd_rpi_googlevoicehat_soundcard index=0 - -pcm.softvol { - type softvol - slave.pcm dmix - control { - name Master - card 0 - } -} - -pcm.micboost { - type route - slave.pcm dsnoop - ttable { - 0.0 30.0 - 1.1 30.0 - } -} - -pcm.!default { - type asym - playback.pcm "plug:softvol" - capture.pcm "plug:micboost" -} - -ctl.!default { - type hw - card 0 -} diff --git a/scripts/configure-driver.sh b/scripts/configure-driver.sh deleted file mode 100755 index ee3a0710..00000000 --- a/scripts/configure-driver.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -# -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -o errexit - -if [[ $EUID -ne 0 ]]; then - echo "This script must be run as root (use sudo)" 1>&2 - exit 1 -fi - -set -e - -sed -i \ - -e "s/^dtparam=audio=on/#\0/" \ - -e "s/^#\s*\(dtparam=i2s=on\)/\1/" \ - -e "s/^#\s*\(dtoverlay=i2s-mmap\)/\1/" \ - -e "s/^#\s*\(dtoverlay=googlevoicehat-soundcard\)/\1/" \ - /boot/config.txt -grep -q "dtoverlay=i2s-mmap" /boot/config.txt || \ - echo "dtoverlay=i2s-mmap" >> /boot/config.txt -grep -q "dtoverlay=googlevoicehat-soundcard" /boot/config.txt || \ - echo "dtoverlay=googlevoicehat-soundcard" >> /boot/config.txt -grep -q "dtparam=i2s=on" /boot/config.txt || \ - echo "dtparam=i2s=on" >> /boot/config.txt - -dtoverlay googlevoicehat-soundcard diff --git a/scripts/install-alsa-config.sh b/scripts/install-alsa-config.sh deleted file mode 100755 index e81b71dc..00000000 --- a/scripts/install-alsa-config.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -# -# Replace the Raspberry Pi's default ALSA config with one for the voiceHAT. -# -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -o errexit - -if [[ $EUID -ne 0 ]]; then - echo "This script must be run as root (use sudo)" 1>&2 - exit 1 -fi - -cd "$(dirname "${BASH_SOURCE[0]}")/.." - -asoundrc=/home/pi/.asoundrc -global_asoundrc=/etc/asound.conf - -for rcfile in "$asoundrc" "$global_asoundrc"; do - if [[ -f "$rcfile" ]] ; then - echo "Renaming $rcfile to $rcfile.bak..." - sudo mv "$rcfile" "$rcfile.bak" - fi -done - -sudo cp scripts/asound.conf "$global_asoundrc" -echo "Installed voiceHAT ALSA config at $global_asoundrc" - -# TODO(rodrigoq): it shouldn't be necessary to install at both locations, but -# if we don't install to $HOME then the volume widget (volumealsa) has a -# tendency to create an incompatible ~/.asoundrc and break the Voice Kit audio. -sudo cp scripts/asound.conf "$asoundrc" -echo "Installed voiceHAT ALSA config at $asoundrc" diff --git a/scripts/install-deps.sh b/scripts/install-deps.sh deleted file mode 100755 index 3242b61e..00000000 --- a/scripts/install-deps.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -o errexit - -scripts_dir="$(dirname "${BASH_SOURCE[0]}")" - -# make sure we're running as the owner of the checkout directory -RUN_AS="$(ls -ld "$scripts_dir" | awk 'NR==1 {print $3}')" -if [ "$USER" != "$RUN_AS" ] -then - echo "This script must run as $RUN_AS, trying to change user..." - exec sudo -u $RUN_AS $0 -fi - -# The google-assistant-library is only available on some platforms. -if [[ "$(uname -m)" == "armv7l" || "$(uname -m)" == "x86_64" || "$(uname -m)" == "armv6l" ]] ; then - pip3 install google-assistant-library==0.1.0 -fi diff --git a/scripts/install-services.sh b/scripts/install-services.sh deleted file mode 100755 index e06a084f..00000000 --- a/scripts/install-services.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# -# Install systemd service files for running on startup. -# -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -o errexit - -if [[ $EUID -ne 0 ]]; then - echo "This script must be run as root (use sudo)" 1>&2 - exit 1 -fi - -cd "$(dirname "${BASH_SOURCE[0]}")/.." -repo_path="$PWD" - -for service in systemd/*.service; do - sed "s:/home/pi/AIY-projects-python:${repo_path}:g" "$service" \ - > "/lib/systemd/system/$(basename "$service")" -done - -# voice-recognizer is not enabled by default, as it doesn't work until -# credentials are set up, so we explicitly enable the other services. -systemctl enable alsa-init.service -systemctl enable ntpdate.service diff --git a/scripts/pre-commit b/scripts/pre-commit deleted file mode 100755 index abdee0b1..00000000 --- a/scripts/pre-commit +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh -# git hook to ensure code style -# ln ../../scripts/pre-commit .git/hooks/ - -which >/dev/null autopep8 || { echo "please install autopep8"; exit 1; } -files=$(git diff --name-only --staged --diff-filter=ACMRTUXB | egrep "*.py$") - -if test -n "$files"; then - diff=$(autopep8 --max-line-length=100 --diff $files) - if [[ -n "${diff}" ]]; then - echo - autopep8 --max-line-length=100 --diff $files - echo - echo "To fix run: autopep8 --max-line-length=100 -i $files" - exit 1 - fi -fi diff --git a/shortcuts/check_audio.desktop b/shortcuts/check_audio.desktop deleted file mode 100644 index 8c961fc1..00000000 --- a/shortcuts/check_audio.desktop +++ /dev/null @@ -1,7 +0,0 @@ -[Desktop Entry] -Encoding=UTF-8 -Type=Application -Name=Check audio -Comment=Check that the voiceHAT audio input and output are both working. -Exec=/home/pi/AIY-projects-python/checkpoints/check_audio.py -Terminal=true diff --git a/shortcuts/check_cloud.desktop b/shortcuts/check_cloud.desktop deleted file mode 100644 index dd9b91d5..00000000 --- a/shortcuts/check_cloud.desktop +++ /dev/null @@ -1,7 +0,0 @@ -[Desktop Entry] -Encoding=UTF-8 -Type=Application -Name=Check Cloud -Comment=Check that the Cloud Speech API can be used. -Exec=/home/pi/AIY-projects-python/checkpoints/check_cloud.py -Terminal=true diff --git a/shortcuts/check_wifi.desktop b/shortcuts/check_wifi.desktop deleted file mode 100644 index 059aaee5..00000000 --- a/shortcuts/check_wifi.desktop +++ /dev/null @@ -1,7 +0,0 @@ -[Desktop Entry] -Encoding=UTF-8 -Type=Application -Name=Check WiFi -Comment=Check that the WiFi is working. -Exec=/home/pi/AIY-projects-python/checkpoints/check_wifi.py -Terminal=true diff --git a/src/.gitignore b/src/.gitignore deleted file mode 100644 index e5547674..00000000 --- a/src/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -MANIFEST -*.egg-info -dist/ diff --git a/src/README.md b/src/README.md deleted file mode 100644 index d272dbf4..00000000 --- a/src/README.md +++ /dev/null @@ -1,42 +0,0 @@ - - -This repository contains an easy-to-use API for the AIY Vision Kit and -AIY Voice Kit. -You can use it for face detection and object recognition, or use it to create -voice commands with simple while loops - have a look at the -[demos](https://github.com/google/aiyprojects-raspbian/tree/aiyprojects/src/examples). -Documentation is at the [AIY Projects site](https://aiyprojects.withgoogle.com). - -For guidelines on contributing, look at [CONTRIBUTING.md](CONTRIBUTING.md). -If you're using Raspbian instead of Google's provided image, read -[HACKING.md](HACKING.md) for information on getting started. - -For returning users: -The code for all AIY kits is in the `aiyprojects` branch, and is included in -images starting with aiyprojects-2017-12-18.img. The previous `voicekit` branch -contains code just for the Voice Kit, and the `master` branch contains the -original, deprecated Voice Recognizer demo. - -# Support - -If you're having trouble assembling your kit or running the demos, -try the [AIY Forums](https://www.raspberrypi.org/forums/viewforum.php?f=114). - -If you've found a bug in the AIY API or demos, you can look at the -[known issues](https://github.com/google/aiyprojects-raspbian/issues) or create -a new one, or even fix it yourself and send us a pull request. - -If you've found a problem with the Assistant (for example, crashes in the -library or incorrect responses), you can try -[the G+ community](https://plus.google.com/communities/117537996116836200696), -[Stack Overflow](https://stackoverflow.com/questions/tagged/google-assistant-sdk), -or [the assistant-sdk-python repo](https://github.com/googlesamples/assistant-sdk-python/). - -If you've had a problem after updating the source code, try downloading the -latest AIY image from the website, or alternatively run the following commands -in the dev terminal: - -``` -rm -r env -./scripts/install-deps.sh -``` diff --git a/src/aiy/_apis/_speech.py b/src/aiy/_apis/_speech.py deleted file mode 100644 index 2a59d5a5..00000000 --- a/src/aiy/_apis/_speech.py +++ /dev/null @@ -1,477 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Classes for speech interaction.""" - -from abc import abstractmethod -import collections -import logging -import os -import sys -import tempfile -import wave - -import google.auth -import google.auth.exceptions -import google.auth.transport.grpc -import google.auth.transport.requests -try: - from google.cloud import speech - from google.cloud.speech import enums - from google.cloud.speech import types -except ImportError: - print("Failed to import google.cloud.speech. Try:") - print(" env/bin/pip install -r requirements.txt") - sys.exit(1) - -from google.rpc import code_pb2 as error_code -from google.assistant.embedded.v1alpha2 import ( - embedded_assistant_pb2, - embedded_assistant_pb2_grpc, -) -import grpc -from six.moves import queue - -import aiy.i18n - -logger = logging.getLogger('speech') - -AUDIO_SAMPLE_SIZE = 2 # bytes per sample -AUDIO_SAMPLE_RATE_HZ = 16000 - -# Expected location of the service credentials file: -SERVICE_CREDENTIALS = os.path.expanduser('~/cloud_speech.json') - - -_Result = collections.namedtuple('_Result', ['transcript', 'response_audio']) - - -class Error(Exception): - pass - - -class _ChannelFactory(object): - - """Creates gRPC channels with a given configuration.""" - - def __init__(self, api_host, credentials): - self._api_host = api_host - self._credentials = credentials - - self._checked = False - - def make_channel(self): - """Creates a secure channel.""" - - request = google.auth.transport.requests.Request() - target = self._api_host + ':443' - - if not self._checked: - # Refresh now, to catch any errors early. Otherwise, they'll be - # raised and swallowed somewhere inside gRPC. - self._credentials.refresh(request) - self._checked = True - - return google.auth.transport.grpc.secure_authorized_channel( - self._credentials, request, target) - - -class GenericSpeechRequest(object): - - """Common base class for Cloud Speech and Assistant APIs.""" - - # TODO(rodrigoq): Refactor audio logging. - # pylint: disable=attribute-defined-outside-init,too-many-instance-attributes - - DEADLINE_SECS = 185 - - def __init__(self, api_host, credentials): - self.dialog_follow_on = False - self._audio_queue = queue.Queue() - self._phrases = [] - self._channel_factory = _ChannelFactory(api_host, credentials) - self._endpointer_cb = None - self._audio_logging_enabled = False - self._request_log_wav = None - - def add_phrases(self, phrases): - """Makes the recognition more likely to recognize the given phrase(s). - phrases: an object with a method get_phrases() that returns a list of - phrases. - """ - - self._phrases.extend(phrases.get_phrases()) - - def add_phrase(self, phrase): - """Makes the recognition more likely to recognize the given phrase.""" - self._phrases.append(phrase) - - def set_endpointer_cb(self, cb): - """Callback to invoke on end of speech.""" - self._endpointer_cb = cb - - def set_audio_logging_enabled(self, audio_logging_enabled=True): - self._audio_logging_enabled = audio_logging_enabled - - if audio_logging_enabled: - self._audio_log_dir = tempfile.mkdtemp() - self._audio_log_ix = 0 - - def reset(self): - while True: - try: - self._audio_queue.get(False) - except queue.Empty: - return - - self.dialog_follow_on = False - - def add_data(self, data): - self._audio_queue.put(data) - - def end_audio(self): - self.add_data(None) - - def _get_speech_context(self): - """Return a SpeechContext instance to bias recognition towards certain - phrases. - """ - return types.SpeechContext( - phrases=self._phrases, - ) - - @abstractmethod - def _make_service(self, channel): - """Create a service stub. - """ - return - - @abstractmethod - def _create_config_request(self): - """Create a config request for the given endpoint. - - This is sent first to the server to configure the speech recognition. - """ - return - - @abstractmethod - def _create_audio_request(self, data): - """Create an audio request for the given endpoint. - - This is sent to the server with audio to be recognized. - """ - return - - def _request_stream(self): - """Yields a config request followed by requests constructed from the - audio queue. - """ - yield self._create_config_request() - - while True: - data = self._audio_queue.get() - - if not data: - return - - if self._request_log_wav: - self._request_log_wav.writeframes(data) - - yield self._create_audio_request(data) - - @abstractmethod - def _create_response_stream(self, service, request_stream, deadline): - """Given a request stream, start the gRPC call to get the response - stream. - """ - return - - @abstractmethod - def _stop_sending_audio(self, resp): - """Return true if this response says user has stopped speaking. - - This stops the request from sending further audio. - """ - return - - @abstractmethod - def _handle_response(self, resp): - """Handle a response from the remote API. - - Args: - resp: StreamingRecognizeResponse instance - """ - return - - def _end_audio_request(self): - self.end_audio() - if self._endpointer_cb: - self._endpointer_cb() - - def _handle_response_stream(self, response_stream): - for resp in response_stream: - if self._stop_sending_audio(resp): - self._end_audio_request() - - self._handle_response(resp) - - # Server has closed the connection - return self._finish_request() or '' - - def _start_logging_request(self): - """Open a WAV file to log the request audio.""" - self._audio_log_ix += 1 - request_filename = '%s/request.%03d.wav' % ( - self._audio_log_dir, self._audio_log_ix) - logger.info('Writing request to %s', request_filename) - - self._request_log_wav = wave.open(request_filename, 'w') - - self._request_log_wav.setnchannels(1) - self._request_log_wav.setsampwidth(AUDIO_SAMPLE_SIZE) - self._request_log_wav.setframerate(AUDIO_SAMPLE_RATE_HZ) - - def _finish_request(self): - """Called after the final response is received.""" - - if self._request_log_wav: - self._request_log_wav.close() - - return _Result(None, None) - - def do_request(self): - """Establishes a connection and starts sending audio to the cloud - endpoint. Responses are handled by the subclass until one returns a - result. - - Returns: - namedtuple with the following fields: - transcript: string with transcript of user query - response_audio: optionally, an audio response from the server - - Raises speech.Error on error. - """ - try: - service = self._make_service(self._channel_factory.make_channel()) - - response_stream = self._create_response_stream( - service, self._request_stream(), self.DEADLINE_SECS) - - if self._audio_logging_enabled: - self._start_logging_request() - - return self._handle_response_stream(response_stream) - except ( - google.auth.exceptions.GoogleAuthError, - grpc.RpcError, - ) as exc: - raise Error('Exception in speech request') from exc - - -class CloudSpeechRequest(GenericSpeechRequest): - - """A transcription request to the Cloud Speech API. - - Args: - credentials_file: path to service account credentials JSON file - """ - - SCOPE = 'https://www.googleapis.com/auth/cloud-platform' - - def __init__(self, credentials_file): - os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = credentials_file - credentials, _ = google.auth.default(scopes=[self.SCOPE]) - - super().__init__('speech.googleapis.com', credentials) - - self._transcript = None - - def reset(self): - super().reset() - self._transcript = None - - def _make_service(self, channel): - return speech.SpeechClient() - - def _create_config_request(self): - recognition_config = types.RecognitionConfig( - encoding=enums.RecognitionConfig.AudioEncoding.LINEAR16, - sample_rate_hertz=AUDIO_SAMPLE_RATE_HZ, - language_code=aiy.i18n.get_language_code(), - speech_contexts=[self._get_speech_context()], - ) - streaming_config = types.StreamingRecognitionConfig( - config=recognition_config, - single_utterance=True, - ) - - # TODO(rodrigoq): we're actually returning a Config, not a Request, as - # the v1 API takes the Config and wraps it up in a Request, but we still - # want to share code with the Assistant API. Can we clean this up? - return streaming_config - - def _create_audio_request(self, data): - return types.StreamingRecognizeRequest(audio_content=data) - - def _create_response_stream(self, client, request_stream, deadline): - config = next(request_stream) - return client.streaming_recognize(config, request_stream) - - def _stop_sending_audio(self, resp): - """Check the endpointer type to see if an utterance has ended.""" - - if resp.speech_event_type: - speech_event_type = types.StreamingRecognizeResponse.SpeechEventType.Name( - resp.speech_event_type) - logger.info('endpointer_type: %s', speech_event_type) - - END_OF_SINGLE_UTTERANCE = types.StreamingRecognizeResponse.SpeechEventType.Value( - 'END_OF_SINGLE_UTTERANCE') - return resp.speech_event_type == END_OF_SINGLE_UTTERANCE - - def _handle_response(self, resp): - """Store the last transcript we received.""" - if resp.results: - self._transcript = ' '.join( - result.alternatives[0].transcript for result in resp.results) - logger.info('transcript: %s', self._transcript) - - def _finish_request(self): - super()._finish_request() - return _Result(self._transcript, None) - - -class AssistantSpeechRequest(GenericSpeechRequest): - - """A request to the Assistant API, which returns audio and text.""" - - def __init__(self, credentials, model_id, device_id): - - super().__init__('embeddedassistant.googleapis.com', credentials) - - self.model_id = model_id - self.device_id = device_id - - self._conversation_state = None - self._response_audio = b'' - self._transcript = None - - def reset(self): - super().reset() - self._response_audio = b'' - self._transcript = None - - def _make_service(self, channel): - return embedded_assistant_pb2_grpc.EmbeddedAssistantStub(channel) - - def _create_config_request(self): - audio_in_config = embedded_assistant_pb2.AudioInConfig( - encoding='LINEAR16', - sample_rate_hertz=AUDIO_SAMPLE_RATE_HZ, - ) - audio_out_config = embedded_assistant_pb2.AudioOutConfig( - encoding='LINEAR16', - sample_rate_hertz=AUDIO_SAMPLE_RATE_HZ, - volume_percentage=50, - ) - device_config = embedded_assistant_pb2.DeviceConfig( - device_id=self.device_id, - device_model_id=self.model_id, - ) - dialog_state_in = embedded_assistant_pb2.DialogStateIn( - conversation_state=self._conversation_state, - language_code=aiy.i18n.get_language_code(), - ) - assist_config = embedded_assistant_pb2.AssistConfig( - audio_in_config=audio_in_config, - audio_out_config=audio_out_config, - device_config=device_config, - dialog_state_in=dialog_state_in, - ) - - return embedded_assistant_pb2.AssistRequest(config=assist_config) - - def _create_audio_request(self, data): - return embedded_assistant_pb2.AssistRequest(audio_in=data) - - def _create_response_stream(self, service, request_stream, deadline): - return service.Assist(request_stream, deadline) - - def _stop_sending_audio(self, resp): - if resp.event_type: - logger.info('event_type: %s', resp.event_type) - - return (resp.event_type == - embedded_assistant_pb2.AssistResponse.END_OF_UTTERANCE) - - def _handle_response(self, resp): - """Accumulate audio and text from the remote end. It will be handled - in _finish_request(). - """ - - if resp.speech_results: - self._transcript = ' '.join(r.transcript for r in resp.speech_results) - logger.info('transcript: %s', self._transcript) - - self._response_audio += resp.audio_out.audio_data - - if resp.dialog_state_out.conversation_state: - self._conversation_state = resp.dialog_state_out.conversation_state - - if resp.dialog_state_out.microphone_mode: - self.dialog_follow_on = ( - resp.dialog_state_out.microphone_mode == - embedded_assistant_pb2.DialogStateOut.DIALOG_FOLLOW_ON) - - def _finish_request(self): - super()._finish_request() - - if self._response_audio and self._audio_logging_enabled: - self._log_audio_out(self._response_audio) - - return _Result(self._transcript, self._response_audio) - - def _log_audio_out(self, frames): - response_filename = '%s/response.%03d.wav' % ( - self._audio_log_dir, self._audio_log_ix) - logger.info('Writing response to %s', response_filename) - - response_wav = wave.open(response_filename, 'w') - response_wav.setnchannels(1) - response_wav.setsampwidth(AUDIO_SAMPLE_SIZE) - response_wav.setframerate(AUDIO_SAMPLE_RATE_HZ) - response_wav.writeframes(frames) - response_wav.close() - - -if __name__ == '__main__': - logging.basicConfig(level=logging.INFO) - - # for testing: use audio from a file - import argparse - parser = argparse.ArgumentParser() - parser.add_argument('file', nargs='?', default='test_speech.raw') - args = parser.parse_args() - - req = CloudSpeechRequest(SERVICE_CREDENTIALS) - - with open(args.file, 'rb') as f: - while True: - chunk = f.read(64000) - if not chunk: - break - req.add_data(chunk) - req.end_audio() - - print('down response:', req.do_request()) diff --git a/src/aiy/_drivers/_alsa.py b/src/aiy/_drivers/_alsa.py deleted file mode 100644 index 58c466cc..00000000 --- a/src/aiy/_drivers/_alsa.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Helpers for ALSA tools, including aplay and arecord.""" - - -def sample_width_to_string(sample_width): - """Convert sample width (bytes) to ALSA format string.""" - return {1: 's8', 2: 's16', 4: 's32'}.get(sample_width, None) diff --git a/src/aiy/_drivers/_button.py b/src/aiy/_drivers/_button.py deleted file mode 100644 index 7c133c69..00000000 --- a/src/aiy/_drivers/_button.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Button driver for the VoiceHat.""" - -import time -import RPi.GPIO as GPIO - - -class Button(object): - """Detect edges on the given GPIO channel.""" - - def __init__(self, - channel, - polarity=GPIO.FALLING, - pull_up_down=GPIO.PUD_UP, - debounce_time=0.08): - """A simple GPIO-based button driver. - - This driver supports a simple GPIO-based button. It works by detecting - edges on the given GPIO channel. Debouncing is automatic. - - Args: - channel: the GPIO pin number to use (BCM mode) - polarity: the GPIO polarity to detect; either GPIO.FALLING or - GPIO.RISING. - pull_up_down: whether the port should be pulled up or down; defaults to - GPIO.PUD_UP. - debounce_time: the time used in debouncing the button in seconds. - """ - if polarity not in [GPIO.FALLING, GPIO.RISING]: - raise ValueError( - 'polarity must be one of: GPIO.FALLING or GPIO.RISING') - - self.channel = int(channel) - self.polarity = polarity - self.expected_value = polarity == GPIO.RISING - self.debounce_time = debounce_time - - GPIO.setmode(GPIO.BCM) - GPIO.setup(channel, GPIO.IN, pull_up_down=pull_up_down) - - self.callback = None - - def __del__(self): - GPIO.cleanup(self.channel) - - def wait_for_press(self): - """Wait for the button to be pressed. - - This method blocks until the button is pressed. - """ - GPIO.add_event_detect(self.channel, self.polarity) - while True: - if GPIO.event_detected(self.channel) and self._debounce(): - GPIO.remove_event_detect(self.channel) - return - time.sleep(0.02) - - def on_press(self, callback): - """Call the callback whenever the button is pressed. - - Args: - callback: a function to call whenever the button is pressed. It should - take a single channel number. If the callback is None, the previously - registered callback, if any, is canceled. - - Example: - def MyButtonPressHandler(channel): - print "button pressed: channel = %d" % channel - my_button.on_press(MyButtonPressHandler) - """ - GPIO.remove_event_detect(self.channel) - if callback: - self.callback = callback - GPIO.add_event_detect( - self.channel, self.polarity, callback=self._debounce_and_callback) - - def _debounce_and_callback(self, _): - if self._debounce(): - self.callback() - - def _debounce(self): - """Debounce the GPIO signal. - - Check that the input holds the expected value for the debounce - period, to avoid false trigger on short pulses. - """ - start = time.time() - while time.time() < start + self.debounce_time: - if GPIO.input(self.channel) != self.expected_value: - return False - time.sleep(0.01) - return True diff --git a/src/aiy/_drivers/_hat.py b/src/aiy/_drivers/_hat.py deleted file mode 100644 index 26868e44..00000000 --- a/src/aiy/_drivers/_hat.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Utilities to identify the currently installed AIY device (if any).""" - -import re -import os - -HAT_PATH = '/proc/device-tree/hat/' -HAT_PRODUCT_ID_RE = re.compile('0x[0-9A-Fa-f]+') -AIY_HATS = { - 1: 'Voice Hat', - 2: 'Vision Bonnet', - 3: 'Voice Bonnet', -} - - -def _is_hat_attached(): - return os.path.exists(HAT_PATH) - - -def _get_hat_product(): - with open(os.path.join(HAT_PATH, 'product')) as f: - return f.readline().strip() - - -def _get_hat_product_id(): - with open(os.path.join(HAT_PATH, 'product_id')) as f: - matches = HAT_PRODUCT_ID_RE.match(f.readline().strip()) - if matches: - return int(matches.group(0), 16) - - -def get_aiy_device_name(): - if not _is_hat_attached(): - # Early Voice HATs don't have correctly programmed EEPROM, so no entry - # shows up in /proc/device-tree. - return 'Voice Hat' - product = _get_hat_product() - if 'AIY' not in product: - return None - product_id = _get_hat_product_id() - if not product_id: - return None - if product_id not in AIY_HATS: - return None - return AIY_HATS[product_id] diff --git a/src/aiy/_drivers/_led.py b/src/aiy/_drivers/_led.py deleted file mode 100644 index f99b1912..00000000 --- a/src/aiy/_drivers/_led.py +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""LED driver for the VoiceHat.""" - -import itertools -import threading -import time -import RPi.GPIO as GPIO - - -class LED: - """Starts a background thread to show patterns with the LED. - - Simple usage: - my_led = LED(channel = 25) - my_led.start() - my_led.set_state(LED.BEACON) - my_led.stop() - """ - - OFF = 0 - ON = 1 - BLINK = 2 - BLINK_3 = 3 - BEACON = 4 - BEACON_DARK = 5 - DECAY = 6 - PULSE_SLOW = 7 - PULSE_QUICK = 8 - - def __init__(self, channel): - self.animator = threading.Thread(target=self._animate, daemon=True) - self.channel = channel - self.iterator = None - self.running = False - self.state = None - self.sleep = 0 - GPIO.setmode(GPIO.BCM) - GPIO.setup(channel, GPIO.OUT) - self.pwm = GPIO.PWM(channel, 100) - self.lock = threading.Lock() - - def __del__(self): - self.stop() - GPIO.cleanup(self.channel) - - def start(self): - """Start the LED driver.""" - with self.lock: # pylint: disable=E1129 - if not self.running: - self.running = True - self.pwm.start(0) # off by default - self.animator.start() - - def stop(self): - """Stop the LED driver and sets the LED to off.""" - with self.lock: # pylint: disable=E1129 - if self.running: - self.running = False - - try: - self.animator.join() - except RuntimeError: - # Edge case where this is stopped before it starts. - pass - - self.pwm.stop() - - def set_state(self, state): - """Set the LED driver's new state. - - Note the LED driver must be started for this to have any effect. - """ - with self.lock: # pylint: disable=E1129 - self.state = state - - def _animate(self): - while True: - state = None - running = False - with self.lock: # pylint: disable=E1129 - state = self.state - self.state = None - running = self.running - if not running: - return - if state is not None: - if not self._parse_state(state): - raise ValueError('unsupported state: %d' % state) - if self.iterator: - self.pwm.ChangeDutyCycle(next(self.iterator)) - time.sleep(self.sleep) - else: - # We can also wait for a state change here with a Condition. - time.sleep(1) - - def _parse_state(self, state): - self.iterator = None - self.sleep = 0.0 - handled = False - - if state == self.OFF: - self.pwm.ChangeDutyCycle(0) - handled = True - elif state == self.ON: - self.pwm.ChangeDutyCycle(100) - handled = True - elif state == self.BLINK: - self.iterator = itertools.cycle([0, 100]) - self.sleep = 0.5 - handled = True - elif state == self.BLINK_3: - self.iterator = itertools.cycle([0, 100] * 3 + [0, 0]) - self.sleep = 0.25 - handled = True - elif state == self.BEACON: - self.iterator = itertools.cycle( - itertools.chain([30] * 100, [100] * 8, range(100, 30, -5))) - self.sleep = 0.05 - handled = True - elif state == self.BEACON_DARK: - self.iterator = itertools.cycle( - itertools.chain([0] * 100, range(0, 30, 3), range(30, 0, -3))) - self.sleep = 0.05 - handled = True - elif state == self.DECAY: - self.iterator = itertools.cycle(range(100, 0, -2)) - self.sleep = 0.05 - handled = True - elif state == self.PULSE_SLOW: - self.iterator = itertools.cycle( - itertools.chain(range(0, 100, 2), range(100, 0, -2))) - self.sleep = 0.1 - handled = True - elif state == self.PULSE_QUICK: - self.iterator = itertools.cycle( - itertools.chain(range(0, 100, 5), range(100, 0, -5))) - self.sleep = 0.05 - handled = True - - return handled diff --git a/src/aiy/_drivers/_player.py b/src/aiy/_drivers/_player.py deleted file mode 100644 index cc1dc623..00000000 --- a/src/aiy/_drivers/_player.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""A driver for audio playback.""" - -import logging -import subprocess -import wave - -import aiy._drivers._alsa - -logger = logging.getLogger('audio') - - -class Player(object): - """Plays short audio clips from a buffer or file.""" - - def __init__(self, output_device='default'): - self._output_device = output_device - - def play_bytes(self, audio_bytes, sample_rate, sample_width=2): - """Play audio from the given bytes-like object. - - Args: - audio_bytes: audio data (mono) - sample_rate: sample rate in Hertz (24 kHz by default) - sample_width: sample width in bytes (eg 2 for 16-bit audio) - """ - cmd = [ - 'aplay', - '-q', - '-t', 'raw', - '-D', self._output_device, - '-c', '1', - # pylint: disable=W0212 - '-f', aiy._drivers._alsa.sample_width_to_string(sample_width), - '-r', str(sample_rate), - ] - - aplay = subprocess.Popen(cmd, stdin=subprocess.PIPE) - aplay.stdin.write(audio_bytes) - aplay.stdin.close() - retcode = aplay.wait() - - if retcode: - logger.error('aplay failed with %d', retcode) - - def play_wav(self, wav_path): - """Play audio from the given WAV file. - - The file should be mono and small enough to load into memory. - Args: - wav_path: path to the wav file - """ - with wave.open(wav_path, 'r') as wav: - if wav.getnchannels() != 1: - raise ValueError(wav_path + ' is not a mono file') - - frames = wav.readframes(wav.getnframes()) - self.play_bytes(frames, wav.getframerate(), wav.getsampwidth()) diff --git a/src/aiy/_drivers/_recorder.py b/src/aiy/_drivers/_recorder.py deleted file mode 100644 index 6e69a837..00000000 --- a/src/aiy/_drivers/_recorder.py +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""A recorder driver capable of recording voice samples from the VoiceHat microphones.""" - -import logging -import os -import subprocess -import threading - -import aiy._drivers._alsa - -logger = logging.getLogger('recorder') - - -class Recorder(threading.Thread): - """A driver to record audio from the VoiceHat microphones. - - Stream audio from microphone in a background thread and run processing - callbacks. It reads audio in a configurable format from the microphone, - then converts it to a known format before passing it to the processors. - - This driver accumulates input (audio samples) in a local buffer. Once the - buffer contains more than CHUNK_S seconds, it passes the chunk to all - processors. An audio processor defines a 'add_data' method that receives - the chunk of audio samples to process. - """ - - CHUNK_S = 0.1 - - def __init__(self, input_device='default', - channels=1, bytes_per_sample=2, sample_rate_hz=16000): - """Create a Recorder with the given audio format. - - The Recorder will not start until start() is called. start() is called - automatically if the Recorder is used in a `with`-statement. - - - input_device: name of ALSA device (for a list, run `arecord -L`) - - channels: number of channels in audio read from the mic - - bytes_per_sample: sample width in bytes (eg 2 for 16-bit audio) - - sample_rate_hz: sample rate in hertz - """ - - super().__init__(daemon=True) - self._record_event = threading.Event() - self._processors = [] - - self._chunk_bytes = int(self.CHUNK_S * sample_rate_hz) * channels * bytes_per_sample - - self._cmd = [ - 'arecord', - '-q', - '-t', 'raw', - '-D', input_device, - '-c', str(channels), - # pylint: disable=W0212 - '-f', aiy._drivers._alsa.sample_width_to_string(bytes_per_sample), - '-r', str(sample_rate_hz), - ] - self._arecord = None - self._closed = False - - def add_processor(self, processor): - """Add an audio processor. - - An audio processor is an object that has an 'add_data' method with the - following signature: - class MyProcessor(object): - def __init__(self): - ... - - def add_data(self, data): - # processes the chunk of data here. - - The added processor may be called multiple times with chunks of audio data. - """ - self._record_event.set() - self._processors.append(processor) - - def remove_processor(self, processor): - """Remove an added audio processor.""" - try: - self._processors.remove(processor) - except ValueError: - logger.warn("processor was not found in the list") - self._record_event.clear() - - def run(self): - """Reads data from arecord and passes to processors.""" - - logger.info("started recording") - - # Check for race-condition when __exit__ is called at the same time as - # the process is started by the background thread - if self._closed: - self._arecord.kill() - return - - this_chunk = b'' - while True: - if not self._record_event.is_set() and self._arecord: - self._arecord.kill() - self._arecord = None - self._record_event.wait() - if not self._arecord: - self._arecord = subprocess.Popen(self._cmd, stdout=subprocess.PIPE) - input_data = self._arecord.stdout.read(self._chunk_bytes) - if not input_data: - break - - this_chunk += input_data - if len(this_chunk) >= self._chunk_bytes: - self._handle_chunk(this_chunk[:self._chunk_bytes]) - this_chunk = this_chunk[self._chunk_bytes:] - - if not self._closed: - logger.error('Microphone recorder died unexpectedly, aborting...') - # sys.exit doesn't work from background threads, so use os._exit as - # an emergency measure. - logging.shutdown() - os._exit(1) # pylint: disable=protected-access - - def stop(self): - """Stops the recorder and cleans up all resources.""" - self._closed = True - if self._arecord: - self._arecord.kill() - - def _handle_chunk(self, chunk): - """Send audio chunk to all processors.""" - for p in self._processors: - p.add_data(chunk) - - def __enter__(self): - self.start() - return self - - def __exit__(self, *args): - self.stop() diff --git a/src/aiy/_drivers/_spicomm.py b/src/aiy/_drivers/_spicomm.py deleted file mode 100644 index 38557d8a..00000000 --- a/src/aiy/_drivers/_spicomm.py +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Python wrapper around the VisionBonnet Spicomm device node.""" - -import array -import fcntl -import struct -import sys - -SPICOMM_DEV = '/dev/vision_spicomm' - -SPICOMM_IOCTL_BASE = 0x8900 -# TODO: 0xc0100000 should be calculated properly base on structure size. -SPICOMM_IOCTL_TRANSACT = 0xc0100000 + SPICOMM_IOCTL_BASE + 3 - -HEADER_SIZE = 16 -PAYLOAD_SIZE = 12 * 1024 * 1024 # 12 M - -FLAG_ERROR = 1 << 0 -FLAG_TIMEOUT = 1 << 1 -FLAG_OVERFLOW = 1 << 2 - - -class SpicommError(IOError): - """Base class for Spicomm errors.""" - pass - - -class SpicommDevNotFoundError(SpicommError): - """A usable Spicomm device node not found.""" - pass - - -class SpicommOverflowError(SpicommError): - """Transaction buffer too small for response. - - Attributes: - size: Number of bytes needed for the response. - """ - - def __init__(self, size): - self.size = size - super(SpicommOverflowError, self).__init__() - - -class SpicommTimeoutError(SpicommError): - """Transaction timed out.""" - pass - - -class SpicommInternalError(SpicommError): - """Internal unexpected error.""" - pass - - -class Spicomm(object): - """VisionBonnet Spicomm wrapper. - - Provides the ability to send and receive data as a transaction. - This means that every call to transact consists of a combined - send and receive step that's atomic from the calling application's - point of view. Multiple threads and processes can access the device - node concurrently using one Spicomm instance per thread. - Transactions are serialized in the underlying kernel driver. - """ - - def __init__(self): - try: - self._dev = open(SPICOMM_DEV, 'r+b', 0) - except (IOError, OSError): - raise SpicommDevNotFoundError - self._tbuf = bytearray(HEADER_SIZE + PAYLOAD_SIZE) - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, exc_tb): - self.close() - - def close(self): - if self._dev: - self._dev.close() - - def transact(self, request, timeout=15): - """Execute a Spicomm transaction. - - The bytes in request are sent, a response is waited for and returned. - If the request or response is too large SpicommOverflowError is raised. - - Args: - request: Request bytes to send. - timeout: How long a response will be waited for, in seconds. - - Returns: - Bytes-like object with response data. - - Raises: - SpicommOverflowError: Transaction buffer was too small for response. - The 'size' attribute contains the required size. - SpicommTimeoutError : Transaction timed out. - SpicommInternalError: Unexpected error interacting with kernel driver. - """ - - payload_len = len(request) - if payload_len > PAYLOAD_SIZE: - raise SpicommOverflowError(PAYLOAD_SIZE) - - # Fill in transaction buffer. - self._tbuf[0:4] = struct.pack('I', 0) # flags, not currently used. - self._tbuf[4:8] = struct.pack('I', int(timeout * 1000)) # timeout, ms. - self._tbuf[8:12] = struct.pack('I', len(self._tbuf)) # total buffer size. - self._tbuf[12:16] = struct.pack('I', payload_len) # filled range of buffer. - self._tbuf[16:16 + payload_len] = request - - try: - # Send transaction to kernel driver. - fcntl.ioctl(self._dev, SPICOMM_IOCTL_TRANSACT, self._tbuf) - - # No exception means errno 0 and self._tbuf is now mutated. - _, _, _, payload_len = struct.unpack('IIII', self._tbuf[0:16]) - return self._tbuf[16:16 + payload_len] - except (IOError, OSError): - # FLAG_ERROR is set if we actually talked to the kernel. - flags, _, _, payload_len = struct.unpack('IIII', self._tbuf[0:16]) - if flags & FLAG_ERROR: - if flags & FLAG_TIMEOUT: - raise SpicommTimeoutError - elif flags & FLAG_OVERFLOW: - raise SpicommOverflowError(payload_len) - - # This is unexpected. - raise SpicommInternalError diff --git a/src/aiy/_drivers/_status_ui.py b/src/aiy/_drivers/_status_ui.py deleted file mode 100644 index 64556729..00000000 --- a/src/aiy/_drivers/_status_ui.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""A status UI powered by the LED on the VoiceHat.""" - -import logging -import os.path - -import aiy.audio -import aiy.voicehat - -logger = logging.getLogger('status_ui') - - -class _StatusUi(object): - """Gives the user status feedback. - - The LED and optionally a trigger sound tell the user when the box is - ready, listening or thinking. - """ - - def __init__(self): - self._trigger_sound_wave = None - self._state_map = { - "starting": aiy.voicehat.LED.PULSE_QUICK, - "ready": aiy.voicehat.LED.BEACON_DARK, - "listening": aiy.voicehat.LED.ON, - "thinking": aiy.voicehat.LED.PULSE_QUICK, - "stopping": aiy.voicehat.LED.PULSE_QUICK, - "power-off": aiy.voicehat.LED.OFF, - "error": aiy.voicehat.LED.BLINK_3, - } - aiy.voicehat.get_led().set_state(aiy.voicehat.LED.OFF) - - def set_trigger_sound_wave(self, trigger_sound_wave): - """Set the trigger sound. - - A trigger sound is played when the status is 'listening' to indicate - that the assistant is actively listening to the user. - The trigger_sound_wave argument should be the path to a valid wave file. - If it is None, the trigger sound is disabled. - """ - if not trigger_sound_wave: - self._trigger_sound_wave = None - return - expanded_path = os.path.expanduser(trigger_sound_wave) - if os.path.exists(expanded_path): - self._trigger_sound_wave = expanded_path - else: - logger.warning( - 'File %s specified as trigger sound does not exist.', - trigger_sound_wave) - self._trigger_sound_wave = None - - def status(self, status): - """Activate the status. - - This method updates the LED animation. Returns True if the status is - valid and has been updated. - """ - if status not in self._state_map: - logger.warning("unsupported state: %s, must be one of %s", - status, ",".join(self._state_map.keys())) - return False - aiy.voicehat.get_led().set_state(self._state_map[status]) - if status == 'listening' and self._trigger_sound_wave: - aiy.audio.play_wave(self._trigger_sound_wave) - return True diff --git a/src/aiy/_drivers/_transport.py b/src/aiy/_drivers/_transport.py deleted file mode 100644 index a0251da4..00000000 --- a/src/aiy/_drivers/_transport.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Transport to communicate with VisionBonnet board.""" - -import logging -import os -import socket -import struct - -from aiy._drivers import _spicomm - - -class _SpiTransport(object): - """Communicate with VisionBonnet over SPI bus.""" - - def __init__(self): - self._spicomm = _spicomm.Spicomm() - - # TODO(dkovalev): add timeout when implemented in Spicomm - def send(self, request): - return self._spicomm.transact(request) - - def close(self): - self._spicomm.close() - - -def _socket_recvall(s, size): - buf = b'' - while size: - newbuf = s.recv(size) - if not newbuf: - return None - buf += newbuf - size -= len(newbuf) - return buf - - -def _socket_receive_message(s): - buf = _socket_recvall(s, 4) # 4 bytes - if not buf: - return None - size = struct.unpack('!I', buf)[0] - return _socket_recvall(s, size) - - -def _socket_send_message(s, msg): - s.sendall(struct.pack('!I', len(msg))) # 4 bytes - s.sendall(msg) # len(msg) bytes - - -class _SocketTransport(object): - """Communicate with VisionBonnet over socket.""" - - def __init__(self): - """Open connection to the bonnet.""" - self._client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - host = os.environ.get('VISION_BONNET_HOST', '172.28.28.10') - port = int(os.environ.get('VISION_BONNET_PORT', '35000')) - self._client.connect((host, port)) - - # TODO(dkovalev,weiranzhao): add timeout parameter - def send(self, request): - _socket_send_message(self._client, request) - return _socket_receive_message(self._client) - - def close(self): - self._client.close() - - -def _is_arm(): - return os.uname()[4].startswith('arm') - - -def make_transport(): - if _is_arm(): - return _SpiTransport() - else: - return _SocketTransport() diff --git a/src/aiy/_drivers/_tts.py b/src/aiy/_drivers/_tts.py deleted file mode 100644 index c223479b..00000000 --- a/src/aiy/_drivers/_tts.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Wrapper around a TTS system.""" - -import functools -import logging -import os -import subprocess -import tempfile -from aiy import i18n - -# Path to a tmpfs directory to avoid SD card wear -TMP_DIR = '/run/user/%d' % os.getuid() - -logger = logging.getLogger('tts') - - -def create_say(player): - """Return a function say(words) for the given player.""" - lang = i18n.get_language_code() - return functools.partial(say, player, lang=lang) - - -def say(player, words, lang='en-US', volume=60, pitch=130): - """Say the given words with TTS. - - Args: - player: To play the text-to-speech audio. - words: string to say aloud. - lang: language for the text-to-speech engine. - volume: volume for the text-to-speech engine. - pitch: pitch for the text-to-speech engine. - """ - try: - (fd, tts_wav) = tempfile.mkstemp(suffix='.wav', dir=TMP_DIR) - except IOError: - logger.exception('Using fallback directory for TTS output') - (fd, tts_wav) = tempfile.mkstemp(suffix='.wav') - os.close(fd) - words = '' + words + '' - try: - subprocess.call(['pico2wave', '--lang', lang, '-w', tts_wav, words]) - player.play_wav(tts_wav) - finally: - os.unlink(tts_wav) - - -def _main(): - import argparse - from aiy import audio - - logging.basicConfig(level=logging.INFO) - - parser = argparse.ArgumentParser(description='Test TTS wrapper') - parser.add_argument('words', nargs='*', help='Words to say') - args = parser.parse_args() - - if args.words: - words = ' '.join(args.words) - player = audio.get_player() - create_say(player)(words) - - -if __name__ == '__main__': - _main() diff --git a/src/aiy/assistant/__init__.py b/src/aiy/assistant/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/aiy/assistant/grpc.py b/src/aiy/assistant/grpc.py deleted file mode 100644 index 0f85413b..00000000 --- a/src/aiy/assistant/grpc.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""An API to access the Google Assistant.""" - -import aiy._apis._speech -import aiy.assistant.auth_helpers -import aiy.assistant.device_helpers -import aiy.audio -import aiy.voicehat - -# Global variables. They are lazily initialized. -_assistant_recognizer = None - - -class _AssistantRecognizer(object): - """Your personal Google Assistant.""" - - def __init__(self, credentials): - model_id, device_id = aiy.assistant.device_helpers.get_ids_for_service(credentials) - self._request = aiy._apis._speech.AssistantSpeechRequest(credentials, model_id, device_id) - self._recorder = aiy.audio.get_recorder() - - def recognize(self): - """Recognizes the user's speech and gets answers from Google Assistant. - - This function listens to the user's speech via the VoiceHat speaker and - sends the audio to the Google Assistant Library. The response is returned in - both text and audio. - - Usage: - transcript, audio = my_recognizer.recognize() - if transcript is not None: - print('You said ', transcript) - aiy.audio.play_audio(audio) - """ - self._request.reset() - self._request.set_endpointer_cb(self._endpointer_callback) - self._recorder.add_processor(self._request) - response = self._request.do_request() - return response.transcript, response.response_audio - - def _endpointer_callback(self): - self._recorder.remove_processor(self._request) - - -def get_assistant(): - """Returns a recognizer that uses Google Assistant APIs. - - Sample usage: - button = aiy.voicehat.get_button() - recognizer = aiy.assistant.grpc.get_recognizer() - print('Your Google Assistant is ready.') - while True: - print('Press the button and speak') - button.wait_for_press() - print('Listening...') - transcript, audio = recognizer.recognize() - if transcript is not None: - print('Assistant said ', transcript) - if audio is not None: - aiy.audio.play_audio(audio) - """ - global _assistant_recognizer - if not _assistant_recognizer: - credentials = aiy.assistant.auth_helpers.get_assistant_credentials() - _assistant_recognizer = _AssistantRecognizer(credentials) - return _assistant_recognizer diff --git a/src/aiy/assistant/library.py b/src/aiy/assistant/library.py deleted file mode 100644 index 3af3b162..00000000 --- a/src/aiy/assistant/library.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Wrapper around google.assistant.library. - -Handles model and device registration.""" - -import google.assistant.library - -import aiy.assistant.device_helpers as device_helpers - - -class Assistant(google.assistant.library.Assistant): - """Client for the Google Assistant Library. - - Similar to google.assistant.library.Assistant, but handles device - registration. - """ - - def __init__(self, credentials): - self._credentials = credentials - self._model_id = device_helpers.register_model_id(credentials) - - super().__init__(credentials, self._model_id) - - def start(self): - events = super().start() - - device_helpers.register_device_id( - self._credentials, self._model_id, self.device_id, "SDK_LIBRARY") - - return events diff --git a/src/aiy/audio.py b/src/aiy/audio.py deleted file mode 100644 index 7f766bbd..00000000 --- a/src/aiy/audio.py +++ /dev/null @@ -1,162 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Drivers for audio functionality provided by the VoiceHat.""" - -import time -import wave - -import aiy._drivers._player -import aiy._drivers._recorder -import aiy._drivers._tts - -AUDIO_SAMPLE_SIZE = 2 # bytes per sample -AUDIO_SAMPLE_RATE_HZ = 16000 - -# Global variables. They are lazily initialized. -_voicehat_recorder = None -_voicehat_player = None -_status_ui = None -_tts_volume = 60 -_tts_pitch = 130 - - -class _WaveDump(object): - """A processor that saves recorded audio to a wave file.""" - - def __init__(self, filepath, duration): - self._wave = wave.open(filepath, 'wb') - self._wave.setnchannels(1) - self._wave.setsampwidth(2) - self._wave.setframerate(16000) - self._bytes = 0 - self._bytes_limit = int(duration * 16000) * 1 * 2 - - def add_data(self, data): - max_bytes = self._bytes_limit - self._bytes - data = data[:max_bytes] - self._bytes += len(data) - if data: - self._wave.writeframes(data) - - def is_done(self): - return self._bytes >= self._bytes_limit - - def __enter__(self): - return self - - def __exit__(self, *args): - self._wave.close() - - -def get_player(): - """Returns a driver to control the VoiceHat speaker. - - The aiy modules automatically use this player. So usually you do not need to - use this. Instead, use 'aiy.audio.play_wave' if you would like to play some - audio. - """ - global _voicehat_player - if not _voicehat_player: - _voicehat_player = aiy._drivers._player.Player() - return _voicehat_player - - -def get_recorder(): - """Returns a driver to control the VoiceHat microphones. - - The aiy modules automatically use this recorder. So usually you do not need to - use this. - """ - global _voicehat_recorder - if not _voicehat_recorder: - _voicehat_recorder = aiy._drivers._recorder.Recorder() - return _voicehat_recorder - - -def record_to_wave(filepath, duration): - """Records an audio for the given duration to a wave file.""" - recorder = get_recorder() - dumper = _WaveDump(filepath, duration) - with recorder, dumper: - recorder.add_processor(dumper) - while not dumper.is_done(): - time.sleep(0.1) - - -def play_wave(wave_file): - """Plays the given wave file. - - The wave file has to be mono and small enough to be loaded in memory. - """ - player = get_player() - player.play_wav(wave_file) - - -def play_audio(audio_data): - """Plays the given audio data.""" - player = get_player() - player.play_bytes(audio_data, sample_width=AUDIO_SAMPLE_SIZE, sample_rate=AUDIO_SAMPLE_RATE_HZ) - - -def say(words, lang=None, volume=None, pitch=None): - """Says the given words in the given language with Google TTS engine. - - If lang is specified, e.g. "en-US", it will be used to say the given words. - Otherwise, the language from aiy.i18n will be used. - volume (optional) volume used to say the given words. - pitch (optional) pitch to say the given words. - Example: aiy.audio.say('This is an example', lang="en-US", volume=75, pitch=135) - Any of the optional variables can be left out. - """ - - if not lang: - lang = aiy.i18n.get_language_code() - if not volume: - volume = aiy.audio.get_tts_volume() - if not pitch: - pitch = aiy.audio.get_tts_pitch() - aiy._drivers._tts.say(aiy.audio.get_player(), words, lang=lang, volume=volume, pitch=pitch) - - -def get_status_ui(): - """Returns a driver to access the StatusUI daemon. - - The StatusUI daemon controls the LEDs in the background. It supports a list - of statuses it is able to communicate with the LED on the Voicehat. - """ - global _status_ui - if not _status_ui: - _status_ui = aiy._drivers._StatusUi() - return _status_ui - - -def set_tts_volume(volume): - global _tts_volume - _tts_volume = volume - - -def get_tts_volume(): - global _tts_volume - return _tts_volume - - -def set_tts_pitch(pitch): - global _tts_pitch - _tts_pitch = pitch - - -def get_tts_pitch(): - global _tts_pitch - return _tts_pitch diff --git a/src/aiy/cloudspeech.py b/src/aiy/cloudspeech.py deleted file mode 100644 index 160fa63f..00000000 --- a/src/aiy/cloudspeech.py +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""An API to access Google Speech recognition service.""" - -import os.path - -import aiy._apis._speech -import aiy.audio -import aiy.voicehat - -# Global variables. They are lazily initialized. -_cloudspeech_recognizer = None - -# Expected location of the CloudSpeech credentials file: -CLOUDSPEECH_CREDENTIALS_FILE = os.path.expanduser('~/cloud_speech.json') - - -class _CloudSpeechRecognizer(object): - """A speech recognizer backed by the Google CloudSpeech APIs. - """ - - def __init__(self, credentials_file): - self._request = aiy._apis._speech.CloudSpeechRequest(credentials_file) - self._recorder = aiy.audio.get_recorder() - self._hotwords = [] - - def recognize(self, immediate=False): - """Recognizes the user's speech and transcript it into text. - - This function listens to the user's speech via the VoiceHat speaker. Then it - contacts Google CloudSpeech APIs and returns a textual transcript if possible. - If hotword list is populated this method will only respond if hotword is said. - - Args: - immediate: ignore the hotword list, even if it has been populated - may be used to create a conversational experience, for example: - - text = recognizer.recognize() - if 'call a friend' in text: - aiy.audio.say('OK, which one?') - friend = recognizer.recognize(immediate=True) - make_a_call(friend) - """ - self._request.reset() - self._request.set_endpointer_cb(self._endpointer_callback) - self._recorder.add_processor(self._request) - text = self._request.do_request().transcript - if immediate: - return text - elif self._hotwords and text: - text = text.lower() - loc_min = len(text) - hotword_found = '' - for hotword in self._hotwords: - loc_temp = text.find(hotword) - if loc_temp > -1 and loc_min > loc_temp: - loc_min = loc_temp - hotword_found = hotword - if hotword_found: - parse_text = text.split(hotword_found)[1] - return parse_text.strip() - else: - return '' - else: - return '' if self._hotwords else text - - def expect_hotword(self, hotword_list): - """Enables hotword detection for a selected list - This method is optional and populates the list of hotwords - to be used for hotword activation. - - For example, to create a recognizer for Google: - - recognizer.expect_hotword('Google') - recognizer.expect_hotword(['Google','Raspberry Pi']) - """ - if isinstance(hotword_list, list): - for hotword in hotword_list: - self._hotwords.append(hotword.lower()) - else: - self._hotwords.append(hotword_list.lower()) - - def expect_phrase(self, phrase): - """Explicitly tells the engine that the phrase is more likely to appear. - - This method is optional and makes speech recognition more accurate - especially when certain commands are expected. - - For example, a light control system may want to add the following commands: - - recognizer.expect_phrase('light on') - recognizer.expect_phrase('light off') - """ - self._request.add_phrase(phrase) - - def _endpointer_callback(self): - self._recorder.remove_processor(self._request) - - -def get_recognizer(): - """Returns a recognizer that uses Google CloudSpeech APIs. - - Sample usage: - button = aiy.voicehat.get_button() - recognizer = aiy.cloudspeech.get_recognizer() - while True: - print('Press the button and speak') - button.wait_for_press() - text = recognizer.recognize() - if 'light on' in text: - turn_on_light() - elif 'light off' in text: - turn_off_light() - """ - global _cloudspeech_recognizer - if not _cloudspeech_recognizer: - _cloudspeech_recognizer = _CloudSpeechRecognizer(CLOUDSPEECH_CREDENTIALS_FILE) - return _cloudspeech_recognizer diff --git a/src/aiy/i18n.py b/src/aiy/i18n.py deleted file mode 100644 index 4afae431..00000000 --- a/src/aiy/i18n.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Internationalization helpers.""" - -import gettext - -_DEFAULT_LANGUAGE_CODE = 'en-US' -_LOCALE_DOMAIN = 'voice-recognizer' - -_language_code = _DEFAULT_LANGUAGE_CODE - -_locale_dir = None - - -def set_locale_dir(locale_dir): - """Sets the directory that contains the language bundles. - - This is only required if you call set_language_code with gettext_install=True. - """ - global _locale_dir - if not locale_dir: - raise ValueError('locale_dir must be valid') - _locale_dir = locale_dir - - -def set_language_code(code, gettext_install=False): - """Set the BCP-47 language code that the speech systems should use. - - Args: - gettext_install: if True, gettext's _() will be installed in as a builtin. - As this has global effect, it should only be done by applications. - """ - global _language_code - _language_code = code.replace('_', '-') - - if gettext_install: - if not _locale_dir: - raise ValueError('locale_dir is not set. Please call set_locale_dir().') - language_id = code.replace('-', '_') - t = gettext.translation(_LOCALE_DOMAIN, _locale_dir, [language_id], fallback=True) - t.install() - - -def get_language_code(): - """Returns the BCP-47 language code that the speech systems should use. - - We don't use the system locale because the Assistant API only supports - en-US at launch, so that should be used by default in all environments. - """ - return _language_code diff --git a/src/aiy/test/__init__.py b/src/aiy/test/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/aiy/vision/__init__.py b/src/aiy/vision/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/aiy/vision/inference.py b/src/aiy/vision/inference.py deleted file mode 100644 index 6b7a08c5..00000000 --- a/src/aiy/vision/inference.py +++ /dev/null @@ -1,317 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""VisionBonnet InferenceEngine API. - -Python API to communicate with the VisionBonnet from the Raspberry Pi side. - -It can be used to load a model, analyze local image or image from camera -shot. It automatically unload the model once the associated object is -deleted. See image_classification.py and object_recognition.py as examples on -how to use this API. -""" - -import logging -from aiy._drivers._transport import make_transport -from aiy.vision.proto import protocol_pb2 - - -_SUPPORTED_FIRMWARE_VERSION = (1, 0) # major, minor - - -class FirmwareVersionException(Exception): - - def __init__(self, *args, **kwargs): - Exception.__init__(self, *args, **kwargs) - - -def _check_firmware_info(info): - firmware_version = '%d.%d' % info - supported_version = '%d.%d' % _SUPPORTED_FIRMWARE_VERSION - if info[0] > _SUPPORTED_FIRMWARE_VERSION[0]: - raise FirmwareVersionException( - 'AIY library supports firmware version %s, current firmware ' - 'version is %s. You should upgrade AIY library.' % - (supported_version, firmware_version)) - if info[0] < _SUPPORTED_FIRMWARE_VERSION[0]: - raise FirmwareVersionException( - 'AIY library supports firmware version %s, current firmware ' - 'version is %s. You should upgrade firmware.' % - (supported_version, firmware_version)) - if info[1] > _SUPPORTED_FIRMWARE_VERSION[1]: - logging.warn( - 'AIY library supports firmware version %s, current firmware ' - 'version is %s. Consider upgrading AIY library.', - supported_version, firmware_version) - if info[1] < _SUPPORTED_FIRMWARE_VERSION[1]: - logging.warn( - 'AIY library supports firmware version %s, current firmware ' - 'version is %s. Consider upgrading firmware.', - supported_version, firmware_version) - - -class CameraInference(object): - """Helper class to run camera inference.""" - - def __init__(self, descriptor, params=None): - self._engine = InferenceEngine() - self._key = self._engine.load_model(descriptor) - self._engine.start_camera_inference(self._key, params) - - def camera_state(self): - return self._engine.get_camera_state() - - def run(self): - while True: - yield self._engine.camera_inference() - - def close(self): - self._engine.stop_camera_inference() - self._engine.unload_model(self._key) - self._engine.close() - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, exc_tb): - self.close() - - -class ImageInference(object): - """Helper class to run image inference.""" - - def __init__(self, descriptor): - self._engine = InferenceEngine() - self._key = self._engine.load_model(descriptor) - - def run(self, image, params=None): - return self._engine.image_inference(self._key, image, params) - - def close(self): - self._engine.unload_model(self._key) - self._engine.close() - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, exc_tb): - self.close() - - -class ModelDescriptor(object): - """Info used by VisionBonnet to load model.""" - - def __init__(self, name, input_shape, input_normalizer, compute_graph): - """Initialzes ModelDescriptor. - - Args: - name: string, a name used to refer the model, should not conflict - with existing model names. - input_shape: (batch, height, width, depth). For now, only batch=1 and - depth=3 are supported. - input_normalizer: (mean, stddev) to convert input image (for analysis) to - the same range model is - trained. For example, if the model is trained with [-1, 1] input. To - analyze an RGB image (input range [0, 255]), one needs to specify the - input normalizer as (128.0, 128.0). - compute_graph: string, converted model proto - """ - self.name = name - self.input_shape = input_shape - self.input_normalizer = input_normalizer - self.compute_graph = compute_graph - - -class InferenceException(Exception): - - def __init__(self, *args, **kwargs): - Exception.__init__(self, *args, **kwargs) - - -class InferenceEngine(object): - """Class to access InferenceEngine on VisionBonnet board. - - Inference result has the following format: - - message InferenceResult { - string model_name; // Name of the model to run inference on. - int32 width; // Input image/frame width. - int32 height; // Input image/frame height. - Rectangle window; // Window inside width x height image/frame. - int32 duration_ms; // Inference duration. - map tensors; // Output tensors. - - message Frame { - int32 index; // Frame number. - int64 timestamp_us; // Frame timestamp. - } - - Frame frame; // Frame-specific inference data. - } - """ - - def __init__(self): - self._transport = make_transport() - logging.info('InferenceEngine transport: %s', - self._transport.__class__.__name__) - - def close(self): - self._transport.close() - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, exc_tb): - self.close() - - def _communicate(self, request): - """Gets response and logs messages if need to. - - Args: - request: protocol_pb2.Request - - Returns: - protocol_pb2.Response - """ - response = protocol_pb2.Response() - response.ParseFromString(self._transport.send(request.SerializeToString())) - if response.status.code != protocol_pb2.Response.Status.OK: - raise InferenceException(response.status.message) - return response - - def load_model(self, descriptor): - """Loads model on VisionBonnet. - - Args: - descriptor: ModelDescriptor, meta info that defines model name, - where to get the model and etc. - Returns: - Model identifier. - """ - _check_firmware_info(self.get_firmware_info()) - - logging.info('Loading model "%s"...', descriptor.name) - - batch, height, width, depth = descriptor.input_shape - mean, stddev = descriptor.input_normalizer - if batch != 1: - raise ValueError('Unsupported batch value: %d. Must be 1.') - - if depth != 3: - raise ValueError('Unsupported depth value: %d. Must be 3.') - - request = protocol_pb2.Request() - request.load_model.model_name = descriptor.name - request.load_model.input_shape.batch = batch - request.load_model.input_shape.height = height - request.load_model.input_shape.width = width - request.load_model.input_shape.depth = depth - request.load_model.input_normalizer.mean = mean - request.load_model.input_normalizer.stddev = stddev - if descriptor.compute_graph: - request.load_model.compute_graph = descriptor.compute_graph - - try: - self._communicate(request) - except InferenceException as e: - logging.warning(str(e)) - - return descriptor.name - - def unload_model(self, model_name): - """Deletes model on VisionBonnet. - - Args: - model_name: string, unique identifier used to refer a model. - """ - logging.info('Unloading model "%s"...', model_name) - - request = protocol_pb2.Request() - request.unload_model.model_name = model_name - self._communicate(request) - - def start_camera_inference(self, model_name, params=None): - """Starts inference running on VisionBonnet.""" - request = protocol_pb2.Request() - request.start_camera_inference.model_name = model_name - - for key, value in (params or {}).items(): - request.start_camera_inference.params[key] = str(value) - - self._communicate(request) - - def camera_inference(self): - """Returns the latest inference result from VisionBonnet.""" - request = protocol_pb2.Request() - request.camera_inference.SetInParent() - return self._communicate(request).inference_result - - def stop_camera_inference(self): - """Stops inference running on VisionBonnet.""" - request = protocol_pb2.Request() - request.stop_camera_inference.SetInParent() - self._communicate(request) - - def get_camera_state(self): - request = protocol_pb2.Request() - request.get_camera_state.SetInParent() - return self._communicate(request).camera_state - - def get_firmware_info(self): - """Returns firmware version as (major, minor) tuple.""" - request = protocol_pb2.Request() - request.get_firmware_info.SetInParent() - try: - info = self._communicate(request).firmware_info - return (info.major_version, info.minor_version) - except InferenceException: - # Request is not supported by firmware, default to 1.0 - return (1, 0) - - def image_inference(self, model_name, image, params=None): - """Runs inference on image using model (identified by model_name). - - Args: - model_name: string, unique identifier used to refer a model. - image: PIL.Image, - params: dict, additional parameters to run inference - - Returns: - protocol_pb2.Response - """ - if not model_name: - raise ValueError('Model name must not be empty.') - - logging.info('Image inference with model "%s"...', model_name) - - width, height = image.size - - request = protocol_pb2.Request() - request.image_inference.model_name = model_name - request.image_inference.tensor.shape.height = height - request.image_inference.tensor.shape.width = width - - if image.mode == 'RGB': - r, g, b = image.split() - request.image_inference.tensor.shape.depth = 3 - request.image_inference.tensor.data = r.tobytes() + g.tobytes() + b.tobytes() - elif image.mode == 'L': - request.image_inference.tensor.shape.depth = 1 - request.image_inference.tensor.data = image.tobytes() - else: - raise InferenceException('Unsupported image format: %s. Must be L or RGB.' % image.mode) - - for key, value in (params or {}).items(): - request.image_inference.params[key] = str(value) - - return self._communicate(request).inference_result diff --git a/src/aiy/vision/leds.py b/src/aiy/vision/leds.py deleted file mode 100644 index 2ad77ee1..00000000 --- a/src/aiy/vision/leds.py +++ /dev/null @@ -1,181 +0,0 @@ -# Copyright 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -def _tflash_reg(duration_ms): - if duration_ms <= 128: - return 0 - elif duration_ms <= 384: - return 1 - else: - return min((int(round(duration_ms / 128))) - 2, 126) - - -def _pwm1_reg(percent): - return int(round(256.0 * percent)) - - -def _trise_tfall_reg(duration_ms): - if duration_ms <= 1.5: - return 0 - else: - return min(int(round(duration_ms / 96)), 15) - - -def _write(path, data): - with open(path, 'w') as file: - file.write(str(data)) - - -def _device_file(prop): - return '/sys/class/leds/ktd202x:led1/device/%s' % prop - - -class Pattern(object): - """Class to define blinking pattern.""" - - def __init__(self, period_ms, on_percent=0.5, rise_ms=0, fall_ms=0): - if on_percent < 0 or on_percent > 0.996: - raise ValueError('on_percent must be in the range [0..0.996]') - - if period_ms < 0 or rise_ms < 0 or fall_ms < 0: - raise ValueError('durations must be non-negative') - - self.period_ms = period_ms - self.on_percent = on_percent - self.rise_ms = rise_ms - self.fall_ms = fall_ms - - @staticmethod - def blink(period_ms): - return Pattern(period_ms, 0.5) - - @staticmethod - def breathe(period_ms): - return Pattern(period_ms, 0.3, period_ms * 0.3, period_ms * 0.3) - - -class Leds(object): - """Class to control KTD LED driver chip.""" - class Channel(object): - """Configuration of each channel on KTD LED driver.""" - OFF = 0 - ON = 1 - PATTERN = 2 - - def __init__(self, state, brightness): - if state not in (self.ON, self.OFF, self.PATTERN): - raise ValueError('state must be OFF, ON, or PATTERN') - - if brightness < 0 or brightness > 255: - raise ValueError('brightness must be in the range [0..255]') - - self.state = state - self.brightness = brightness - - @staticmethod - def rgb(state, rgb): - """Returns configuration for channels: 1 (red), 2 (green), 3 (blue).""" - return { - 1: Leds.Channel(state, rgb[0]), - 2: Leds.Channel(state, rgb[1]), - 3: Leds.Channel(state, rgb[2]), - } - - @staticmethod - def rgb_off(): - return Leds.rgb(Leds.Channel.OFF, (0, 0, 0)) - - @staticmethod - def rgb_on(rgb): - return Leds.rgb(Leds.Channel.ON, rgb) - - @staticmethod - def rgb_pattern(rgb): - return Leds.rgb(Leds.Channel.PATTERN, rgb) - - @staticmethod - def privacy(enabled, brightness=255): - """Returns configuration for channel 4 (privacy).""" - if enabled: - return {4: Leds.Channel(Leds.Channel.ON, brightness)} - else: - return {4: Leds.Channel(Leds.Channel.OFF, 0)} - - @staticmethod - def privacy_on(brightness=255): - return Leds.privacy(True, brightness) - - @staticmethod - def privacy_off(): - return Leds.privacy(False, 0) - - def __init__(self, reset=True): - if reset: - self.reset() - - def reset(self): - _write(_device_file('reset'), 1) - - @property - def pattern(self): - return self._pattern - - @pattern.setter - def pattern(self, value): - self._pattern = value - command = 'tflash=%d;pwm1=%d;trise=%d;tfall=%d;' % ( - _tflash_reg(value.period_ms), - _pwm1_reg(value.on_percent), - _trise_tfall_reg(value.rise_ms), - _trise_tfall_reg(value.fall_ms)) - _write(_device_file('registers'), command) - - def update(self, channels): - command = '' - for index, channel in channels.items(): - if channel.brightness is not None: - command += 'led%d=%d;' % (index, channel.brightness) - if channel.state is not None: - command += 'ch%d_enable=%d;' % (index, channel.state) - if command: - _write(_device_file('registers'), command) - - -class PrivacyLed(object): - """Helper class to turn Privacy LED off automatically.""" - - def __init__(self, leds, brightness=32): - self._leds = leds - self._brightness = brightness - - def __enter__(self): - self._leds.update(Leds.privacy_on(self._brightness)) - - def __exit__(self, exc_type, exc_value, exc_tb): - self._leds.update(Leds.privacy_off()) - - -class RgbLeds(object): - """Helper class to turn RGB LEDs off automatically.""" - - def __init__(self, leds, channels): - self._leds = leds - self._channels = channels - - def __enter__(self): - self._leds.update(self._channels) - - def __exit__(self, exc_type, exc_value, exc_tb): - self._leds.update(Leds.rgb_off()) diff --git a/src/aiy/vision/models/__init__.py b/src/aiy/vision/models/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/aiy/vision/models/dish_classifier.py b/src/aiy/vision/models/dish_classifier.py deleted file mode 100644 index 0be5c53c..00000000 --- a/src/aiy/vision/models/dish_classifier.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""API for Dish Classifier.""" - -from aiy.vision.inference import ModelDescriptor -from aiy.vision.models import utils -from aiy.vision.models.dish_classifier_classes import CLASSES - -_COMPUTE_GRAPH_NAME = 'mobilenet_v1_192res_1.0_seefood.binaryproto' - - -def model(): - return ModelDescriptor( - name='dish_classifier', - input_shape=(1, 192, 192, 3), - input_normalizer=(128.0, 128.0), - compute_graph=utils.load_compute_graph(_COMPUTE_GRAPH_NAME)) - - -def get_classes(result, max_num_objects=None, object_prob_threshold=0.0): - """Converts dish classifier model output to list of detected objects. - - Args: - result: output tensor from dish classifier model. - max_num_objects: int; max number of objects to return. - object_prob_threshold: float; min probability of each returned object. - - Returns: - A list of (class_name: string, probability: float) pairs ordered by - probability from highest to lowest. The number of pairs is not greater than - max_num_objects. Each probability is greater than object_prob_threshold. For - example: - - [('Ramen', 0.981934) - ('Yaka mein, 0.005497)] - """ - assert len(result.tensors) == 1 - tensor = result.tensors['MobilenetV1/Predictions/Softmax'] - probs, shape = tensor.data, tensor.shape - assert (shape.batch, shape.height, shape.width, shape.depth) == (1, 1, 1, - 2024) - - pairs = [pair for pair in enumerate(probs) if pair[1] > object_prob_threshold] - pairs = sorted(pairs, key=lambda pair: pair[1], reverse=True) - pairs = pairs[0:max_num_objects] - return [('/'.join(CLASSES[index]), prob) for index, prob in pairs] diff --git a/src/aiy/vision/models/dish_classifier_classes.py b/src/aiy/vision/models/dish_classifier_classes.py deleted file mode 100644 index 70c711ea..00000000 --- a/src/aiy/vision/models/dish_classifier_classes.py +++ /dev/null @@ -1,2042 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Predefined dish classes for dish classifier model.""" - -CLASSES = ( - ('background',), # index=0 - ('Chaudin',), # index=1 - ('Bambalouni',), # index=2 - ('Ghoriba',), # index=3 - ('Mango sticky rice',), # index=4 - ('Jianbing',), # index=5 - ('Aguachile',), # index=6 - ('Carrozza',), # index=7 - ('Miyan kuka',), # index=8 - ('Efo riro',), # index=9 - ('Ayam masak merah',), # index=10 - ('Chiffon pie',), # index=11 - ('Instant noodle',), # index=12 - ('Riso patate e cozze',), # index=13 - ('Bazin',), # index=14 - ('Black bottom pie',), # index=15 - ('Pal\xc3\xb3c soup',), # index=16 - ('Sailor sandwich',), # index=17 - ('Tuwo shinkafa',), # index=18 - ('Carne a la tampique\xc3\xb1a',), # index=19 - ('Pastel azteca',), # index=20 - ('Fujian red wine chicken',), # index=21 - ('Boeber',), # index=22 - ('Lady Baltimore cake',), # index=23 - ('Yam khai dao',), # index=24 - ('Texas Tommy',), # index=25 - ('Har cheong gai',), # index=26 - ('Kolokythopita',), # index=27 - ('Karydopita',), # index=28 - ('Rinflaj\xc5\xa1',), # index=29 - ('Hainanese curry rice',), # index=30 - ('Sonoran hot dog',), # index=31 - ('Kamounia',), # index=32 - ('Afghani burger',), # index=33 - ('Teochew porridge',), # index=34 - ('Minestra di ceci',), # index=35 - ('Pastrami on rye',), # index=36 - ('Roast beef sandwich',), # index=37 - ('Chahan',), # index=38 - ('Ekuru',), # index=39 - ('Sciusceddu',), # index=40 - ('Breakfast burrito',), # index=41 - ('\xc3\x84ggost',), # index=42 - ('Sausage Stroganoff',), # index=43 - ('Roti jala',), # index=44 - ('Pirao',), # index=45 - ('Casatiello',), # index=46 - ('Khanom tan',), # index=47 - ('Muamba chicken',), # index=48 - ('Dobradinha',), # index=49 - ('Bruckfleisch',), # index=50 - ('Molote',), # index=51 - ('Spongata',), # index=52 - ('Funge',), # index=53 - ('\xc3\x84lplermagronen',), # index=54 - ('K\xc3\xb6ttbullar',), # index=55 - ("Ka'ak",), # index=56 - ('Papet vaudois',), # index=57 - ('Broodpap',), # index=58 - ('Prosciutto di Norcia',), # index=59 - ('Malloreddus',), # index=60 - ('Farcidure',), # index=61 - ('Pannekoek',), # index=62 - ('\xc5\xa0porki makaruli',), # index=63 - ('Bolo Rei',), # index=64 - ('Camarones al mojo de ajo',), # index=65 - ('Fricasse',), # index=66 - ('Stracciatella',), # index=67 - ('Fondu creusois',), # index=68 - ('Sart\xc3\xb9',), # index=69 - ('Matelote',), # index=70 - ('Baodu',), # index=71 - ('Tarte au maton',), # index=72 - ('Cartellate',), # index=73 - ('Gyeran-ppang',), # index=74 - ('Torta pasqualina',), # index=75 - ('Caltabo\xc8\x99',), # index=76 - ('Khanom mo kaeng',), # index=77 - ('Suimono',), # index=78 - ('Dimlama',), # index=79 - ('Tav\xc3\xab kosi',), # index=80 - ('Salade li\xc3\xa9geoise',), # index=81 - ('Salame di Fabriano',), # index=82 - ('Kalach',), # index=83 - ('Jambon persill\xc3\xa9',), # index=84 - ('Tonkotsu ramen',), # index=85 - ('Pozharsky cutlet',), # index=86 - ('Roccoc\xc3\xb2',), # index=87 - ('Feij\xc3\xa3o com \xc3\xb3leo de palma',), # index=88 - ('Calulu',), # index=89 - ('Begova \xc4\x8dorba',), # index=90 - ('Cuzzupa',), # index=91 - ('Th\xe1\xbb\x8bt kho t\xc3\xa0u',), # index=92 - ('Bon bon chicken',), # index=93 - ('Zoque',), # index=94 - ('Bint al-sahn',), # index=95 - ('Tempoyak',), # index=96 - ('Puran poli',), # index=97 - ('Enfrijoladas',), # index=98 - ('Chueo-tang',), # index=99 - ('Naem',), # index=100 - ('Sate kikil',), # index=101 - ('Pinzimonio',), # index=102 - ('Pizokels',), # index=103 - ('Schiacciatina',), # index=104 - ('Schiacciata',), # index=105 - ('Daheen',), # index=106 - ('Chapssal-tteok',), # index=107 - ('Ojja',), # index=108 - ('Tigella',), # index=109 - ('Pansotti',), # index=110 - ('Fried eggplant',), # index=111 - ('Portuguese seafood rice',), # index=112 - ('Tripes \xc3\xa0 la mode de Caen',), # index=113 - ('Arraksbulle',), # index=114 - ('Brenebon',), # index=115 - ('Gnocco fritto',), # index=116 - ('Pan di ramerino',), # index=117 - ('Tahu tek-tek',), # index=118 - ('Bibikkan',), # index=119 - ('Tongseng cumi',), # index=120 - ('Nakl\xc3\xa1dan\xc3\xbd hermel\xc3\xadn',), # index=121 - ('Bundevara',), # index=122 - ('Sop saudara',), # index=123 - ('Mian cha',), # index=124 - ('Erbazzone',), # index=125 - ('Kisra',), # index=126 - ('Carne di t\xc3\xacblizze del Me\xc4\x91imurje',), # index=127 - ('Kagape kambing',), # index=128 - ('Markook',), # index=129 - ('Pisarei e fa\xc5\x9b\xc3\xb6',), # index=130 - ('Lontong Krubyuk',), # index=131 - ('Pampushka',), # index=132 - ('Makowiec',), # index=133 - ('Saleeg',), # index=134 - ('Scaccia',), # index=135 - ('J\xc3\xb3kai bean soup',), # index=136 - ('Bookbinder soup',), # index=137 - ('Selat solo',), # index=138 - ('Kutsinta',), # index=139 - ('Sago soup',), # index=140 - ('Vinegret',), # index=141 - ('Shrimp and grits',), # index=142 - ('Sirop de Li\xc3\xa8ge',), # index=143 - ('Woku',), # index=144 - ('Muhallebi',), # index=145 - ('Empal gepuk',), # index=146 - ('Fou\xc3\xa9e',), # index=147 - ('Octopus as food',), # index=148 - ('Koba',), # index=149 - ('B\xc3\xb2 l\xc3\xbac l\xe1\xba\xafc',), # index=150 - ("Squid l\xc5\xab'au",), # index=151 - ('Shrimp Louie',), # index=152 - ('Black pudding',), # index=153 - ('Cherry kebab',), # index=154 - ('Pitsi-pits\xc3\xae',), # index=155 - ('Sabich salad',), # index=156 - ('Mie kocok',), # index=157 - ('Maraca pie',), # index=158 - ('Banga',), # index=159 - ('Baccal\xc3\xa0 alla lucana',), # index=160 - ('Nasi tumpang',), # index=161 - ('Gratin dauphinois',), # index=162 - ('Arroz chaufa',), # index=163 - ('Kuih',), # index=164 - ('Ayam goreng',), # index=165 - ('Chongos zamoranos',), # index=166 - ('NOT_HOT_DOG',), # index=167 - ('M\xc4\x83m\xc4\x83lig\xc4\x83',), # index=168 - ('Candied almonds',), # index=169 - ('Lasagne',), # index=170 - ('Pecel Lele',), # index=171 - ('Lettuce soup',), # index=172 - ('Acquacotta',), # index=173 - ('Pork blood soup',), # index=174 - ('Sai krok Isan',), # index=175 - ('Buridda',), # index=176 - ('Maccu',), # index=177 - ('Turkey Devonshire',), # index=178 - ('Ginestrata',), # index=179 - ('Garmugia',), # index=180 - ('Meringue',), # index=181 - ('Peanut butter and jelly sandwich',), # index=182 - ('Couque de Dinant',), # index=183 - ('Omo tuo',), # index=184 - ('Thapthim krop',), # index=185 - ('Pie tee',), # index=186 - ('Sutarfeni',), # index=187 - ('Raclette',), # index=188 - ('Wotou',), # index=189 - ('Punugulu',), # index=190 - ('Succotash',), # index=191 - ('Chim chum',), # index=192 - ('Wachipa',), # index=193 - ('Boat noodles',), # index=194 - ('Tantuni',), # index=195 - ('Shab Deg',), # index=196 - ('Ch\xe1\xba\xa3 gi\xc3\xb2',), # index=197 - ('Ciabatta Bacon Cheeseburger',), # index=198 - ('Mie kangkung',), # index=199 - ('Tuwo masara',), # index=200 - ('Kokonte',), # index=201 - ('Akple',), # index=202 - ('Plakali',), # index=203 - ('Kware\xc5\xbcimal',), # index=204 - ('Bento',), # index=205 - ('Osechi',), # index=206 - ('Okonomiyaki',), # index=207 - ('Miso soup',), # index=208 - ('Dango',), # index=209 - ('Onigiri',), # index=210 - ('Hiyayakko',), # index=211 - ('Tempura',), # index=212 - ('Mochi',), # index=213 - ('Peppersoup',), # index=214 - ('Caldo de queso',), # index=215 - ('Dodo ikire',), # index=216 - ('Uir\xc5\x8d',), # index=217 - ('Red bean soup',), # index=218 - ('Kakig\xc5\x8dri',), # index=219 - ('Khichu',), # index=220 - ('Bolo de arroz',), # index=221 - ('Chips and dip',), # index=222 - ('Murgh Musallam',), # index=223 - ('Utica greens',), # index=224 - ('Zaalouk',), # index=225 - ('Mutton curry',), # index=226 - ('Mughlai paratha',), # index=227 - ('Tuo Zaafi',), # index=228 - ('B\xc3\xa1nh b\xe1\xbb\x99t l\xe1\xbb\x8dc',), # index=229 - ('Kavarma',), # index=230 - ('Cheeseburger',), # index=231 - ('Jelly bean',), # index=232 - ('Apple pie',), # index=233 - ('Udon',), # index=234 - ('Falafel',), # index=235 - ('Agedashi tofu',), # index=236 - ('Dashi',), # index=237 - ('Tortell',), # index=238 - ('Omelette',), # index=239 - ('Cr\xc3\xa8me br\xc3\xbbl\xc3\xa9e',), # index=240 - ('Cucumber soup',), # index=241 - ('French toast',), # index=242 - ('Tripe',), # index=243 - ('Pepperoni',), # index=244 - ('Salami',), # index=245 - ('Kimchi',), # index=246 - ('Kn\xc3\xb6del',), # index=247 - ('Takoyaki',), # index=248 - ('Halva',), # index=249 - ('Pigs in blankets',), # index=250 - ('Spanakopita',), # index=251 - ('Pumpkin pie',), # index=252 - ('Jambalaya',), # index=253 - ('Club sandwich',), # index=254 - ('Churro',), # index=255 - ('Turducken',), # index=256 - ('Welsh rarebit',), # index=257 - ('Hot dog',), # index=258 - ('Oyakodon',), # index=259 - ('Meatball',), # index=260 - ('Waldorf salad',), # index=261 - ('Potato salad',), # index=262 - ('Satay',), # index=263 - ('Pemmican',), # index=264 - ('M\xc3\xa4mmi',), # index=265 - ('Fideu\xc3\xa0',), # index=266 - ('Waffle',), # index=267 - ('Pancake',), # index=268 - ('Quiche',), # index=269 - ('Borscht',), # index=270 - ('Bratwurst',), # index=271 - ('Foie gras',), # index=272 - ('Burrito',), # index=273 - ('Goulash',), # index=274 - ('Spotted dick',), # index=275 - ('Coq au vin',), # index=276 - ('Ratatouille',), # index=277 - ('Cornbread',), # index=278 - ('Souvlaki',), # index=279 - ('Chow mein',), # index=280 - ('Roast beef',), # index=281 - ('Peking duck',), # index=282 - ('Fried chicken',), # index=283 - ('Croquembouche',), # index=284 - ('Tahini',), # index=285 - ('Gumbo',), # index=286 - ('Fajita',), # index=287 - ('Chicken fried steak',), # index=288 - ('Sukiyaki',), # index=289 - ('Scrapple',), # index=290 - ('Chili con carne',), # index=291 - ('Monte Cristo sandwich',), # index=292 - ('Kielbasa',), # index=293 - ('Polenta',), # index=294 - ('Reuben sandwich',), # index=295 - ("S'more",), # index=296 - ('Andouille',), # index=297 - ('Beignet',), # index=298 - ('Cr\xc3\xaape',), # index=299 - ('Gulai',), # index=300 - ('Breakfast sausage',), # index=301 - ('Chorizo',), # index=302 - ('Gyro',), # index=303 - ('Nachos',), # index=304 - ('Larb',), # index=305 - ('Couscous',), # index=306 - ('Meze',), # index=307 - ('Cheesesteak',), # index=308 - ('Frozen yogurt',), # index=309 - ('Injera',), # index=310 - ('Muesli',), # index=311 - ('Meatloaf',), # index=312 - ('Fuet',), # index=313 - ('Natt\xc5\x8d',), # index=314 - ('Banana split',), # index=315 - ('P\xc4\x85czki',), # index=316 - ('Pound cake',), # index=317 - ('Fuqi feipian',), # index=318 - ('Nasi lemak',), # index=319 - ('Flan',), # index=320 - ('Pad thai',), # index=321 - ('Yakitori',), # index=322 - ('Amanatt\xc5\x8d',), # index=323 - ('Tom kha kai',), # index=324 - ('Lokma',), # index=325 - ('Mooncake',), # index=326 - ('Idli',), # index=327 - ('Sp\xc3\xa4tzle',), # index=328 - ('Nopalito',), # index=329 - ('Sincronizada',), # index=330 - ('\xc5\xbdganci',), # index=331 - ('Totopo',), # index=332 - ('Folar',), # index=333 - ('Cherry pie',), # index=334 - ('Umeboshi',), # index=335 - ('Patty',), # index=336 - ('Saltah',), # index=337 - ('Khinkali',), # index=338 - ('Shkedei marak',), # index=339 - ('Tekkadon',), # index=340 - ('Chadachadi',), # index=341 - ('Kaipen',), # index=342 - ('Draw soup',), # index=343 - ('Shahan ful',), # index=344 - ('Shiro',), # index=345 - ("Ga'at",), # index=346 - ('Skordalia',), # index=347 - ('Budae jjigae',), # index=348 - ('Anju',), # index=349 - ('Fried Coke',), # index=350 - ('Lemang',), # index=351 - ('Basundi',), # index=352 - ('Brown Betty',), # index=353 - ('Khabees',), # index=354 - ('Kottu',), # index=355 - ('Isterband',), # index=356 - ('Ciauscolo',), # index=357 - ('Khatkhate',), # index=358 - ('Pan de muerto',), # index=359 - ('Caponata',), # index=360 - ('Pulla',), # index=361 - ('Sabaayad',), # index=362 - ('Miyeok-guk',), # index=363 - ('Imoni',), # index=364 - ('Pitha',), # index=365 - ('Kedgeree',), # index=366 - ('Bife a cavalo',), # index=367 - ('Yaki udon',), # index=368 - ('She-crab soup',), # index=369 - ('Koozh',), # index=370 - ('Ke\xc5\x9fkek',), # index=371 - ('Cabidela',), # index=372 - ('Gerber sandwich',), # index=373 - ('Zagorski \xc5\xa0trukli',), # index=374 - ('Himbasha',), # index=375 - ('Satara\xc5\xa1',), # index=376 - ('Kakuni',), # index=377 - ('Enormous Omelet Sandwich',), # index=378 - ('Turr\xc3\xb3n',), # index=379 - ('Tsukudani',), # index=380 - ('Hawaiian haystack',), # index=381 - ('Kateh',), # index=382 - ('Stoemp',), # index=383 - ('Pajeon',), # index=384 - ('\xc4\xa0bejna',), # index=385 - ('Kaya toast',), # index=386 - ('Fit-fit',), # index=387 - ('Kitcha',), # index=388 - ('Thalipeeth',), # index=389 - ('Figgy pudding',), # index=390 - ('Cachupa',), # index=391 - ('Cherries jubilee',), # index=392 - ('Crappit heid',), # index=393 - ('Mince and tatties',), # index=394 - ('Anadama bread',), # index=395 - ('Carbonara',), # index=396 - ('Kladdkaka',), # index=397 - ('Shakshouka',), # index=398 - ('Chicken Vesuvio',), # index=399 - ('Jibarito',), # index=400 - ('Chicken Divan',), # index=401 - ('Motsunabe',), # index=402 - ('Sonofabitch stew',), # index=403 - ('Pudding corn',), # index=404 - ('Johnny Marzetti',), # index=405 - ('Mostarda',), # index=406 - ('Maafe',), # index=407 - ('Churma',), # index=408 - ('Chole bhature',), # index=409 - ('Dobos torte',), # index=410 - ('Carne de porco \xc3\xa0 alentejana',), # index=411 - ('Khao soi',), # index=412 - ('Kissel',), # index=413 - ('Cottage loaf',), # index=414 - ('Silver needle noodles',), # index=415 - ('Shrimp DeJonghe',), # index=416 - ('Kiritanpo',), # index=417 - ('Bean pie',), # index=418 - ('Churchkhela',), # index=419 - ('Yahni',), # index=420 - ('Gringas',), # index=421 - ('Annin tofu',), # index=422 - ('Jiaozi',), # index=423 - ('Breakfast sandwich',), # index=424 - ('Tanghulu',), # index=425 - ('Black sesame soup',), # index=426 - ('Goug\xc3\xa8re',), # index=427 - ('Namul',), # index=428 - ('Kosambari',), # index=429 - ("Ma'amoul",), # index=430 - ('Caldo de pollo',), # index=431 - ('Loukaniko',), # index=432 - ('Doberge cake',), # index=433 - ('Nasi campur',), # index=434 - ('Snack cake',), # index=435 - ('Taiyaki',), # index=436 - ('Karn\xc4\xb1yar\xc4\xb1k',), # index=437 - ('Pierogi',), # index=438 - ('Macaroni and cheese',), # index=439 - ('Huevos motule\xc3\xb1os',), # index=440 - ('Chislic',), # index=441 - ('Corn dog',), # index=442 - ('Shawarma',), # index=443 - ('Zongzi',), # index=444 - ('Dumpling',), # index=445 - ('Syrniki',), # index=446 - ('King cake',), # index=447 - ('Souffl\xc3\xa9',), # index=448 - ('Gy\xc5\xabdon',), # index=449 - ('Chicken nugget',), # index=450 - ('Bulgogi',), # index=451 - ('Eggs Benedict',), # index=452 - ('Hot dry noodles',), # index=453 - ('Mashed potato',), # index=454 - ('Anpan',), # index=455 - ('Quesadilla',), # index=456 - ('Youtiao',), # index=457 - ('Congee',), # index=458 - ('Sekihan',), # index=459 - ('Semla',), # index=460 - ('Arctic roll',), # index=461 - ('Castella',), # index=462 - ('Hanabiramochi',), # index=463 - ('Falukorv',), # index=464 - ('Ketupat',), # index=465 - ('Rendang',), # index=466 - ('Chocolate brownie',), # index=467 - ('Mapo doufu',), # index=468 - ('Chinese noodles',), # index=469 - ('Empanada',), # index=470 - ('Fried rice',), # index=471 - ('Chicago-style pizza',), # index=472 - ('Cuban sandwich',), # index=473 - ('Tarte Tatin',), # index=474 - ('Yakisoba',), # index=475 - ('Dagwood sandwich',), # index=476 - ('Cheesecake',), # index=477 - ('Samosa',), # index=478 - ("Devil's food cake",), # index=479 - ('Shashlik',), # index=480 - ('Horseshoe sandwich',), # index=481 - ('City chicken',), # index=482 - ('Key lime pie',), # index=483 - ('Potato skins',), # index=484 - ('Haejang-guk',), # index=485 - ('Burmese tofu',), # index=486 - ('Shumai',), # index=487 - ('Sour cherry soup',), # index=488 - ('Gigandes plaki',), # index=489 - ('Kabsa',), # index=490 - ('Chicken curry',), # index=491 - ('Shrimp Creole',), # index=492 - ('Pork tenderloin sandwich',), # index=493 - ('Dampfnudel',), # index=494 - ('Finnan haddie',), # index=495 - ('Kenkey',), # index=496 - ('Pincho',), # index=497 - ('Gundruk',), # index=498 - ('Chilorio',), # index=499 - ('Koulourakia',), # index=500 - ('Bryndzov\xc3\xa9 halu\xc5\xa1ky',), # index=501 - ('Imagawayaki',), # index=502 - ('Vasilopita',), # index=503 - ('Strapa\xc4\x8dky',), # index=504 - ("Po' boy",), # index=505 - ('Capirotada',), # index=506 - ('Beef Manhattan',), # index=507 - ('Sandwich loaf',), # index=508 - ('Jian dui',), # index=509 - ('Almond biscuit',), # index=510 - ('North Slavic fermented cereal soups',), # index=511 - ('Fried plantain',), # index=512 - ('Stuffed peppers',), # index=513 - ('Piperade',), # index=514 - ('Rogan josh',), # index=515 - ('Fabada asturiana',), # index=516 - ('Potato wedges',), # index=517 - ('Calisson',), # index=518 - ('Prawn ball',), # index=519 - ('Kushikatsu',), # index=520 - ('Lo mai chi',), # index=521 - ('Manchet',), # index=522 - ('Leek soup',), # index=523 - ('Vanillerostbraten',), # index=524 - ('Hangtown fry',), # index=525 - ('Cabbie claw',), # index=526 - ('Chitranna',), # index=527 - ('Ragi mudde',), # index=528 - ('Denver sandwich',), # index=529 - ('Laver',), # index=530 - ('Elote',), # index=531 - ('Kulolo',), # index=532 - ('Oxtail soup',), # index=533 - ('Pantua',), # index=534 - ('Corn relish',), # index=535 - ('Poga\xc4\x8da',), # index=536 - ('Qubani ka meetha',), # index=537 - ('Boondi',), # index=538 - ('Arrosticini',), # index=539 - ('Panelle',), # index=540 - ('Santula',), # index=541 - ('Tofu skin roll',), # index=542 - ('Crispy fried chicken',), # index=543 - ('Steamed meatball',), # index=544 - ('Lobio',), # index=545 - ('Suman',), # index=546 - ('H\xc5\x8dt\xc5\x8d',), # index=547 - ('Matbukha',), # index=548 - ('Stuffed squash',), # index=549 - ('A\xc3\xa7orda',), # index=550 - ('Makdous',), # index=551 - ('Soto',), # index=552 - ('Frangollo',), # index=553 - ('Patty melt',), # index=554 - ('Taro dumpling',), # index=555 - ('Entomatada',), # index=556 - ('B\xc3\xa1nh cu\xe1\xbb\x91n',), # index=557 - ('Corunda',), # index=558 - ('Zhaliang',), # index=559 - ('Cassoulet',), # index=560 - ('Debrecener',), # index=561 - ('Scampi',), # index=562 - ('Pilaf',), # index=563 - ('Sambar',), # index=564 - ('Century egg',), # index=565 - ('Escargot',), # index=566 - ('Cong you bing',), # index=567 - ('Beef noodle soup',), # index=568 - ('Magiritsa',), # index=569 - ('Gugelhupf',), # index=570 - ('Sachima',), # index=571 - ('White rice',), # index=572 - ('Maultasche',), # index=573 - ('American chop suey',), # index=574 - ('Fish slice',), # index=575 - ('Sea cucumber as food',), # index=576 - ('Beef ball',), # index=577 - ('Siu yuk',), # index=578 - ('Seafood birdsnest',), # index=579 - ('White cut chicken',), # index=580 - ('Pinchitos',), # index=581 - ('Satsivi',), # index=582 - ('Malpua',), # index=583 - ('Chhena gaja',), # index=584 - ('Flying Jacob',), # index=585 - ('Steak de Burgo',), # index=586 - ('Crab Louie',), # index=587 - ('Butter chicken',), # index=588 - ('Amok trey',), # index=589 - ('Menemen',), # index=590 - ('Piadina',), # index=591 - ('Orange cuttlefish',), # index=592 - ('Fudge',), # index=593 - ('Cottage Pudding',), # index=594 - ('Meatcake',), # index=595 - ('Buttermilk pie',), # index=596 - ('Kalamay',), # index=597 - ('Puto',), # index=598 - ('Dal makhani',), # index=599 - ('Mixiote',), # index=600 - ('Bagel dog',), # index=601 - ('B\xc3\xban ri\xc3\xaau',), # index=602 - ('Feijoada',), # index=603 - ('Pho',), # index=604 - ('Milk toast',), # index=605 - ('Liver and onions',), # index=606 - ('Iced bun',), # index=607 - ('Sheer khurma',), # index=608 - ('Yi mein',), # index=609 - ('Shrimp roe noodles',), # index=610 - ('Lai fun',), # index=611 - ('Oil noodles',), # index=612 - ('Kal-guksu',), # index=613 - ('Youmian',), # index=614 - ('Avgolemono',), # index=615 - ('Pork roll',), # index=616 - ('Tart',), # index=617 - ('Leberk\xc3\xa4se',), # index=618 - ('Kalakukko',), # index=619 - ('Mustamakkara',), # index=620 - ('Baba ghanoush',), # index=621 - ('Karelian pasty',), # index=622 - ('Shortcake',), # index=623 - ('Profiterole',), # index=624 - ('Moussaka',), # index=625 - ('Dulce de leche',), # index=626 - ('Blaa',), # index=627 - ('Risotto',), # index=628 - ('Funnel cake',), # index=629 - ('Fried dough',), # index=630 - ('Consomm\xc3\xa9',), # index=631 - ('Clam chowder',), # index=632 - ('Tartiflette',), # index=633 - ('Red curry',), # index=634 - ('Tandoori chicken',), # index=635 - ('Gazpacho',), # index=636 - ('Prosciutto',), # index=637 - ('Boerewors',), # index=638 - ('Baked potato',), # index=639 - ('Bouillabaisse',), # index=640 - ('Kralan',), # index=641 - ('Chireta',), # index=642 - ('Bakewell tart',), # index=643 - ('Grits',), # index=644 - ('Shaved ice',), # index=645 - ('Choco pie',), # index=646 - ('Cumian',), # index=647 - ('Jokbal',), # index=648 - ('Grillades',), # index=649 - ('Hotteok',), # index=650 - ('Ezogelin soup',), # index=651 - ('Knedle',), # index=652 - ('Masgouf',), # index=653 - ('Sope',), # index=654 - ('Coconut rice',), # index=655 - ('Bakarkhani',), # index=656 - ('Asida',), # index=657 - ('Dirt cake',), # index=658 - ('Sel roti',), # index=659 - ('Kalakand',), # index=660 - ('Ghevar',), # index=661 - ('Sussex pond pudding',), # index=662 - ('Lontong',), # index=663 - ('B\xc3\xa1nh b\xc3\xa8o',), # index=664 - ('Pring\xc3\xa1',), # index=665 - ('Bull roast',), # index=666 - ('Stuffed ham',), # index=667 - ('Lablabi',), # index=668 - ('Gooey butter cake',), # index=669 - ('Carciofi alla giudia',), # index=670 - ('Yin si juan',), # index=671 - ('Babi panggang',), # index=672 - ('Chao hong guo',), # index=673 - ('Fun guo',), # index=674 - ('Khira sagara',), # index=675 - ('Coconut bar',), # index=676 - ('Sundae',), # index=677 - ('Tuna fish sandwich',), # index=678 - ('Zhangcha duck',), # index=679 - ('Marry girl cake',), # index=680 - ('Frijoles charros',), # index=681 - ('Rosca de reyes',), # index=682 - ('Happy Faces',), # index=683 - ('Deviled crab',), # index=684 - ('Sundubu-jjigae',), # index=685 - ('Sinseollo',), # index=686 - ('Dongchimi',), # index=687 - ('Nabak-kimchi',), # index=688 - ('Dhondas',), # index=689 - ('Soan papdi',), # index=690 - ('Baek-kimchi',), # index=691 - ('Chicken riggies',), # index=692 - ('Afelia',), # index=693 - ('Guly\xc3\xa1sleves',), # index=694 - ('Marie biscuit',), # index=695 - ('Caf\xc3\xa9 li\xc3\xa9geois',), # index=696 - ('Ch\xc3\xa8',), # index=697 - ('Pootharekulu',), # index=698 - ('Escalope',), # index=699 - ('Rajma',), # index=700 - ('Beshbarmak',), # index=701 - ('Torta Tre Monti',), # index=702 - ('French dip',), # index=703 - ('Pumpkin-coconut custard',), # index=704 - ('Rose hip soup',), # index=705 - ('Veggie burger',), # index=706 - ('Steak tartare',), # index=707 - ('Bologna sausage',), # index=708 - ('P\xc3\xa2t\xc3\xa9',), # index=709 - ('Bibimbap',), # index=710 - ('Shahi paneer',), # index=711 - ('Fufu',), # index=712 - ('Pyttipanna',), # index=713 - ('Chicken sandwich',), # index=714 - ('Ghari',), # index=715 - ('Michigan salad',), # index=716 - ('Cabinet pudding',), # index=717 - ('American fried rice',), # index=718 - ('Korovai',), # index=719 - ('Churrasco',), # index=720 - ('Pasulj',), # index=721 - ('Mitraillette',), # index=722 - ('Salat\xc4\x83 de boeuf',), # index=723 - ('Rice pudding',), # index=724 - ('R\xc3\xb6sti',), # index=725 - ('Naryn',), # index=726 - ('Kaldereta',), # index=727 - ('Makroudh',), # index=728 - ('Kachumbari',), # index=729 - ('Tsukemono',), # index=730 - ('Cheese fries',), # index=731 - ('Slatko',), # index=732 - ('Qatayef',), # index=733 - ('Passatelli',), # index=734 - ('Sweet potato soup',), # index=735 - ('Shchi',), # index=736 - ('Kulfi',), # index=737 - ('Dolma',), # index=738 - ('Kai yang',), # index=739 - ('Shark fin soup',), # index=740 - ('Pozole',), # index=741 - ('Pakora',), # index=742 - ('Chantilly cake',), # index=743 - ('Kr\xc3\xb3wki',), # index=744 - ('Russian tea cake',), # index=745 - ('Ox-tongue pastry',), # index=746 - ('Sachertorte',), # index=747 - ('Palitaw',), # index=748 - ('Jolpan',), # index=749 - ('Mantou',), # index=750 - ('Finger steaks',), # index=751 - ('Steak sandwich',), # index=752 - ('Talo',), # index=753 - ('Erkuai',), # index=754 - ('Mixian',), # index=755 - ('St. Louis-style pizza',), # index=756 - ('Moambe',), # index=757 - ('Upma',), # index=758 - ('Panjiri',), # index=759 - ('Eggs Sardou',), # index=760 - ('Shanghai fried noodles',), # index=761 - ('Quarkk\xc3\xa4ulchen',), # index=762 - ('Cupcake',), # index=763 - ('Snickerdoodle',), # index=764 - ('Farl',), # index=765 - ('Coleslaw',), # index=766 - ('Calas',), # index=767 - ('Beef Stroganoff',), # index=768 - ('Shimotsukare',), # index=769 - ('Squab',), # index=770 - ('Basbousa',), # index=771 - ('Watalappam',), # index=772 - ('Tepsi baytinijan',), # index=773 - ('Kuli-kuli',), # index=774 - ('Shabu-shabu',), # index=775 - ('Sundae',), # index=776 - ('Fried brain sandwich',), # index=777 - ('Rollmops',), # index=778 - ('Higashi',), # index=779 - ('Panna cotta',), # index=780 - ('Aloo gobi',), # index=781 - ('Aspic',), # index=782 - ('Obatzda',), # index=783 - ('Gulab jamun',), # index=784 - ('Tuna casserole',), # index=785 - ('Ribollita',), # index=786 - ('Chomchom',), # index=787 - ('Rassolnik',), # index=788 - ('Jeongol',), # index=789 - ('Cantonese seafood soup',), # index=790 - ('Mashed Eggplant Salad',), # index=791 - ('K\xc3\xbcrt\xc5\x91skal\xc3\xa1cs',), # index=792 - ('P\xc3\xb6lsa',), # index=793 - ('Lobster roll',), # index=794 - ('Sloppy joe',), # index=795 - ('Schnitzel',), # index=796 - ('Bacalhau',), # index=797 - ('Sfenj',), # index=798 - ('Menudo',), # index=799 - ('Gujia',), # index=800 - ('Liver soup',), # index=801 - ('Panocha',), # index=802 - ('Chakapuli',), # index=803 - ('Sklandrausis',), # index=804 - ('Liver p\xc3\xa2t\xc3\xa9',), # index=805 - ('Rullep\xc3\xb8lse',), # index=806 - ('Frikadeller',), # index=807 - ('Frikandel',), # index=808 - ('Cinnamon roll',), # index=809 - ('Scotch pie',), # index=810 - ('Hot wiener',), # index=811 - ('Wodzionka',), # index=812 - ('Greek salad',), # index=813 - ('Raita',), # index=814 - ("Dong'an chicken",), # index=815 - ('Boortsog',), # index=816 - ('Coca',), # index=817 - ('Champon',), # index=818 - ('Tabbouleh',), # index=819 - ('Korokke',), # index=820 - ('Chile relleno',), # index=821 - ('Brandade',), # index=822 - ('Hoppang',), # index=823 - ('Gozinaki',), # index=824 - ('Lazarakia',), # index=825 - ('Puff Puff',), # index=826 - ('Fatteh',), # index=827 - ('Speculaas',), # index=828 - ('Karasumi',), # index=829 - ('Brandy snaps',), # index=830 - ('Trdeln\xc3\xadk',), # index=831 - ('Cocido madrile\xc3\xb1o',), # index=832 - ('Red velvet cake',), # index=833 - ('Kringle',), # index=834 - ('Quenelle',), # index=835 - ('Toasted ravioli',), # index=836 - ('Tajine',), # index=837 - ('Cranachan',), # index=838 - ('Rusk',), # index=839 - ('Mille-feuille',), # index=840 - ('Acorn noodle soup',), # index=841 - ('Gachas',), # index=842 - ('Jingisukan',), # index=843 - ('Thekua',), # index=844 - ('Ghugni',), # index=845 - ('Taramasalata',), # index=846 - ('Italian beef',), # index=847 - ('Challah',), # index=848 - ('Fried ice cream',), # index=849 - ('Onion ring',), # index=850 - ('Smoked meat',), # index=851 - ('Dahi vada',), # index=852 - ('Mother-in-law',), # index=853 - ('Blondie',), # index=854 - ('Guk',), # index=855 - ('Hiyashi ch\xc5\xabka',), # index=856 - ('Sweet shells',), # index=857 - ('Salisbury steak',), # index=858 - ('Poffertjes',), # index=859 - ('Eggs Neptune',), # index=860 - ('Galbi-jjim',), # index=861 - ('Agwi-jjim',), # index=862 - ('Ladob',), # index=863 - ('Instant-boiled mutton',), # index=864 - ('Cincalok',), # index=865 - ('Jook-sing noodles',), # index=866 - ('Potbrood',), # index=867 - ('Burkinab\xc3\xa9 cuisine',), # index=868 - ('Taralli',), # index=869 - ('Carbonade flamande',), # index=870 - ('X\xc3\xb4i',), # index=871 - ('Sauerbraten',), # index=872 - ('Spiedie',), # index=873 - ('Gimbap',), # index=874 - ('Czernina',), # index=875 - ('Kroppkaka',), # index=876 - ("Buddha's delight",), # index=877 - ('Pain au chocolat',), # index=878 - ('Goetta',), # index=879 - ('German chocolate cake',), # index=880 - ('Melt sandwich',), # index=881 - ('Popiah',), # index=882 - ('Haleem',), # index=883 - ('Hornazo',), # index=884 - ('Janchi-guksu',), # index=885 - ('Kipper',), # index=886 - ('Bossam',), # index=887 - ('Arbroath smokie',), # index=888 - ('Bologna sandwich',), # index=889 - ('Cobbler',), # index=890 - ('Kouign-amann',), # index=891 - ('Char kway teow',), # index=892 - ('Rostbr\xc3\xa4tel',), # index=893 - ('Doenjang-jjigae',), # index=894 - ('Tharid',), # index=895 - ('Hainanese chicken rice',), # index=896 - ('Bak kut teh',), # index=897 - ('Cabbage roll',), # index=898 - ('Runza',), # index=899 - ('Bananas Foster',), # index=900 - ('Kozhukkatta',), # index=901 - ('K\xc5\xab\xc4\x8diukai',), # index=902 - ('Sm\xc3\xb8rrebr\xc3\xb8d',), # index=903 - ('Kutia',), # index=904 - ('Deviled egg',), # index=905 - ('Buchteln',), # index=906 - ('Apple strudel',), # index=907 - ('Wonton',), # index=908 - ('Chess pie',), # index=909 - ('Pirozhki',), # index=910 - ('Douzhi',), # index=911 - ('Macaroni soup',), # index=912 - ('Crossing the bridge noodles',), # index=913 - ('Lechazo',), # index=914 - ('Rolled oyster',), # index=915 - ('Asam pedas',), # index=916 - ('Mi krop',), # index=917 - ('Patoleo',), # index=918 - ('Rig\xc3\xb3 Jancsi',), # index=919 - ('Ollada',), # index=920 - ('Garbure',), # index=921 - ('Sabudana Khichadi',), # index=922 - ('Pot\xc3\xa9e',), # index=923 - ('Phanaeng curry',), # index=924 - ('Madeleine',), # index=925 - ('Mashed pumpkin',), # index=926 - ('Suet pudding',), # index=927 - ('Bombay mix',), # index=928 - ('Namagashi',), # index=929 - ('Struffoli',), # index=930 - ('Dak-galbi',), # index=931 - ('Dumpling',), # index=932 - ('Misal',), # index=933 - ('Patatnik',), # index=934 - ('Yuxiang',), # index=935 - ('Frozen banana',), # index=936 - ('Psarosoupa',), # index=937 - ('Mekitsa',), # index=938 - ('Sanna',), # index=939 - ('Kazy',), # index=940 - ('Sorbetes',), # index=941 - ("Potatoes O'Brien",), # index=942 - ('Tom yum',), # index=943 - ('Balushahi',), # index=944 - ('Arroz a la cubana',), # index=945 - ('Jalebi',), # index=946 - ('Sopaipilla',), # index=947 - ('Ukha',), # index=948 - ('Sv\xc3\xad\xc4\x8dkov\xc3\xa1',), # index=949 - ('T\xc3\xbar\xc3\xb3s csusza',), # index=950 - ('Pinnekj\xc3\xb8tt',), # index=951 - ('Salty liquorice',), # index=952 - ('Lemon ice box pie',), # index=953 - ('Knickerbocker glory',), # index=954 - ('Zhajiangmian',), # index=955 - ('Cobb salad',), # index=956 - ('Misua',), # index=957 - ('Shoofly pie',), # index=958 - ('Bhakri',), # index=959 - ('Apple cake',), # index=960 - ('Orange chicken',), # index=961 - ('Jam\xc3\xb3n serrano',), # index=962 - ('Bundt cake',), # index=963 - ('Bara brith',), # index=964 - ('Hot pot',), # index=965 - ('Kung Pao chicken',), # index=966 - ('Mulukhiyah',), # index=967 - ('Piti',), # index=968 - ('Double ka meetha',), # index=969 - ('Choila',), # index=970 - ('Moustalevria',), # index=971 - ('Arizona cheese crisp',), # index=972 - ('Rice Krispies Treats',), # index=973 - ('Liangpi',), # index=974 - ('Prinskorv',), # index=975 - ('Salmorejo',), # index=976 - ('Chicken Fran\xc3\xa7aise',), # index=977 - ('Fl\xc3\xa4skkorv',), # index=978 - ('Glorified rice',), # index=979 - ('Shishbarak',), # index=980 - ('Stinky tofu',), # index=981 - ('Muffuletta',), # index=982 - ('Soy sauce chicken',), # index=983 - ('Chicken fingers',), # index=984 - ('Pecan pie',), # index=985 - ('Eba',), # index=986 - ('Parfait',), # index=987 - ('Ndol\xc3\xa9',), # index=988 - ('Cheese sandwich',), # index=989 - ("Carne de vinha d'alhos",), # index=990 - ('Bob Andy pie',), # index=991 - ('Cincinnati chili',), # index=992 - ('Frico',), # index=993 - ('Tapioca pudding',), # index=994 - ('Minestrone',), # index=995 - ('Boxty',), # index=996 - ('Naengmyeon',), # index=997 - ('Seven-layer salad',), # index=998 - ('Samgyeopsal',), # index=999 - ('Cawl',), # index=1000 - ('Chocolate pudding',), # index=1001 - ('Hotdish',), # index=1002 - ('Ciccioli',), # index=1003 - ('Douhua',), # index=1004 - ('Berliner',), # index=1005 - ('Fried fish',), # index=1006 - ('Apple crisp',), # index=1007 - ('Boudin',), # index=1008 - ('Yusheng',), # index=1009 - ('Babka',), # index=1010 - ('Pizzoccheri',), # index=1011 - ('Welsh cake',), # index=1012 - ('Parker House roll',), # index=1013 - ('Tripe soups',), # index=1014 - ('Chimichanga',), # index=1015 - ('Jucy Lucy',), # index=1016 - ('Dodger Dog',), # index=1017 - ('Pastiera',), # index=1018 - ('Huarache',), # index=1019 - ('Solkadhi',), # index=1020 - ('Schupfnudel',), # index=1021 - ('Waldorf pudding',), # index=1022 - ('Harees',), # index=1023 - ('Ash reshteh',), # index=1024 - ('Celery Victor',), # index=1025 - ('Diples',), # index=1026 - ('Kompot',), # index=1027 - ('French onion soup',), # index=1028 - ('Tres leches cake',), # index=1029 - ('Torta caprese',), # index=1030 - ('Black Forest gateau',), # index=1031 - ('P\xc3\xa2t\xc3\xa9 aux pommes de terre',), # index=1032 - ('L\xc3\xa2pa',), # index=1033 - ('B\xc3\xbcndner Nusstorte',), # index=1034 - ('Hachee',), # index=1035 - ('Spaghetti aglio e olio',), # index=1036 - ('Whoopie pie',), # index=1037 - ('Ais kacang',), # index=1038 - ('Chermoula',), # index=1039 - ('Gado-gado',), # index=1040 - ('Merguez',), # index=1041 - ('Snickers salad',), # index=1042 - ('Giouvetsi',), # index=1043 - ('Kharcho',), # index=1044 - ('Chicken fried bacon',), # index=1045 - ('Dessert bar',), # index=1046 - ('Coulibiac',), # index=1047 - ('Thieboudienne',), # index=1048 - ('Rabri',), # index=1049 - ('Sapin-sapin',), # index=1050 - ('Sealed crustless sandwich',), # index=1051 - ('Carne asada',), # index=1052 - ('Coyotas',), # index=1053 - ('Chocolate-covered bacon',), # index=1054 - ('Stroopwafel',), # index=1055 - ('Gravlax',), # index=1056 - ('Pot pie',), # index=1057 - ('Ghormeh sabzi',), # index=1058 - ('Surf and turf',), # index=1059 - ('Brunswick stew',), # index=1060 - ('Mititei',), # index=1061 - ('Fluffernutter',), # index=1062 - ('Khaja',), # index=1063 - ('Stottie cake',), # index=1064 - ('London broil',), # index=1065 - ('Fasolada',), # index=1066 - ('Strudel',), # index=1067 - ('\xc3\x98llebr\xc3\xb8d',), # index=1068 - ('Tamago kake gohan',), # index=1069 - ('Hot water corn bread',), # index=1070 - ('Philippine adobo',), # index=1071 - ('Hulatang',), # index=1072 - ('Dyrl\xc3\xa6gens natmad',), # index=1073 - ('Chistorra',), # index=1074 - ('Polkagris',), # index=1075 - ('Galbi-tang',), # index=1076 - ('Mrouzia',), # index=1077 - ('Gopchang-jeongol',), # index=1078 - ('Miang kham',), # index=1079 - ('Clams casino',), # index=1080 - ('Nanbanzuke',), # index=1081 - ('Dripping cake',), # index=1082 - ('Cookie salad',), # index=1083 - ('Usal',), # index=1084 - ('Mandu-guk',), # index=1085 - ('Smalahove',), # index=1086 - ('Kokis',), # index=1087 - ('Ori-tang',), # index=1088 - ('Pakhala',), # index=1089 - ('Cream pie',), # index=1090 - ('Butajiru',), # index=1091 - ('New England boiled dinner',), # index=1092 - ('Chhena jalebi',), # index=1093 - ('Pastitsio',), # index=1094 - ('Panucho',), # index=1095 - ('Chhena kheeri',), # index=1096 - ('Kifli',), # index=1097 - ('Solyanka',), # index=1098 - ('Sadhya',), # index=1099 - ('Cullen skink',), # index=1100 - ('Chokladboll',), # index=1101 - ('Harira',), # index=1102 - ('Cornish game hen',), # index=1103 - ('Beef on weck',), # index=1104 - ('Tompouce',), # index=1105 - ('Caldo de siete mares',), # index=1106 - ('Millionb\xc3\xb8f',), # index=1107 - ('Chicago-style hot dog',), # index=1108 - ('Risalamande',), # index=1109 - ('Alinazik kebab',), # index=1110 - ('Medisterp\xc3\xb8lse',), # index=1111 - ('Sarson da saag',), # index=1112 - ('Liangfen',), # index=1113 - ('Pistolette',), # index=1114 - ('Steamed clams',), # index=1115 - ('Ulam',), # index=1116 - ('Kheer',), # index=1117 - ('Tlacoyo',), # index=1118 - ('Tarator',), # index=1119 - ('Hu tieu',), # index=1120 - ('Teja',), # index=1121 - ('Cochinita pibil',), # index=1122 - ('Buddha Jumps Over the Wall',), # index=1123 - ('Sfouf',), # index=1124 - ('Ham and cheese sandwich',), # index=1125 - ('Peanut butter', 'banana and bacon sandwich'), # index=1126 - ('Bacon', 'egg and cheese sandwich'), # index=1127 - ('Chicken karahi',), # index=1128 - ('Maple bacon donut',), # index=1129 - ('Litti',), # index=1130 - ('Nam khao',), # index=1131 - ('Nam tok',), # index=1132 - ('Baozi',), # index=1133 - ('Kibbeh',), # index=1134 - ('Kushari',), # index=1135 - ('Jiuniang',), # index=1136 - ('Aseed',), # index=1137 - ('Machher Jhol',), # index=1138 - ('Fahsa',), # index=1139 - ('Mysore pak',), # index=1140 - ('Chalupa',), # index=1141 - ('Swiss roll',), # index=1142 - ('Balkenbrij',), # index=1143 - ('Tortas de aceite',), # index=1144 - ('Popover',), # index=1145 - ('Falooda',), # index=1146 - ('Macaroni salad',), # index=1147 - ('Barbacoa',), # index=1148 - ('Hushpuppy',), # index=1149 - ('Luther Burger',), # index=1150 - ('Ragout',), # index=1151 - ('B\xc3\xa1nh bao',), # index=1152 - ('Moronga',), # index=1153 - ('Hayashi rice',), # index=1154 - ('Z\xc3\xbcrcher Geschnetzeltes',), # index=1155 - ('\xc3\x89clair',), # index=1156 - ('Colcannon',), # index=1157 - ('Bear claw',), # index=1158 - ('Francesinha',), # index=1159 - ('Wat',), # index=1160 - ('Loco moco',), # index=1161 - ('Hot milk cake',), # index=1162 - ('Hoe',), # index=1163 - ('Gordita',), # index=1164 - ('Macaron',), # index=1165 - ('Pepperoni roll',), # index=1166 - ('Rasgulla',), # index=1167 - ('Angel wings',), # index=1168 - ('Huevos rancheros',), # index=1169 - ('Caprese salad',), # index=1170 - ('Kombdi vade',), # index=1171 - ('Yong Tau Foo',), # index=1172 - ('Chai tow kway',), # index=1173 - ('Machaca',), # index=1174 - ('Ugali',), # index=1175 - ('Arr\xc3\xb2s negre',), # index=1176 - ('Kimchi fried rice',), # index=1177 - ('Frybread',), # index=1178 - ('Halo-halo',), # index=1179 - ('Shiokara',), # index=1180 - ('Janssons frestelse',), # index=1181 - ('Hot Brown',), # index=1182 - ('Torta',), # index=1183 - ('\xc4\x86evapi',), # index=1184 - ('Salt water taffy',), # index=1185 - ('\xc3\x87\xc4\xb1lb\xc4\xb1r',), # index=1186 - ('Murtabak',), # index=1187 - ('Tahu goreng',), # index=1188 - ('Soto ayam',), # index=1189 - ('Mee siam',), # index=1190 - ('Submarine sandwich',), # index=1191 - ('Halu\xc5\xa1ky',), # index=1192 - ('Kimchi-jjigae',), # index=1193 - ('Fish ball',), # index=1194 - ('Blodpalt',), # index=1195 - ('Lebanon bologna',), # index=1196 - ('Okroshka',), # index=1197 - ('Linzer torte',), # index=1198 - ('Shrikhand',), # index=1199 - ('Yakiniku',), # index=1200 - ('Huevos divorciados',), # index=1201 - ('Nihari',), # index=1202 - ('Saut\xc3\xa9ed reindeer',), # index=1203 - ('Hasty pudding',), # index=1204 - ('Mission burrito',), # index=1205 - ('Sweet and sour pork',), # index=1206 - ('R\xc3\xb8dgr\xc3\xb8d',), # index=1207 - ('Booyah',), # index=1208 - ('Bienenstich',), # index=1209 - ('Dressed herring',), # index=1210 - ('New York-style pizza',), # index=1211 - ('Bistek',), # index=1212 - ('Sinigang',), # index=1213 - ('Fios de ovos',), # index=1214 - ('Vitello tonnato',), # index=1215 - ('Bisque',), # index=1216 - ('Khao tom',), # index=1217 - ('Modak',), # index=1218 - ('New Haven-style pizza',), # index=1219 - ('California-style pizza',), # index=1220 - ('Wrap',), # index=1221 - ('Puri',), # index=1222 - ('Jam\xc3\xb3n',), # index=1223 - ('Khash',), # index=1224 - ('Beef bourguignon',), # index=1225 - ('Truffade',), # index=1226 - ('B\xc3\xb2 n\xc6\xb0\xe1\xbb\x9bng l\xc3\xa1 l\xe1\xbb\x91t', - ), # index=1227 - ('Ful medames',), # index=1228 - ('Aligot',), # index=1229 - ('Kolach',), # index=1230 - ('Guaiwei',), # index=1231 - ('Kesme',), # index=1232 - ('Funeral potatoes',), # index=1233 - ('Sushi',), # index=1234 - ('Arancini',), # index=1235 - ('Creamed corn',), # index=1236 - ('Mozzarella sticks',), # index=1237 - ('American goulash',), # index=1238 - ('Gofio',), # index=1239 - ('Soup alla Canavese',), # index=1240 - ('Red beans and rice',), # index=1241 - ('R\xc3\xb6ssypottu',), # index=1242 - ('Fl\xc3\xa4skpannkaka',), # index=1243 - ('Hyderabadi biryani',), # index=1244 - ('Baeckeoffe',), # index=1245 - ('Eton mess',), # index=1246 - ('Khachapuri',), # index=1247 - ('Banoffee pie',), # index=1248 - ('Ants climbing a tree',), # index=1249 - ('Dandan noodles',), # index=1250 - ('Suanla chaoshou',), # index=1251 - ('Samgye-tang',), # index=1252 - ('Spam musubi',), # index=1253 - ('Bridie',), # index=1254 - ('Kaju katli',), # index=1255 - ('Chocolate-covered potato chips',), # index=1256 - ('Enne gai',), # index=1257 - ('Ruske kape',), # index=1258 - ('Spaghetti',), # index=1259 - ('Grass jelly',), # index=1260 - ('Salt potatoes',), # index=1261 - ('Katsudon',), # index=1262 - ('Pasanda',), # index=1263 - ('Banitsa',), # index=1264 - ('Tarte flamb\xc3\xa9e',), # index=1265 - ('Twice cooked pork',), # index=1266 - ('Kare-kare',), # index=1267 - ('Laobing',), # index=1268 - ('Banmian',), # index=1269 - ('Ontbijtkoek',), # index=1270 - ('Swiss wing',), # index=1271 - ('Michigan hot dog',), # index=1272 - ('Tong sui',), # index=1273 - ('Taco',), # index=1274 - ('Sosatie',), # index=1275 - ('Pap',), # index=1276 - ('Umngqusho',), # index=1277 - ('Malva pudding',), # index=1278 - ('Vichyssoise',), # index=1279 - ('Z\xc5\x8dni',), # index=1280 - ('Maxwell Street Polish',), # index=1281 - ('Vetkoek',), # index=1282 - ('Mealie bread',), # index=1283 - ('Chakalaka',), # index=1284 - ('Frikkadel',), # index=1285 - ('Pizza strips',), # index=1286 - ('Tteokguk',), # index=1287 - ('Coney Island hot dog',), # index=1288 - ('Tirokafteri',), # index=1289 - ('Fesikh',), # index=1290 - ('Boston cream pie',), # index=1291 - ('Buttermilk koldsk\xc3\xa5l',), # index=1292 - ('White boiled shrimp',), # index=1293 - ('Bagnun',), # index=1294 - ('Buntil',), # index=1295 - ('Kaiserschmarrn',), # index=1296 - ('Pisto',), # index=1297 - ('Dhokla',), # index=1298 - ('Al pastor',), # index=1299 - ('St. Paul sandwich',), # index=1300 - ('Melonpan',), # index=1301 - ('Haupia',), # index=1302 - ('L\xc3\xa1ngos',), # index=1303 - ('\xc3\x89touff\xc3\xa9e',), # index=1304 - ('Galaktoboureko',), # index=1305 - ('B\xc3\xb6rek',), # index=1306 - ('Suya',), # index=1307 - ('Rye bread',), # index=1308 - ("Escudella i carn d'olla",), # index=1309 - ('Gari',), # index=1310 - ('Tilkut',), # index=1311 - ('Botok',), # index=1312 - ('Tatws Pum Munud',), # index=1313 - ('Char siu',), # index=1314 - ('Burgoo',), # index=1315 - ('Cac\xc4\xb1k',), # index=1316 - ('Barfi',), # index=1317 - ('Mulligan stew',), # index=1318 - ('Biangbiang noodles',), # index=1319 - ('Banana pudding',), # index=1320 - ('Crab cake',), # index=1321 - ('Chinese sausage',), # index=1322 - ('Veal',), # index=1323 - ('Curry bread',), # index=1324 - ('Pastry heart',), # index=1325 - ('Cr\xc3\xa8me caramel',), # index=1326 - ('Panada',), # index=1327 - ('Pie \xc3\xa0 la Mode',), # index=1328 - ('Bonus Jack',), # index=1329 - ('Princess cake',), # index=1330 - ('Harihari-nabe',), # index=1331 - ('Hot chicken',), # index=1332 - ('Chhena Jhili',), # index=1333 - ('Grape pie',), # index=1334 - ('Chicken bog',), # index=1335 - ('Sausage gravy',), # index=1336 - ('Derby Pie',), # index=1337 - ('Ice cream cake',), # index=1338 - ('Swiss steak',), # index=1339 - ('Bagna c\xc3\xa0uda',), # index=1340 - ('Stack cake',), # index=1341 - ('Lobster Newberg',), # index=1342 - ('Nikujaga',), # index=1343 - ('Manti',), # index=1344 - ('Parmigiana',), # index=1345 - ('Palatschinke',), # index=1346 - ('Gujeolpan',), # index=1347 - ('Rajas con crema',), # index=1348 - ('Mak-guksu',), # index=1349 - ('Tetrazzini',), # index=1350 - ('Squid as food',), # index=1351 - ('Palak paneer',), # index=1352 - ('Krumkake',), # index=1353 - ('Bolani',), # index=1354 - ('Pork and beans',), # index=1355 - ('Nian gao',), # index=1356 - ('Oysters Rockefeller',), # index=1357 - ('Tav\xc4\x8de grav\xc4\x8de',), # index=1358 - ('Bakkwa',), # index=1359 - ('Xacuti',), # index=1360 - ('Sarapatel',), # index=1361 - ('Taquito',), # index=1362 - ('Egg drop soup',), # index=1363 - ('Shaobing',), # index=1364 - ('Chawanmushi',), # index=1365 - ('Nshima',), # index=1366 - ('Pollock roe',), # index=1367 - ('Slinger',), # index=1368 - ('Japchae',), # index=1369 - ('St. Honor\xc3\xa9 cake',), # index=1370 - ('Barm cake',), # index=1371 - ('Tulumba',), # index=1372 - ('Xiaolongbao',), # index=1373 - ('Delmonico steak',), # index=1374 - ('Stromboli',), # index=1375 - ('Kanafeh',), # index=1376 - ('Hamdog',), # index=1377 - ('Garri',), # index=1378 - ('Kofta',), # index=1379 - ('Chana masala',), # index=1380 - ('Salo',), # index=1381 - ('Lung fung soup',), # index=1382 - ('Dirty rice',), # index=1383 - ('Urnebes',), # index=1384 - ('Andouillette',), # index=1385 - ('Landj\xc3\xa4ger',), # index=1386 - ("Fisherman's soup",), # index=1387 - ('Romeritos',), # index=1388 - ('Lane cake',), # index=1389 - ('Pork jelly',), # index=1390 - ('Idiyappam',), # index=1391 - ('Sm\xc3\xb6rg\xc3\xa5st\xc3\xa5rta',), # index=1392 - ('Sma\xc5\xbeen\xc3\xbd s\xc3\xbdr',), # index=1393 - ('Arroz con pollo',), # index=1394 - ('Lahmacun',), # index=1395 - ('Molten chocolate cake',), # index=1396 - ('Tea egg',), # index=1397 - ('Cocada amarela',), # index=1398 - ('Japanese curry',), # index=1399 - ('Keema',), # index=1400 - ('Unagi',), # index=1401 - ("Hoppin' John",), # index=1402 - ('Gy\xc5\xabhi',), # index=1403 - ('Clafoutis',), # index=1404 - ('Green curry',), # index=1405 - ('G\xe1\xbb\x8fi cu\xe1\xbb\x91n',), # index=1406 - ('Chilli crab',), # index=1407 - ('Lo mai gai',), # index=1408 - ('Lo mein',), # index=1409 - ('Puttu',), # index=1410 - ('Fried pie',), # index=1411 - ('Spanish rice',), # index=1412 - ('Nuea phat phrik',), # index=1413 - ('Jeow bong',), # index=1414 - ('Massaman curry',), # index=1415 - ('Ostkaka',), # index=1416 - ('Guilinggao',), # index=1417 - ('Spettekaka',), # index=1418 - ('Cudighi',), # index=1419 - ('Saltimbocca',), # index=1420 - ('Sfogliatella',), # index=1421 - ('Beef chow fun',), # index=1422 - ('Chow mein sandwich',), # index=1423 - ('Carnitas',), # index=1424 - ('Chinese steamed eggs',), # index=1425 - ('Oyster omelette',), # index=1426 - ('Garden salad',), # index=1427 - ('Salade ni\xc3\xa7oise',), # index=1428 - ('Dal bhat',), # index=1429 - ('Biscuits and gravy',), # index=1430 - ('Omurice',), # index=1431 - ('Pao cai',), # index=1432 - ('Nasi liwet',), # index=1433 - ('Thai suki',), # index=1434 - ('Moo shu pork',), # index=1435 - ('Corn crab soup',), # index=1436 - ('Fabes con almejas',), # index=1437 - ('Golden Opulence Sundae',), # index=1438 - ('Ketoprak',), # index=1439 - ('Mala Mogodu',), # index=1440 - ('Tekwan',), # index=1441 - ('Vatrushka',), # index=1442 - ('Yin Yang fish',), # index=1443 - ('Boston cream doughnut',), # index=1444 - ('Ramen',), # index=1445 - ('Home fries',), # index=1446 - ('Mustacciuoli',), # index=1447 - ('Clam cake',), # index=1448 - ('Sarma',), # index=1449 - ('Shahe fen',), # index=1450 - ('Charleston red rice',), # index=1451 - ('Fish head curry',), # index=1452 - ('Podvarak',), # index=1453 - ('Pihtije',), # index=1454 - ('Popara',), # index=1455 - ('Ka\xc4\x8damak',), # index=1456 - ('Seolleongtang',), # index=1457 - ('Go\xc5\x82\xc4\x85bki',), # index=1458 - ('Szaloncukor',), # index=1459 - ('Kalduny',), # index=1460 - ('Zrazy',), # index=1461 - ('Panettone',), # index=1462 - ('Ambelopoulia',), # index=1463 - ('Persimmon pudding',), # index=1464 - ('Floating island',), # index=1465 - ('Zeeuwse bolus',), # index=1466 - ('Ambuyat',), # index=1467 - ('Smulpaj',), # index=1468 - ('Moravian spice cookies',), # index=1469 - ('Mee pok',), # index=1470 - ('Jjigae',), # index=1471 - ('Pizza bagel',), # index=1472 - ('Tteok',), # index=1473 - ('Br\xc3\xa6ndende k\xc3\xa6rlighed',), # index=1474 - ('Beaten biscuit',), # index=1475 - ('\xc3\x86blefl\xc3\xa6sk',), # index=1476 - ('Chicken paprikash',), # index=1477 - ('Tangyuan',), # index=1478 - ('Tuna pot',), # index=1479 - ('Burnt ends',), # index=1480 - ('Jam\xc3\xb3n ib\xc3\xa9rico',), # index=1481 - ('Rakfisk',), # index=1482 - ('Zarangollo',), # index=1483 - ('T\xc3\xbar\xc3\xb3 Rudi',), # index=1484 - ('Flummery',), # index=1485 - ('Cecina',), # index=1486 - ('Galinha \xc3\xa0 portuguesa',), # index=1487 - ('Ankimo',), # index=1488 - ('Galinha \xc3\xa0 africana',), # index=1489 - ('Cha siu bao',), # index=1490 - ('Fugu chiri',), # index=1491 - ('Assidat Zgougou',), # index=1492 - ('Oxtail stew',), # index=1493 - ('Laping',), # index=1494 - ('Chaku',), # index=1495 - ('Caldillo de perro',), # index=1496 - ('Sopa de Gato',), # index=1497 - ('Keledo\xc5\x9f',), # index=1498 - ('M\xc3\xbccver',), # index=1499 - ('Brotzeit',), # index=1500 - ('Shekerbura',), # index=1501 - ('Oeufs en meurette',), # index=1502 - ('Pappa al pomodoro',), # index=1503 - ('Teurgoule',), # index=1504 - ('B\xc3\xa1nh x\xc3\xa8o',), # index=1505 - ('Musakhan',), # index=1506 - ('Maqluba',), # index=1507 - ('Bob chorba',), # index=1508 - ('Rum baba',), # index=1509 - ('Veda bread',), # index=1510 - ('Fried prawn',), # index=1511 - ('Pastilla',), # index=1512 - ('Strawberry Delight',), # index=1513 - ('Cheese dream',), # index=1514 - ('Frejon',), # index=1515 - ('Gyeran-jjim',), # index=1516 - ('Revithia',), # index=1517 - ('Nasi bogana',), # index=1518 - ('Torta de gazpacho',), # index=1519 - ('Double Down',), # index=1520 - ('Seri Muka',), # index=1521 - ('Obi non',), # index=1522 - ('Garganelli',), # index=1523 - ('Kig ha farz',), # index=1524 - ('Mississippi mud pie',), # index=1525 - ("Eve's pudding",), # index=1526 - ('Amala',), # index=1527 - ('Okinawa soba',), # index=1528 - ('Lamian',), # index=1529 - ('Soki',), # index=1530 - ('Chicken Maryland',), # index=1531 - ('Chanpur\xc5\xab',), # index=1532 - ('Mlinci',), # index=1533 - ('Smyrna meatballs',), # index=1534 - ('Tavern sandwich',), # index=1535 - ('Yangzhou fried rice',), # index=1536 - ('Qutab',), # index=1537 - ('Dum Aloo',), # index=1538 - ('Queijo do Pico',), # index=1539 - ('Cocadas',), # index=1540 - ("Calf's liver and bacon",), # index=1541 - ('Moules-frites',), # index=1542 - ('Anarsa',), # index=1543 - ('Tlayuda',), # index=1544 - ('\xc5\xa0akotis',), # index=1545 - ('Jollof rice',), # index=1546 - ('Moin moin',), # index=1547 - ('Jam roly-poly',), # index=1548 - ('Hochzeitssuppe',), # index=1549 - ('Mucenici',), # index=1550 - ('Ema datshi',), # index=1551 - ('Ngo hiang',), # index=1552 - ('Jello salad',), # index=1553 - ('Claypot chicken rice',), # index=1554 - ('Maeun-tang',), # index=1555 - ('Cifantuan',), # index=1556 - ('Rhubarb pie',), # index=1557 - ('Olla podrida',), # index=1558 - ('Har gow',), # index=1559 - ('Sayur lodeh',), # index=1560 - ('Memela',), # index=1561 - ('Wenchang chicken',), # index=1562 - ('Galinhada',), # index=1563 - ('Lecs\xc3\xb3',), # index=1564 - ('Gypsy tart',), # index=1565 - ('Bougatsa',), # index=1566 - ('Germkn\xc3\xb6del',), # index=1567 - ('Haystack',), # index=1568 - ('Yule log',), # index=1569 - ('Butter cookie',), # index=1570 - ('Chicken \xc3\xa0 la King',), # index=1571 - ('M\xc3\xa9choui',), # index=1572 - ('Croquette',), # index=1573 - ('Shami kebab',), # index=1574 - ('Chicken and waffles',), # index=1575 - ('Poke',), # index=1576 - ('Punsch-roll',), # index=1577 - ('Turtle soup',), # index=1578 - ('Kansar',), # index=1579 - ('Glamorgan sausage',), # index=1580 - ('Mango pudding',), # index=1581 - ('B\xc3\xa1nh canh',), # index=1582 - ('Caparrones',), # index=1583 - ('Zopf',), # index=1584 - ('Bath bun',), # index=1585 - ('Chelsea bun',), # index=1586 - ('London bun',), # index=1587 - ('Saffron bun',), # index=1588 - ('Chakhchoukha',), # index=1589 - ('Angel food cake',), # index=1590 - ('Lalab',), # index=1591 - ('Suckling pig',), # index=1592 - ('Barmbrack',), # index=1593 - ('Kotlet schabowy',), # index=1594 - ('Pastel de nata',), # index=1595 - ('Shave ice',), # index=1596 - ('Tipsy cake',), # index=1597 - ('Creamed eggs on toast',), # index=1598 - ('Kerak telor',), # index=1599 - ('Ogok-bap',), # index=1600 - ('Mortadella',), # index=1601 - ('Nut roll',), # index=1602 - ('Fried green tomatoes',), # index=1603 - ('Beondegi',), # index=1604 - ('Tsoureki',), # index=1605 - ('Tiropita',), # index=1606 - ('Pljeskavica',), # index=1607 - ('Kara\xc4\x91or\xc4\x91eva \xc5\xa1nicla',), # index=1608 - ('Kokoretsi',), # index=1609 - ('Skilpadjies',), # index=1610 - ('Corn chowder',), # index=1611 - ('Tarhana',), # index=1612 - ('Tufahije',), # index=1613 - ('Birria',), # index=1614 - ('Veal Orloff',), # index=1615 - ('Fattoush',), # index=1616 - ('Pane carasau',), # index=1617 - ('Rab cake',), # index=1618 - ('Buffalo burger',), # index=1619 - ('Treacle tart',), # index=1620 - ('Hamburger',), # index=1621 - ('Stamppot',), # index=1622 - ('Kopytka',), # index=1623 - ('Khai yat sai',), # index=1624 - ('Minchee',), # index=1625 - ('Kinema',), # index=1626 - ('Sgabeo',), # index=1627 - ('Chili dog',), # index=1628 - ('Spaghetti alle vongole',), # index=1629 - ('Bavarian cream',), # index=1630 - ('Bhaji',), # index=1631 - ('Kachori',), # index=1632 - ('Chowder',), # index=1633 - ('Scotch broth',), # index=1634 - ('Pea soup',), # index=1635 - ('Kitfo',), # index=1636 - ('Gored gored',), # index=1637 - ('B\xc3\xa1nh ch\xc6\xb0ng',), # index=1638 - ('B\xc3\xban b\xc3\xb2 Hu\xe1\xba\xbf',), # index=1639 - ('B\xc3\xb2 7 m\xc3\xb3n',), # index=1640 - ('C\xc6\xa1m t\xe1\xba\xa5m',), # index=1641 - ('Ambrosia',), # index=1642 - ('R\xc3\xb6ntt\xc3\xb6nen',), # index=1643 - ('Balch\xc3\xa3o',), # index=1644 - ('Gibassier',), # index=1645 - ('Bacalhau \xc3\xa0 Z\xc3\xa9 do Pipo',), # index=1646 - ('Pane di Altamura',), # index=1647 - ('Mykyrokka',), # index=1648 - ('Paska',), # index=1649 - ('Blackberry pie',), # index=1650 - ('Mince pie',), # index=1651 - ('Corn cookie',), # index=1652 - ('Francesinha poveira',), # index=1653 - ('Picadillo',), # index=1654 - ('Runeberg torte',), # index=1655 - ('Khakhra',), # index=1656 - ('Ohn no khao sw\xc3\xa8',), # index=1657 - ('Sultsina',), # index=1658 - ('Kabab torsh',), # index=1659 - ('Paella',), # index=1660 - ('Espetada',), # index=1661 - ('Pathiri',), # index=1662 - ('Horumonyaki',), # index=1663 - ('Khubz',), # index=1664 - ('Ciorb\xc4\x83',), # index=1665 - ('Kimchi-buchimgae',), # index=1666 - ('Sesame chicken',), # index=1667 - ('Thukpa',), # index=1668 - ('Chwinamul',), # index=1669 - ('Kabuni',), # index=1670 - ('Jhunka',), # index=1671 - ('Jolada rotti',), # index=1672 - ('Spoonbread',), # index=1673 - ('Kulich',), # index=1674 - ('Phat khing',), # index=1675 - ('Namasu',), # index=1676 - ('Wonton noodles',), # index=1677 - ('Johnnycake',), # index=1678 - ('Panellets',), # index=1679 - ('Manj\xc5\xab',), # index=1680 - ('Mandi',), # index=1681 - ('Fortune cookie',), # index=1682 - ('Noppe',), # index=1683 - ('Slavink',), # index=1684 - ('Cockle bread',), # index=1685 - ('Caruru',), # index=1686 - ('Ch\xe1\xba\xa3 l\xe1\xbb\xa5a',), # index=1687 - ('Pan bagnat',), # index=1688 - ('Sardenara',), # index=1689 - ('Enchilada',), # index=1690 - ('Sausage sandwich',), # index=1691 - ('Pistachio pudding',), # index=1692 - ('Chikki',), # index=1693 - ('Champorado',), # index=1694 - ('Coconut cake',), # index=1695 - ('Kaassouffl\xc3\xa9',), # index=1696 - ('Carne pizzaiola',), # index=1697 - ('Khauk sw\xc3\xa8 thoke',), # index=1698 - ('Gamja-tang',), # index=1699 - ('Kadhi',), # index=1700 - ('Green bean casserole',), # index=1701 - ('Apple dumpling',), # index=1702 - ('Tsoureki',), # index=1703 - ('Pissaladi\xc3\xa8re',), # index=1704 - ('Phat si-io',), # index=1705 - ('Drunken noodles',), # index=1706 - ('Jing Jiang Rou Si',), # index=1707 - ('Enduri Pitha',), # index=1708 - ('Kakara pitha',), # index=1709 - ('Tarta de Santiago',), # index=1710 - ('Spoon sweets',), # index=1711 - ('Sheftalia',), # index=1712 - ('Soybean sprout',), # index=1713 - ('Italian hot dog',), # index=1714 - ('Makchang',), # index=1715 - ('Meeshay',), # index=1716 - ('Bacalhau com natas',), # index=1717 - ('Mazurek',), # index=1718 - ('Nan gyi thohk',), # index=1719 - ('Ajapsandali',), # index=1720 - ('Carac',), # index=1721 - ('Mont di',), # index=1722 - ('Geng',), # index=1723 - ('Vispipuuro',), # index=1724 - ('Bakso',), # index=1725 - ('Canjica',), # index=1726 - ('Fougasse',), # index=1727 - ("Fool's Gold Loaf",), # index=1728 - ('Blueberry pie',), # index=1729 - ('Cucumber Salad',), # index=1730 - ('Ogbono soup',), # index=1731 - ('Champ',), # index=1732 - ('Oysters en brochette',), # index=1733 - ('Paskha',), # index=1734 - ('Shish taouk',), # index=1735 - ('Acaraj\xc3\xa9',), # index=1736 - ('Ras malai',), # index=1737 - ('San-nakji',), # index=1738 - ('Bungeo-ppang',), # index=1739 - ('Skilandis',), # index=1740 - ('Gosh-e Fil',), # index=1741 - ('Nasi dagang',), # index=1742 - ('Gheimeh',), # index=1743 - ('Fesenj\xc4\x81n',), # index=1744 - ('Bacalhau \xc3\xa0 Gomes de S\xc3\xa1',), # index=1745 - ('F\xc3\xa5rik\xc3\xa5l',), # index=1746 - ('Bedfordshire clanger',), # index=1747 - ('Tonkatsu',), # index=1748 - ('Thai fried rice',), # index=1749 - ('Manakish',), # index=1750 - ('Schweinshaxe',), # index=1751 - ('Chorba',), # index=1752 - ('Oliebol',), # index=1753 - ('Ropa vieja',), # index=1754 - ('Natchitoches meat pie',), # index=1755 - ('Icebox cake',), # index=1756 - ('Sorrel soup',), # index=1757 - ('Lahoh',), # index=1758 - ('Bolillo',), # index=1759 - ('Mollete',), # index=1760 - ('Caldeirada',), # index=1761 - ('Ogi',), # index=1762 - ('Watergate salad',), # index=1763 - ('Yaksik',), # index=1764 - ('Half-smoke',), # index=1765 - ('Dakos',), # index=1766 - ('Sweet potato pie',), # index=1767 - ('Cappon magro',), # index=1768 - ('Serundeng',), # index=1769 - ('Rijstevlaai',), # index=1770 - ('Ajoblanco',), # index=1771 - ('Yaka mein',), # index=1772 - ('Jujeh kabab',), # index=1773 - ('Soy egg',), # index=1774 - ('Shuizhu',), # index=1775 - ('Puliyogare',), # index=1776 - ('Sago',), # index=1777 - ('Laulau',), # index=1778 - ('Curtido',), # index=1779 - ('Tapai',), # index=1780 - ('Press cake',), # index=1781 - ('Cuchifritos',), # index=1782 - ('Vlaai',), # index=1783 - ('Malvern pudding',), # index=1784 - ('Baklava',), # index=1785 - ('Cheese dog',), # index=1786 - ('Luchi',), # index=1787 - ('Cowboy beans',), # index=1788 - ('Sandesh',), # index=1789 - ('Steak Diane',), # index=1790 - ('Lobster stew',), # index=1791 - ('Finikia',), # index=1792 - ('Bibingka',), # index=1793 - ('Tafelspitz',), # index=1794 - ('Ploye',), # index=1795 - ('Sayur asem',), # index=1796 - ('Trinxat',), # index=1797 - ('Nikuman',), # index=1798 - ('Cozido \xc3\xa0 portuguesa',), # index=1799 - ('Bacalhau \xc3\xa0 Br\xc3\xa1s',), # index=1800 - ('Tomato compote',), # index=1801 - ('Sesame seed candy',), # index=1802 - ('Dhebra',), # index=1803 - ('Kaeng pa',), # index=1804 - ('Mas riha',), # index=1805 - ('Zosui',), # index=1806 - ('Yassa',), # index=1807 - ('Pambazo',), # index=1808 - ('Imarti',), # index=1809 - ('Bacalhau com todos',), # index=1810 - ('Black pepper crab',), # index=1811 - ('Queso flameado',), # index=1812 - ('Black and white cookie',), # index=1813 - ('Red braised pork belly',), # index=1814 - ('Krofne',), # index=1815 - ('U\xc5\xa1tipci',), # index=1816 - ('Ro\xc5\xbeata',), # index=1817 - ('Punjena paprika',), # index=1818 - ('Fusi',), # index=1819 - ('Mane\xc5\xa1tra',), # index=1820 - ('Kro\xc5\xa1tule',), # index=1821 - ('Fritule',), # index=1822 - ('Protein bar',), # index=1823 - ('Cordon bleu',), # index=1824 - ('Pirog',), # index=1825 - ('Pachi Pulusu',), # index=1826 - ('Frig\xc4\x83rui',), # index=1827 - ('Chhena poda',), # index=1828 - ('Poornalu',), # index=1829 - ('Ponganalu',), # index=1830 - ('Bing',), # index=1831 - ('Flaouna',), # index=1832 - ('Chakodi',), # index=1833 - ('Aloo paratha',), # index=1834 - ('Konro',), # index=1835 - ('Cemita',), # index=1836 - ('Asinan',), # index=1837 - ('Broa',), # index=1838 - ('Trifle',), # index=1839 - ('Rat na',), # index=1840 - ('Borlengo',), # index=1841 - ('Gazpachuelo',), # index=1842 - ('Esterh\xc3\xa1zy torte',), # index=1843 - ('Magenbrot',), # index=1844 - ('Detroit-style pizza',), # index=1845 - ('Fuling jiabing',), # index=1846 - ('Lakhamari',), # index=1847 - ('Mu\xc4\x87kalica',), # index=1848 - ('Sukhdi',), # index=1849 - ('Kilishi',), # index=1850 - ('Baji',), # index=1851 - ('Peanut butter cookie',), # index=1852 - ('Rabbit pie',), # index=1853 - ("Paling in 't groen",), # index=1854 - ('Chataamari',), # index=1855 - ('Lawar',), # index=1856 - ('Arisa Pitha',), # index=1857 - ('Empal gentong',), # index=1858 - ('Carne asada fries',), # index=1859 - ('Takikomi gohan',), # index=1860 - ('Kamameshi',), # index=1861 - ('Pasta salad',), # index=1862 - ('Fasole cu c\xc3\xa2rna\xc8\x9bi',), # index=1863 - ('Zelnik',), # index=1864 - ('Pl\xc4\x83cint\xc4\x83',), # index=1865 - ('Tongseng',), # index=1866 - ('Soto mie',), # index=1867 - ('Sarburma',), # index=1868 - ('Lutefisk',), # index=1869 - ('Khichdi',), # index=1870 - ('Briouat',), # index=1871 - ('Chili burger',), # index=1872 - ('Bolo de mel',), # index=1873 - ('Clootie',), # index=1874 - ('Seswaa',), # index=1875 - ('Tahu sumedang',), # index=1876 - ('Pichelsteiner',), # index=1877 - ('Bread soup',), # index=1878 - ('Scotcheroos',), # index=1879 - ('Kartoffelk\xc3\xa4se',), # index=1880 - ('Schuxen',), # index=1881 - ('Caramel',), # index=1882 - ('Zwetschgenkuchen',), # index=1883 - ('Alloco',), # index=1884 - ('Vangibath',), # index=1885 - ('Torricado',), # index=1886 - ('Phat phrik khing',), # index=1887 - ('Tomato and egg soup',), # index=1888 - ('Dushbara',), # index=1889 - ('Spanakorizo',), # index=1890 - ('Ostropel',), # index=1891 - ('Tamale',), # index=1892 - ('Seattle-style hot dog',), # index=1893 - ('Ammonia cookie',), # index=1894 - ('Boston baked beans',), # index=1895 - ('Amandine',), # index=1896 - ('Duck blood and vermicelli soup',), # index=1897 - ('Azerbaijani pakhlava',), # index=1898 - ('Bakwan',), # index=1899 - ('Wallenbergare',), # index=1900 - ('Pastry',), # index=1901 - ('Melomakarono',), # index=1902 - ('Cocido lebaniego',), # index=1903 - ('Koi',), # index=1904 - ('Stir-fried tomato and scrambled eggs',), # index=1905 - ('Fl\xc3\xa6skesteg',), # index=1906 - ("Beggar's Chicken",), # index=1907 - ('Lymonnyk',), # index=1908 - ('Konkonte',), # index=1909 - ('Stuffed zucchini',), # index=1910 - ('Kaeng som',), # index=1911 - ('Kentucky jam cake',), # index=1912 - ('Mur\xc4\x83turi',), # index=1913 - ('Tochitur\xc4\x83',), # index=1914 - ('Urap',), # index=1915 - ('Cornule\xc8\x9be',), # index=1916 - ('Quad City-style pizza',), # index=1917 - ('Paneer tikka',), # index=1918 - ('Ciorb\xc4\x83 de peri\xc8\x99oare',), # index=1919 - ('Semolina porridge',), # index=1920 - ('Shaker Lemon Pie',), # index=1921 - ('Doodhpak',), # index=1922 - ('Ceviche',), # index=1923 - ('Cabbage soup',), # index=1924 - ('Nasi timbel',), # index=1925 - ('Pa amb tom\xc3\xa0quet',), # index=1926 - ('Escalivada',), # index=1927 - ('Me\xc4\x91imurska gibanica',), # index=1928 - ('Khanom chan',), # index=1929 - ('Ohaw',), # index=1930 - ('Baghrir',), # index=1931 - ('Hummingbird cake',), # index=1932 - ('Neapolitan pizza',), # index=1933 - ('Doughnut',), # index=1934 - ('Hummus',), # index=1935 - ('Nimono',), # index=1936 - ('Chocolate chip cookie',), # index=1937 - ('B\xc3\xban \xe1\xbb\x91c',), # index=1938 - ('Cheese straw',), # index=1939 - ('Sausage',), # index=1940 - ('Frogeye salad',), # index=1941 - ('Senate bean soup',), # index=1942 - ('Botifarra',), # index=1943 - ('Leberkn\xc3\xb6del',), # index=1944 - ('Laziji',), # index=1945 - ('Quzi',), # index=1946 - ('Chazuke',), # index=1947 - ('Sandwich',), # index=1948 - ('BLT',), # index=1949 - ('Chikhirtma',), # index=1950 - ('Pico de gallo',), # index=1951 - ('Oden',), # index=1952 - ('Tostada',), # index=1953 - ('Chilaquiles',), # index=1954 - ('Cocido monta\xc3\xb1\xc3\xa9s',), # index=1955 - ('Lontong Cap Go Meh',), # index=1956 - ('Porra antequerana',), # index=1957 - ('Kedjenou',), # index=1958 - ('Tourin',), # index=1959 - ('Atti\xc3\xa9k\xc3\xa9',), # index=1960 - ('Dak-bokkeum-tang',), # index=1961 - ('\xc5\xbdemlovka',), # index=1962 - ('Dovga',), # index=1963 - ('Rice and gravy',), # index=1964 - ('Sai ua',), # index=1965 - ('Nam ngiao',), # index=1966 - ('Kaeng khae',), # index=1967 - ('Kaeng tai pla',), # index=1968 - ('Dim sum',), # index=1969 - ('Tahri',), # index=1970 - ('Bolo do caco',), # index=1971 - ('Buffalo wing',), # index=1972 - ('Pustakari',), # index=1973 - ('Pieds paquets',), # index=1974 - ('Tinginys',), # index=1975 - ('Sunnundallu',), # index=1976 - ('Lapskaus',), # index=1977 - ('Caldo tlalpe\xc3\xb1o',), # index=1978 - ('Milho frito',), # index=1979 - ('Kalu dodol',), # index=1980 - ('Poppyseed muffin',), # index=1981 - ('Peanut soup',), # index=1982 - ('Tarte \xc3\xa0 la Bouillie',), # index=1983 - ('Caldo gallego',), # index=1984 - ('Samay Baji',), # index=1985 - ('Limburger sandwich',), # index=1986 - ('Huachinango a la Veracruzana',), # index=1987 - ('Sambal stingray',), # index=1988 - ('Kuluban',), # index=1989 - ('Modjeska',), # index=1990 - ('Pan dulce',), # index=1991 - ('Florina pepper',), # index=1992 - ('Oysters Bienville',), # index=1993 - ('Cronut',), # index=1994 - ('Duck rice',), # index=1995 - ('Sulu k\xc3\xb6fte',), # index=1996 - ('Toyga soup',), # index=1997 - ('Majjige huli',), # index=1998 - ('Ikan goreng',), # index=1999 - ('Lekor',), # index=2000 - ('Ciulama',), # index=2001 - ('Ayam bakar',), # index=2002 - ('Hinava',), # index=2003 - ('Waakye',), # index=2004 - ('Salbute',), # index=2005 - ('Kuchmachi',), # index=2006 - ('Kibinai',), # index=2007 - ('Lobiani',), # index=2008 - ('Chanakhi',), # index=2009 - ('Baghala ghatogh',), # index=2010 - ('Pkhali',), # index=2011 - ('Poc Chuc',), # index=2012 - ('Bionico',), # index=2013 - ('Bamischijf',), # index=2014 - ('Racuchy',), # index=2015 - ('Kuurdak',), # index=2016 - ('Hokkien fried rice',), # index=2017 - ('Mu kratha',), # index=2018 - ('Thong yip',), # index=2019 - ('Zuppa toscana',), # index=2020 - ('Dhindo',), # index=2021 - ('Thiakry',), # index=2022 - ('Kondowole',), # index=2023 -) diff --git a/src/aiy/vision/models/face_detection.py b/src/aiy/vision/models/face_detection.py deleted file mode 100644 index 078cdeab..00000000 --- a/src/aiy/vision/models/face_detection.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""API for Face Detection.""" - -from __future__ import division - -from aiy.vision.inference import ModelDescriptor -from aiy.vision.models import utils - -_COMPUTE_GRAPH_NAME = 'face_detection.binaryproto' - - -def _reshape(array, width): - assert len(array) % width == 0 - height = len(array) // width - return [array[i * width:(i + 1) * width] for i in range(height)] - - -class Face(object): - """Face detection result.""" - - def __init__(self, bounding_box, face_score, joy_score): - """Creates a new Face instance. - - Args: - bounding_box: (x, y, width, height). - face_score: float, face confidence score. - joy_score: float, face joy score. - """ - self.bounding_box = bounding_box - self.face_score = face_score - self.joy_score = joy_score - - def __str__(self): - return 'face_score=%f, joy_score=%f, bbox=%s' % (self.face_score, - self.joy_score, - str(self.bounding_box)) - - -def model(): - # Face detection model has special implementation in VisionBonnet firmware. - # input_shape, input_normalizer, and computate_graph params have on effect. - return ModelDescriptor( - name='FaceDetection', - input_shape=(1, 0, 0, 3), - input_normalizer=(0, 0), - compute_graph=utils.load_compute_graph(_COMPUTE_GRAPH_NAME)) - - -def get_faces(result): - """Retunrs list of Face objects decoded from the inference result.""" - assert len(result.tensors) == 3 - # TODO(dkovalev): check tensor shapes - bboxes = _reshape(result.tensors['bounding_boxes'].data, 4) - face_scores = result.tensors['face_scores'].data - joy_scores = result.tensors['joy_scores'].data - assert len(bboxes) == len(joy_scores) - assert len(bboxes) == len(face_scores) - return [ - Face(tuple(bbox), face_score, joy_score) - for bbox, face_score, joy_score in zip(bboxes, face_scores, joy_scores) - ] diff --git a/src/aiy/vision/models/image_classification.py b/src/aiy/vision/models/image_classification.py deleted file mode 100644 index 20bd89dd..00000000 --- a/src/aiy/vision/models/image_classification.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""API for Image Classification tasks.""" - -from aiy.vision.inference import ModelDescriptor -from aiy.vision.models import utils -from aiy.vision.models.image_classification_classes import CLASSES - -# There are two models in our repository that can do image classification. One -# based on MobileNet model structure, the other based on SqueezeNet model -# structure. -# -# MobileNet based model has 59.9% top-1 accuracy on ImageNet. -# SqueezeNet based model has 45.3% top-1 accuracy on ImageNet. -MOBILENET = 'image_classification_mobilenet' -SQUEEZENET = 'image_classification_squeezenet' -_COMPUTE_GRAPH_NAME_MAP = { - MOBILENET: 'mobilenet_v1_160res_0.5_imagenet.binaryproto', - SQUEEZENET: 'squeezenet_160res_5x5_0.75.binaryproto', -} -_OUTPUT_TENSOR_NAME_MAP = { - MOBILENET: 'MobilenetV1/Predictions/Softmax', - SQUEEZENET: 'Prediction', -} - - -def model(model_type=MOBILENET): - return ModelDescriptor( - name=model_type, - input_shape=(1, 160, 160, 3), - input_normalizer=(128.0, 128.0), - compute_graph=utils.load_compute_graph( - _COMPUTE_GRAPH_NAME_MAP[model_type])) - - -def get_classes(result, max_num_objects=None, object_prob_threshold=0.0): - """Converts image classification model output to list of detected objects. - - Args: - result: output tensor from image classification model. - max_num_objects: int; max number of objects to return. - object_prob_threshold: float; min probability of each returned object. - - Returns: - A list of (class_name: string, probability: float) pairs ordered by - probability from highest to lowest. The number of pairs is not greater than - max_num_objects. Each probability is greater than object_prob_threshold. For - example: - - [('Egyptian cat', 0.767578) - ('tiger cat, 0.163574) - ('lynx/catamount', 0.039795)] - """ - assert len(result.tensors) == 1 - tensor_name = _OUTPUT_TENSOR_NAME_MAP[result.model_name] - tensor = result.tensors[tensor_name] - probs, shape = tensor.data, tensor.shape - assert (shape.batch, shape.height, shape.width, shape.depth) == (1, 1, 1, - 1001) - - pairs = [pair for pair in enumerate(probs) if pair[1] > object_prob_threshold] - pairs = sorted(pairs, key=lambda pair: pair[1], reverse=True) - pairs = pairs[0:max_num_objects] - return [('/'.join(CLASSES[index]), prob) for index, prob in pairs] diff --git a/src/aiy/vision/models/image_classification_classes.py b/src/aiy/vision/models/image_classification_classes.py deleted file mode 100644 index c3bddce8..00000000 --- a/src/aiy/vision/models/image_classification_classes.py +++ /dev/null @@ -1,1076 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Predefined image classes for image classification model.""" - -CLASSES = ( - ('background',), # index=0 - ('tench', 'Tinca tinca'), # index=1 - ('goldfish', 'Carassius auratus'), # index=2 - ('great white shark', 'white shark', 'man-eater', 'man-eating shark', - 'Carcharodon carcharias'), # index=3 - ('tiger shark', 'Galeocerdo cuvieri'), # index=4 - ('hammerhead', 'hammerhead shark'), # index=5 - ('electric ray', 'crampfish', 'numbfish', 'torpedo'), # index=6 - ('stingray',), # index=7 - ('cock',), # index=8 - ('hen',), # index=9 - ('ostrich', 'Struthio camelus'), # index=10 - ('brambling', 'Fringilla montifringilla'), # index=11 - ('goldfinch', 'Carduelis carduelis'), # index=12 - ('house finch', 'linnet', 'Carpodacus mexicanus'), # index=13 - ('junco', 'snowbird'), # index=14 - ('indigo bunting', 'indigo finch', 'indigo bird', - 'Passerina cyanea'), # index=15 - ('robin', 'American robin', 'Turdus migratorius'), # index=16 - ('bulbul',), # index=17 - ('jay',), # index=18 - ('magpie',), # index=19 - ('chickadee',), # index=20 - ('water ouzel', 'dipper'), # index=21 - ('kite',), # index=22 - ('bald eagle', 'American eagle', 'Haliaeetus leucocephalus'), # index=23 - ('vulture',), # index=24 - ('great grey owl', 'great gray owl', 'Strix nebulosa'), # index=25 - ('European fire salamander', 'Salamandra salamandra'), # index=26 - ('common newt', 'Triturus vulgaris'), # index=27 - ('eft',), # index=28 - ('spotted salamander', 'Ambystoma maculatum'), # index=29 - ('axolotl', 'mud puppy', 'Ambystoma mexicanum'), # index=30 - ('bullfrog', 'Rana catesbeiana'), # index=31 - ('tree frog', 'tree-frog'), # index=32 - ('tailed frog', 'bell toad', 'ribbed toad', 'tailed toad', - 'Ascaphus trui'), # index=33 - ('loggerhead', 'loggerhead turtle', 'Caretta caretta'), # index=34 - ('leatherback turtle', 'leatherback', 'leathery turtle', - 'Dermochelys coriacea'), # index=35 - ('mud turtle',), # index=36 - ('terrapin',), # index=37 - ('box turtle', 'box tortoise'), # index=38 - ('banded gecko',), # index=39 - ('common iguana', 'iguana', 'Iguana iguana'), # index=40 - ('American chameleon', 'anole', 'Anolis carolinensis'), # index=41 - ('whiptail', 'whiptail lizard'), # index=42 - ('agama',), # index=43 - ('frilled lizard', 'Chlamydosaurus kingi'), # index=44 - ('alligator lizard',), # index=45 - ('Gila monster', 'Heloderma suspectum'), # index=46 - ('green lizard', 'Lacerta viridis'), # index=47 - ('African chameleon', 'Chamaeleo chamaeleon'), # index=48 - ('Komodo dragon', 'Komodo lizard', 'dragon lizard', 'giant lizard', - 'Varanus komodoensis'), # index=49 - ('African crocodile', 'Nile crocodile', 'Crocodylus niloticus'), # index=50 - ('American alligator', 'Alligator mississipiensis'), # index=51 - ('triceratops',), # index=52 - ('thunder snake', 'worm snake', 'Carphophis amoenus'), # index=53 - ('ringneck snake', 'ring-necked snake', 'ring snake'), # index=54 - ('hognose snake', 'puff adder', 'sand viper'), # index=55 - ('green snake', 'grass snake'), # index=56 - ('king snake', 'kingsnake'), # index=57 - ('garter snake', 'grass snake'), # index=58 - ('water snake',), # index=59 - ('vine snake',), # index=60 - ('night snake', 'Hypsiglena torquata'), # index=61 - ('boa constrictor', 'Constrictor constrictor'), # index=62 - ('rock python', 'rock snake', 'Python sebae'), # index=63 - ('Indian cobra', 'Naja naja'), # index=64 - ('green mamba',), # index=65 - ('sea snake',), # index=66 - ('horned viper', 'cerastes', 'sand viper', 'horned asp', - 'Cerastes cornutus'), # index=67 - ('diamondback', 'diamondback rattlesnake', - 'Crotalus adamanteus'), # index=68 - ('sidewinder', 'horned rattlesnake', 'Crotalus cerastes'), # index=69 - ('trilobite',), # index=70 - ('harvestman', 'daddy longlegs', 'Phalangium opilio'), # index=71 - ('scorpion',), # index=72 - ('black and gold garden spider', 'Argiope aurantia'), # index=73 - ('barn spider', 'Araneus cavaticus'), # index=74 - ('garden spider', 'Aranea diademata'), # index=75 - ('black widow', 'Latrodectus mactans'), # index=76 - ('tarantula',), # index=77 - ('wolf spider', 'hunting spider'), # index=78 - ('tick',), # index=79 - ('centipede',), # index=80 - ('black grouse',), # index=81 - ('ptarmigan',), # index=82 - ('ruffed grouse', 'partridge', 'Bonasa umbellus'), # index=83 - ('prairie chicken', 'prairie grouse', 'prairie fowl'), # index=84 - ('peacock',), # index=85 - ('quail',), # index=86 - ('partridge',), # index=87 - ('African grey', 'African gray', 'Psittacus erithacus'), # index=88 - ('macaw',), # index=89 - ('sulphur-crested cockatoo', 'Kakatoe galerita', - 'Cacatua galerita'), # index=90 - ('lorikeet',), # index=91 - ('coucal',), # index=92 - ('bee eater',), # index=93 - ('hornbill',), # index=94 - ('hummingbird',), # index=95 - ('jacamar',), # index=96 - ('toucan',), # index=97 - ('drake',), # index=98 - ('red-breasted merganser', 'Mergus serrator'), # index=99 - ('goose',), # index=100 - ('black swan', 'Cygnus atratus'), # index=101 - ('tusker',), # index=102 - ('echidna', 'spiny anteater', 'anteater'), # index=103 - ('platypus', 'duckbill', 'duckbilled platypus', 'duck-billed platypus', - 'Ornithorhynchus anatinus'), # index=104 - ('wallaby', 'brush kangaroo'), # index=105 - ('koala', 'koala bear', 'kangaroo bear', 'native bear', - 'Phascolarctos cinereus'), # index=106 - ('wombat',), # index=107 - ('jellyfish',), # index=108 - ('sea anemone', 'anemone'), # index=109 - ('brain coral',), # index=110 - ('flatworm', 'platyhelminth'), # index=111 - ('nematode', 'nematode worm', 'roundworm'), # index=112 - ('conch',), # index=113 - ('snail',), # index=114 - ('slug',), # index=115 - ('sea slug', 'nudibranch'), # index=116 - ('chiton', 'coat-of-mail shell', 'sea cradle', - 'polyplacophore'), # index=117 - ('chambered nautilus', 'pearly nautilus', 'nautilus'), # index=118 - ('Dungeness crab', 'Cancer magister'), # index=119 - ('rock crab', 'Cancer irroratus'), # index=120 - ('fiddler crab',), # index=121 - ('king crab', 'Alaska crab', 'Alaskan king crab', 'Alaska king crab', - 'Paralithodes camtschatica'), # index=122 - ('American lobster', 'Northern lobster', 'Maine lobster', - 'Homarus americanus'), # index=123 - ('spiny lobster', 'langouste', 'rock lobster', 'crawfish', 'crayfish', - 'sea crawfish'), # index=124 - ('crayfish', 'crawfish', 'crawdad', 'crawdaddy'), # index=125 - ('hermit crab',), # index=126 - ('isopod',), # index=127 - ('white stork', 'Ciconia ciconia'), # index=128 - ('black stork', 'Ciconia nigra'), # index=129 - ('spoonbill',), # index=130 - ('flamingo',), # index=131 - ('little blue heron', 'Egretta caerulea'), # index=132 - ('American egret', 'great white heron', 'Egretta albus'), # index=133 - ('bittern',), # index=134 - ('crane',), # index=135 - ('limpkin', 'Aramus pictus'), # index=136 - ('European gallinule', 'Porphyrio porphyrio'), # index=137 - ('American coot', 'marsh hen', 'mud hen', 'water hen', - 'Fulica americana'), # index=138 - ('bustard',), # index=139 - ('ruddy turnstone', 'Arenaria interpres'), # index=140 - ('red-backed sandpiper', 'dunlin', 'Erolia alpina'), # index=141 - ('redshank', 'Tringa totanus'), # index=142 - ('dowitcher',), # index=143 - ('oystercatcher', 'oyster catcher'), # index=144 - ('pelican',), # index=145 - ('king penguin', 'Aptenodytes patagonica'), # index=146 - ('albatross', 'mollymawk'), # index=147 - ('grey whale', 'gray whale', 'devilfish', 'Eschrichtius gibbosus', - 'Eschrichtius robustus'), # index=148 - ('killer whale', 'killer', 'orca', 'grampus', 'sea wolf', - 'Orcinus orca'), # index=149 - ('dugong', 'Dugong dugon'), # index=150 - ('sea lion',), # index=151 - ('Chihuahua',), # index=152 - ('Japanese spaniel',), # index=153 - ('Maltese dog', 'Maltese terrier', 'Maltese'), # index=154 - ('Pekinese', 'Pekingese', 'Peke'), # index=155 - ('Shih-Tzu',), # index=156 - ('Blenheim spaniel',), # index=157 - ('papillon',), # index=158 - ('toy terrier',), # index=159 - ('Rhodesian ridgeback',), # index=160 - ('Afghan hound', 'Afghan'), # index=161 - ('basset', 'basset hound'), # index=162 - ('beagle',), # index=163 - ('bloodhound', 'sleuthhound'), # index=164 - ('bluetick',), # index=165 - ('black-and-tan coonhound',), # index=166 - ('Walker hound', 'Walker foxhound'), # index=167 - ('English foxhound',), # index=168 - ('redbone',), # index=169 - ('borzoi', 'Russian wolfhound'), # index=170 - ('Irish wolfhound',), # index=171 - ('Italian greyhound',), # index=172 - ('whippet',), # index=173 - ('Ibizan hound', 'Ibizan Podenco'), # index=174 - ('Norwegian elkhound', 'elkhound'), # index=175 - ('otterhound', 'otter hound'), # index=176 - ('Saluki', 'gazelle hound'), # index=177 - ('Scottish deerhound', 'deerhound'), # index=178 - ('Weimaraner',), # index=179 - ('Staffordshire bullterrier', 'Staffordshire bull terrier'), # index=180 - ('American Staffordshire terrier', 'Staffordshire terrier', - 'American pit bull terrier', 'pit bull terrier'), # index=181 - ('Bedlington terrier',), # index=182 - ('Border terrier',), # index=183 - ('Kerry blue terrier',), # index=184 - ('Irish terrier',), # index=185 - ('Norfolk terrier',), # index=186 - ('Norwich terrier',), # index=187 - ('Yorkshire terrier',), # index=188 - ('wire-haired fox terrier',), # index=189 - ('Lakeland terrier',), # index=190 - ('Sealyham terrier', 'Sealyham'), # index=191 - ('Airedale', 'Airedale terrier'), # index=192 - ('cairn', 'cairn terrier'), # index=193 - ('Australian terrier',), # index=194 - ('Dandie Dinmont', 'Dandie Dinmont terrier'), # index=195 - ('Boston bull', 'Boston terrier'), # index=196 - ('miniature schnauzer',), # index=197 - ('giant schnauzer',), # index=198 - ('standard schnauzer',), # index=199 - ('Scotch terrier', 'Scottish terrier', 'Scottie'), # index=200 - ('Tibetan terrier', 'chrysanthemum dog'), # index=201 - ('silky terrier', 'Sydney silky'), # index=202 - ('soft-coated wheaten terrier',), # index=203 - ('West Highland white terrier',), # index=204 - ('Lhasa', 'Lhasa apso'), # index=205 - ('flat-coated retriever',), # index=206 - ('curly-coated retriever',), # index=207 - ('golden retriever',), # index=208 - ('Labrador retriever',), # index=209 - ('Chesapeake Bay retriever',), # index=210 - ('German short-haired pointer',), # index=211 - ('vizsla', 'Hungarian pointer'), # index=212 - ('English setter',), # index=213 - ('Irish setter', 'red setter'), # index=214 - ('Gordon setter',), # index=215 - ('Brittany spaniel',), # index=216 - ('clumber', 'clumber spaniel'), # index=217 - ('English springer', 'English springer spaniel'), # index=218 - ('Welsh springer spaniel',), # index=219 - ('cocker spaniel', 'English cocker spaniel', 'cocker'), # index=220 - ('Sussex spaniel',), # index=221 - ('Irish water spaniel',), # index=222 - ('kuvasz',), # index=223 - ('schipperke',), # index=224 - ('groenendael',), # index=225 - ('malinois',), # index=226 - ('briard',), # index=227 - ('kelpie',), # index=228 - ('komondor',), # index=229 - ('Old English sheepdog', 'bobtail'), # index=230 - ('Shetland sheepdog', 'Shetland sheep dog', 'Shetland'), # index=231 - ('collie',), # index=232 - ('Border collie',), # index=233 - ('Bouvier des Flandres', 'Bouviers des Flandres'), # index=234 - ('Rottweiler',), # index=235 - ('German shepherd', 'German shepherd dog', 'German police dog', - 'alsatian'), # index=236 - ('Doberman', 'Doberman pinscher'), # index=237 - ('miniature pinscher',), # index=238 - ('Greater Swiss Mountain dog',), # index=239 - ('Bernese mountain dog',), # index=240 - ('Appenzeller',), # index=241 - ('EntleBucher',), # index=242 - ('boxer',), # index=243 - ('bull mastiff',), # index=244 - ('Tibetan mastiff',), # index=245 - ('French bulldog',), # index=246 - ('Great Dane',), # index=247 - ('Saint Bernard', 'St Bernard'), # index=248 - ('Eskimo dog', 'husky'), # index=249 - ('malamute', 'malemute', 'Alaskan malamute'), # index=250 - ('Siberian husky',), # index=251 - ('dalmatian', 'coach dog', 'carriage dog'), # index=252 - ('affenpinscher', 'monkey pinscher', 'monkey dog'), # index=253 - ('basenji',), # index=254 - ('pug', 'pug-dog'), # index=255 - ('Leonberg',), # index=256 - ('Newfoundland', 'Newfoundland dog'), # index=257 - ('Great Pyrenees',), # index=258 - ('Samoyed', 'Samoyede'), # index=259 - ('Pomeranian',), # index=260 - ('chow', 'chow chow'), # index=261 - ('keeshond',), # index=262 - ('Brabancon griffon',), # index=263 - ('Pembroke', 'Pembroke Welsh corgi'), # index=264 - ('Cardigan', 'Cardigan Welsh corgi'), # index=265 - ('toy poodle',), # index=266 - ('miniature poodle',), # index=267 - ('standard poodle',), # index=268 - ('Mexican hairless',), # index=269 - ('timber wolf', 'grey wolf', 'gray wolf', 'Canis lupus'), # index=270 - ('white wolf', 'Arctic wolf', 'Canis lupus tundrarum'), # index=271 - ('red wolf', 'maned wolf', 'Canis rufus', 'Canis niger'), # index=272 - ('coyote', 'prairie wolf', 'brush wolf', 'Canis latrans'), # index=273 - ('dingo', 'warrigal', 'warragal', 'Canis dingo'), # index=274 - ('dhole', 'Cuon alpinus'), # index=275 - ('African hunting dog', 'hyena dog', 'Cape hunting dog', - 'Lycaon pictus'), # index=276 - ('hyena', 'hyaena'), # index=277 - ('red fox', 'Vulpes vulpes'), # index=278 - ('kit fox', 'Vulpes macrotis'), # index=279 - ('Arctic fox', 'white fox', 'Alopex lagopus'), # index=280 - ('grey fox', 'gray fox', 'Urocyon cinereoargenteus'), # index=281 - ('tabby', 'tabby cat'), # index=282 - ('tiger cat',), # index=283 - ('Persian cat',), # index=284 - ('Siamese cat', 'Siamese'), # index=285 - ('Egyptian cat',), # index=286 - ('cougar', 'puma', 'catamount', 'mountain lion', 'painter', 'panther', - 'Felis concolor'), # index=287 - ('lynx', 'catamount'), # index=288 - ('leopard', 'Panthera pardus'), # index=289 - ('snow leopard', 'ounce', 'Panthera uncia'), # index=290 - ('jaguar', 'panther', 'Panthera onca', 'Felis onca'), # index=291 - ('lion', 'king of beasts', 'Panthera leo'), # index=292 - ('tiger', 'Panthera tigris'), # index=293 - ('cheetah', 'chetah', 'Acinonyx jubatus'), # index=294 - ('brown bear', 'bruin', 'Ursus arctos'), # index=295 - ('American black bear', 'black bear', 'Ursus americanus', - 'Euarctos americanus'), # index=296 - ('ice bear', 'polar bear', 'Ursus Maritimus', - 'Thalarctos maritimus'), # index=297 - ('sloth bear', 'Melursus ursinus', 'Ursus ursinus'), # index=298 - ('mongoose',), # index=299 - ('meerkat', 'mierkat'), # index=300 - ('tiger beetle',), # index=301 - ('ladybug', 'ladybeetle', 'lady beetle', 'ladybird', - 'ladybird beetle'), # index=302 - ('ground beetle', 'carabid beetle'), # index=303 - ('long-horned beetle', 'longicorn', 'longicorn beetle'), # index=304 - ('leaf beetle', 'chrysomelid'), # index=305 - ('dung beetle',), # index=306 - ('rhinoceros beetle',), # index=307 - ('weevil',), # index=308 - ('fly',), # index=309 - ('bee',), # index=310 - ('ant', 'emmet', 'pismire'), # index=311 - ('grasshopper', 'hopper'), # index=312 - ('cricket',), # index=313 - ('walking stick', 'walkingstick', 'stick insect'), # index=314 - ('cockroach', 'roach'), # index=315 - ('mantis', 'mantid'), # index=316 - ('cicada', 'cicala'), # index=317 - ('leafhopper',), # index=318 - ('lacewing', 'lacewing fly'), # index=319 - ('dragonfly', 'darning needle', "devil's darning needle", 'sewing needle', - 'snake feeder', 'snake doctor', 'mosquito hawk', - 'skeeter hawk'), # index=320 - ('damselfly',), # index=321 - ('admiral',), # index=322 - ('ringlet', 'ringlet butterfly'), # index=323 - ('monarch', 'monarch butterfly', 'milkweed butterfly', - 'Danaus plexippus'), # index=324 - ('cabbage butterfly',), # index=325 - ('sulphur butterfly', 'sulfur butterfly'), # index=326 - ('lycaenid', 'lycaenid butterfly'), # index=327 - ('starfish', 'sea star'), # index=328 - ('sea urchin',), # index=329 - ('sea cucumber', 'holothurian'), # index=330 - ('wood rabbit', 'cottontail', 'cottontail rabbit'), # index=331 - ('hare',), # index=332 - ('Angora', 'Angora rabbit'), # index=333 - ('hamster',), # index=334 - ('porcupine', 'hedgehog'), # index=335 - ('fox squirrel', 'eastern fox squirrel', 'Sciurus niger'), # index=336 - ('marmot',), # index=337 - ('beaver',), # index=338 - ('guinea pig', 'Cavia cobaya'), # index=339 - ('sorrel',), # index=340 - ('zebra',), # index=341 - ('hog', 'pig', 'grunter', 'squealer', 'Sus scrofa'), # index=342 - ('wild boar', 'boar', 'Sus scrofa'), # index=343 - ('warthog',), # index=344 - ('hippopotamus', 'hippo', 'river horse', - 'Hippopotamus amphibius'), # index=345 - ('ox',), # index=346 - ('water buffalo', 'water ox', 'Asiatic buffalo', - 'Bubalus bubalis'), # index=347 - ('bison',), # index=348 - ('ram', 'tup'), # index=349 - ('bighorn', 'bighorn sheep', 'cimarron', 'Rocky Mountain bighorn', - 'Rocky Mountain sheep', 'Ovis canadensis'), # index=350 - ('ibex', 'Capra ibex'), # index=351 - ('hartebeest',), # index=352 - ('impala', 'Aepyceros melampus'), # index=353 - ('gazelle',), # index=354 - ('Arabian camel', 'dromedary', 'Camelus dromedarius'), # index=355 - ('llama',), # index=356 - ('weasel',), # index=357 - ('mink',), # index=358 - ('polecat', 'fitch', 'foulmart', 'foumart', - 'Mustela putorius'), # index=359 - ('black-footed ferret', 'ferret', 'Mustela nigripes'), # index=360 - ('otter',), # index=361 - ('skunk', 'polecat', 'wood pussy'), # index=362 - ('badger',), # index=363 - ('armadillo',), # index=364 - ('three-toed sloth', 'ai', 'Bradypus tridactylus'), # index=365 - ('orangutan', 'orang', 'orangutang', 'Pongo pygmaeus'), # index=366 - ('gorilla', 'Gorilla gorilla'), # index=367 - ('chimpanzee', 'chimp', 'Pan troglodytes'), # index=368 - ('gibbon', 'Hylobates lar'), # index=369 - ('siamang', 'Hylobates syndactylus', - 'Symphalangus syndactylus'), # index=370 - ('guenon', 'guenon monkey'), # index=371 - ('patas', 'hussar monkey', 'Erythrocebus patas'), # index=372 - ('baboon',), # index=373 - ('macaque',), # index=374 - ('langur',), # index=375 - ('colobus', 'colobus monkey'), # index=376 - ('proboscis monkey', 'Nasalis larvatus'), # index=377 - ('marmoset',), # index=378 - ('capuchin', 'ringtail', 'Cebus capucinus'), # index=379 - ('howler monkey', 'howler'), # index=380 - ('titi', 'titi monkey'), # index=381 - ('spider monkey', 'Ateles geoffroyi'), # index=382 - ('squirrel monkey', 'Saimiri sciureus'), # index=383 - ('Madagascar cat', 'ring-tailed lemur', 'Lemur catta'), # index=384 - ('indri', 'indris', 'Indri indri', 'Indri brevicaudatus'), # index=385 - ('Indian elephant', 'Elephas maximus'), # index=386 - ('African elephant', 'Loxodonta africana'), # index=387 - ('lesser panda', 'red panda', 'panda', 'bear cat', 'cat bear', - 'Ailurus fulgens'), # index=388 - ('giant panda', 'panda', 'panda bear', 'coon bear', - 'Ailuropoda melanoleuca'), # index=389 - ('barracouta', 'snoek'), # index=390 - ('eel',), # index=391 - ('coho', 'cohoe', 'coho salmon', 'blue jack', 'silver salmon', - 'Oncorhynchus kisutch'), # index=392 - ('rock beauty', 'Holocanthus tricolor'), # index=393 - ('anemone fish',), # index=394 - ('sturgeon',), # index=395 - ('gar', 'garfish', 'garpike', 'billfish', - 'Lepisosteus osseus'), # index=396 - ('lionfish',), # index=397 - ('puffer', 'pufferfish', 'blowfish', 'globefish'), # index=398 - ('abacus',), # index=399 - ('abaya',), # index=400 - ('academic gown', 'academic robe', "judge's robe"), # index=401 - ('accordion', 'piano accordion', 'squeeze box'), # index=402 - ('acoustic guitar',), # index=403 - ('aircraft carrier', 'carrier', 'flattop', - 'attack aircraft carrier'), # index=404 - ('airliner',), # index=405 - ('airship', 'dirigible'), # index=406 - ('altar',), # index=407 - ('ambulance',), # index=408 - ('amphibian', 'amphibious vehicle'), # index=409 - ('analog clock',), # index=410 - ('apiary', 'bee house'), # index=411 - ('apron',), # index=412 - ('ashcan', 'trash can', 'garbage can', 'wastebin', 'ash bin', 'ash-bin', - 'ashbin', 'dustbin', 'trash barrel', 'trash bin'), # index=413 - ('assault rifle', 'assault gun'), # index=414 - ('backpack', 'back pack', 'knapsack', 'packsack', 'rucksack', - 'haversack'), # index=415 - ('bakery', 'bakeshop', 'bakehouse'), # index=416 - ('balance beam', 'beam'), # index=417 - ('balloon',), # index=418 - ('ballpoint', 'ballpoint pen', 'ballpen', 'Biro'), # index=419 - ('Band Aid',), # index=420 - ('banjo',), # index=421 - ('bannister', 'banister', 'balustrade', 'balusters', - 'handrail'), # index=422 - ('barbell',), # index=423 - ('barber chair',), # index=424 - ('barbershop',), # index=425 - ('barn',), # index=426 - ('barometer',), # index=427 - ('barrel', 'cask'), # index=428 - ('barrow', 'garden cart', 'lawn cart', 'wheelbarrow'), # index=429 - ('baseball',), # index=430 - ('basketball',), # index=431 - ('bassinet',), # index=432 - ('bassoon',), # index=433 - ('bathing cap', 'swimming cap'), # index=434 - ('bath towel',), # index=435 - ('bathtub', 'bathing tub', 'bath', 'tub'), # index=436 - ('beach wagon', 'station wagon', 'wagon', 'estate car', 'beach waggon', - 'station waggon', 'waggon'), # index=437 - ('beacon', 'lighthouse', 'beacon light', 'pharos'), # index=438 - ('beaker',), # index=439 - ('bearskin', 'busby', 'shako'), # index=440 - ('beer bottle',), # index=441 - ('beer glass',), # index=442 - ('bell cote', 'bell cot'), # index=443 - ('bib',), # index=444 - ('bicycle-built-for-two', 'tandem bicycle', 'tandem'), # index=445 - ('bikini', 'two-piece'), # index=446 - ('binder', 'ring-binder'), # index=447 - ('binoculars', 'field glasses', 'opera glasses'), # index=448 - ('birdhouse',), # index=449 - ('boathouse',), # index=450 - ('bobsled', 'bobsleigh', 'bob'), # index=451 - ('bolo tie', 'bolo', 'bola tie', 'bola'), # index=452 - ('bonnet', 'poke bonnet'), # index=453 - ('bookcase',), # index=454 - ('bookshop', 'bookstore', 'bookstall'), # index=455 - ('bottlecap',), # index=456 - ('bow',), # index=457 - ('bow tie', 'bow-tie', 'bowtie'), # index=458 - ('brass', 'memorial tablet', 'plaque'), # index=459 - ('brassiere', 'bra', 'bandeau'), # index=460 - ('breakwater', 'groin', 'groyne', 'mole', 'bulwark', 'seawall', - 'jetty'), # index=461 - ('breastplate', 'aegis', 'egis'), # index=462 - ('broom',), # index=463 - ('bucket', 'pail'), # index=464 - ('buckle',), # index=465 - ('bulletproof vest',), # index=466 - ('bullet train', 'bullet'), # index=467 - ('butcher shop', 'meat market'), # index=468 - ('cab', 'hack', 'taxi', 'taxicab'), # index=469 - ('caldron', 'cauldron'), # index=470 - ('candle', 'taper', 'wax light'), # index=471 - ('cannon',), # index=472 - ('canoe',), # index=473 - ('can opener', 'tin opener'), # index=474 - ('cardigan',), # index=475 - ('car mirror',), # index=476 - ('carousel', 'carrousel', 'merry-go-round', 'roundabout', - 'whirligig'), # index=477 - ("carpenter's kit", 'tool kit'), # index=478 - ('carton',), # index=479 - ('car wheel',), # index=480 - ('cash machine', 'cash dispenser', 'automated teller machine', - 'automatic teller machine', 'automated teller', 'automatic teller', - 'ATM'), # index=481 - ('cassette',), # index=482 - ('cassette player',), # index=483 - ('castle',), # index=484 - ('catamaran',), # index=485 - ('CD player',), # index=486 - ('cello', 'violoncello'), # index=487 - ('cellular telephone', 'cellular phone', 'cellphone', 'cell', - 'mobile phone'), # index=488 - ('chain',), # index=489 - ('chainlink fence',), # index=490 - ('chain mail', 'ring mail', 'mail', 'chain armor', 'chain armour', - 'ring armor', 'ring armour'), # index=491 - ('chain saw', 'chainsaw'), # index=492 - ('chest',), # index=493 - ('chiffonier', 'commode'), # index=494 - ('chime', 'bell', 'gong'), # index=495 - ('china cabinet', 'china closet'), # index=496 - ('Christmas stocking',), # index=497 - ('church', 'church building'), # index=498 - ('cinema', 'movie theater', 'movie theatre', 'movie house', - 'picture palace'), # index=499 - ('cleaver', 'meat cleaver', 'chopper'), # index=500 - ('cliff dwelling',), # index=501 - ('cloak',), # index=502 - ('clog', 'geta', 'patten', 'sabot'), # index=503 - ('cocktail shaker',), # index=504 - ('coffee mug',), # index=505 - ('coffeepot',), # index=506 - ('coil', 'spiral', 'volute', 'whorl', 'helix'), # index=507 - ('combination lock',), # index=508 - ('computer keyboard', 'keypad'), # index=509 - ('confectionery', 'confectionary', 'candy store'), # index=510 - ('container ship', 'containership', 'container vessel'), # index=511 - ('convertible',), # index=512 - ('corkscrew', 'bottle screw'), # index=513 - ('cornet', 'horn', 'trumpet', 'trump'), # index=514 - ('cowboy boot',), # index=515 - ('cowboy hat', 'ten-gallon hat'), # index=516 - ('cradle',), # index=517 - ('crane',), # index=518 - ('crash helmet',), # index=519 - ('crate',), # index=520 - ('crib', 'cot'), # index=521 - ('Crock Pot',), # index=522 - ('croquet ball',), # index=523 - ('crutch',), # index=524 - ('cuirass',), # index=525 - ('dam', 'dike', 'dyke'), # index=526 - ('desk',), # index=527 - ('desktop computer',), # index=528 - ('dial telephone', 'dial phone'), # index=529 - ('diaper', 'nappy', 'napkin'), # index=530 - ('digital clock',), # index=531 - ('digital watch',), # index=532 - ('dining table', 'board'), # index=533 - ('dishrag', 'dishcloth'), # index=534 - ('dishwasher', 'dish washer', 'dishwashing machine'), # index=535 - ('disk brake', 'disc brake'), # index=536 - ('dock', 'dockage', 'docking facility'), # index=537 - ('dogsled', 'dog sled', 'dog sleigh'), # index=538 - ('dome',), # index=539 - ('doormat', 'welcome mat'), # index=540 - ('drilling platform', 'offshore rig'), # index=541 - ('drum', 'membranophone', 'tympan'), # index=542 - ('drumstick',), # index=543 - ('dumbbell',), # index=544 - ('Dutch oven',), # index=545 - ('electric fan', 'blower'), # index=546 - ('electric guitar',), # index=547 - ('electric locomotive',), # index=548 - ('entertainment center',), # index=549 - ('envelope',), # index=550 - ('espresso maker',), # index=551 - ('face powder',), # index=552 - ('feather boa', 'boa'), # index=553 - ('file', 'file cabinet', 'filing cabinet'), # index=554 - ('fireboat',), # index=555 - ('fire engine', 'fire truck'), # index=556 - ('fire screen', 'fireguard'), # index=557 - ('flagpole', 'flagstaff'), # index=558 - ('flute', 'transverse flute'), # index=559 - ('folding chair',), # index=560 - ('football helmet',), # index=561 - ('forklift',), # index=562 - ('fountain',), # index=563 - ('fountain pen',), # index=564 - ('four-poster',), # index=565 - ('freight car',), # index=566 - ('French horn', 'horn'), # index=567 - ('frying pan', 'frypan', 'skillet'), # index=568 - ('fur coat',), # index=569 - ('garbage truck', 'dustcart'), # index=570 - ('gasmask', 'respirator', 'gas helmet'), # index=571 - ('gas pump', 'gasoline pump', 'petrol pump', - 'island dispenser'), # index=572 - ('goblet',), # index=573 - ('go-kart',), # index=574 - ('golf ball',), # index=575 - ('golfcart', 'golf cart'), # index=576 - ('gondola',), # index=577 - ('gong', 'tam-tam'), # index=578 - ('gown',), # index=579 - ('grand piano', 'grand'), # index=580 - ('greenhouse', 'nursery', 'glasshouse'), # index=581 - ('grille', 'radiator grille'), # index=582 - ('grocery store', 'grocery', 'food market', 'market'), # index=583 - ('guillotine',), # index=584 - ('hair slide',), # index=585 - ('hair spray',), # index=586 - ('half track',), # index=587 - ('hammer',), # index=588 - ('hamper',), # index=589 - ('hand blower', 'blow dryer', 'blow drier', 'hair dryer', - 'hair drier'), # index=590 - ('hand-held computer', 'hand-held microcomputer'), # index=591 - ('handkerchief', 'hankie', 'hanky', 'hankey'), # index=592 - ('hard disc', 'hard disk', 'fixed disk'), # index=593 - ('harmonica', 'mouth organ', 'harp', 'mouth harp'), # index=594 - ('harp',), # index=595 - ('harvester', 'reaper'), # index=596 - ('hatchet',), # index=597 - ('holster',), # index=598 - ('home theater', 'home theatre'), # index=599 - ('honeycomb',), # index=600 - ('hook', 'claw'), # index=601 - ('hoopskirt', 'crinoline'), # index=602 - ('horizontal bar', 'high bar'), # index=603 - ('horse cart', 'horse-cart'), # index=604 - ('hourglass',), # index=605 - ('iPod',), # index=606 - ('iron', 'smoothing iron'), # index=607 - ("jack-o'-lantern",), # index=608 - ('jean', 'blue jean', 'denim'), # index=609 - ('jeep', 'landrover'), # index=610 - ('jersey', 'T-shirt', 'tee shirt'), # index=611 - ('jigsaw puzzle',), # index=612 - ('jinrikisha', 'ricksha', 'rickshaw'), # index=613 - ('joystick',), # index=614 - ('kimono',), # index=615 - ('knee pad',), # index=616 - ('knot',), # index=617 - ('lab coat', 'laboratory coat'), # index=618 - ('ladle',), # index=619 - ('lampshade', 'lamp shade'), # index=620 - ('laptop', 'laptop computer'), # index=621 - ('lawn mower', 'mower'), # index=622 - ('lens cap', 'lens cover'), # index=623 - ('letter opener', 'paper knife', 'paperknife'), # index=624 - ('library',), # index=625 - ('lifeboat',), # index=626 - ('lighter', 'light', 'igniter', 'ignitor'), # index=627 - ('limousine', 'limo'), # index=628 - ('liner', 'ocean liner'), # index=629 - ('lipstick', 'lip rouge'), # index=630 - ('Loafer',), # index=631 - ('lotion',), # index=632 - ('loudspeaker', 'speaker', 'speaker unit', 'loudspeaker system', - 'speaker system'), # index=633 - ('loupe', "jeweler's loupe"), # index=634 - ('lumbermill', 'sawmill'), # index=635 - ('magnetic compass',), # index=636 - ('mailbag', 'postbag'), # index=637 - ('mailbox', 'letter box'), # index=638 - ('maillot',), # index=639 - ('maillot', 'tank suit'), # index=640 - ('manhole cover',), # index=641 - ('maraca',), # index=642 - ('marimba', 'xylophone'), # index=643 - ('mask',), # index=644 - ('matchstick',), # index=645 - ('maypole',), # index=646 - ('maze', 'labyrinth'), # index=647 - ('measuring cup',), # index=648 - ('medicine chest', 'medicine cabinet'), # index=649 - ('megalith', 'megalithic structure'), # index=650 - ('microphone', 'mike'), # index=651 - ('microwave', 'microwave oven'), # index=652 - ('military uniform',), # index=653 - ('milk can',), # index=654 - ('minibus',), # index=655 - ('miniskirt', 'mini'), # index=656 - ('minivan',), # index=657 - ('missile',), # index=658 - ('mitten',), # index=659 - ('mixing bowl',), # index=660 - ('mobile home', 'manufactured home'), # index=661 - ('Model T',), # index=662 - ('modem',), # index=663 - ('monastery',), # index=664 - ('monitor',), # index=665 - ('moped',), # index=666 - ('mortar',), # index=667 - ('mortarboard',), # index=668 - ('mosque',), # index=669 - ('mosquito net',), # index=670 - ('motor scooter', 'scooter'), # index=671 - ('mountain bike', 'all-terrain bike', 'off-roader'), # index=672 - ('mountain tent',), # index=673 - ('mouse', 'computer mouse'), # index=674 - ('mousetrap',), # index=675 - ('moving van',), # index=676 - ('muzzle',), # index=677 - ('nail',), # index=678 - ('neck brace',), # index=679 - ('necklace',), # index=680 - ('nipple',), # index=681 - ('notebook', 'notebook computer'), # index=682 - ('obelisk',), # index=683 - ('oboe', 'hautboy', 'hautbois'), # index=684 - ('ocarina', 'sweet potato'), # index=685 - ('odometer', 'hodometer', 'mileometer', 'milometer'), # index=686 - ('oil filter',), # index=687 - ('organ', 'pipe organ'), # index=688 - ('oscilloscope', 'scope', 'cathode-ray oscilloscope', 'CRO'), # index=689 - ('overskirt',), # index=690 - ('oxcart',), # index=691 - ('oxygen mask',), # index=692 - ('packet',), # index=693 - ('paddle', 'boat paddle'), # index=694 - ('paddlewheel', 'paddle wheel'), # index=695 - ('padlock',), # index=696 - ('paintbrush',), # index=697 - ('pajama', 'pyjama', "pj's", 'jammies'), # index=698 - ('palace',), # index=699 - ('panpipe', 'pandean pipe', 'syrinx'), # index=700 - ('paper towel',), # index=701 - ('parachute', 'chute'), # index=702 - ('parallel bars', 'bars'), # index=703 - ('park bench',), # index=704 - ('parking meter',), # index=705 - ('passenger car', 'coach', 'carriage'), # index=706 - ('patio', 'terrace'), # index=707 - ('pay-phone', 'pay-station'), # index=708 - ('pedestal', 'plinth', 'footstall'), # index=709 - ('pencil box', 'pencil case'), # index=710 - ('pencil sharpener',), # index=711 - ('perfume', 'essence'), # index=712 - ('Petri dish',), # index=713 - ('photocopier',), # index=714 - ('pick', 'plectrum', 'plectron'), # index=715 - ('pickelhaube',), # index=716 - ('picket fence', 'paling'), # index=717 - ('pickup', 'pickup truck'), # index=718 - ('pier',), # index=719 - ('piggy bank', 'penny bank'), # index=720 - ('pill bottle',), # index=721 - ('pillow',), # index=722 - ('ping-pong ball',), # index=723 - ('pinwheel',), # index=724 - ('pirate', 'pirate ship'), # index=725 - ('pitcher', 'ewer'), # index=726 - ('plane', "carpenter's plane", 'woodworking plane'), # index=727 - ('planetarium',), # index=728 - ('plastic bag',), # index=729 - ('plate rack',), # index=730 - ('plow', 'plough'), # index=731 - ('plunger', "plumber's helper"), # index=732 - ('Polaroid camera', 'Polaroid Land camera'), # index=733 - ('pole',), # index=734 - ('police van', 'police wagon', 'paddy wagon', 'patrol wagon', 'wagon', - 'black Maria'), # index=735 - ('poncho',), # index=736 - ('pool table', 'billiard table', 'snooker table'), # index=737 - ('pop bottle', 'soda bottle'), # index=738 - ('pot', 'flowerpot'), # index=739 - ("potter's wheel",), # index=740 - ('power drill',), # index=741 - ('prayer rug', 'prayer mat'), # index=742 - ('printer',), # index=743 - ('prison', 'prison house'), # index=744 - ('projectile', 'missile'), # index=745 - ('projector',), # index=746 - ('puck', 'hockey puck'), # index=747 - ('punching bag', 'punch bag', 'punching ball', 'punchball'), # index=748 - ('purse',), # index=749 - ('quill', 'quill pen'), # index=750 - ('quilt', 'comforter', 'comfort', 'puff'), # index=751 - ('racer', 'race car', 'racing car'), # index=752 - ('racket', 'racquet'), # index=753 - ('radiator',), # index=754 - ('radio', 'wireless'), # index=755 - ('radio telescope', 'radio reflector'), # index=756 - ('rain barrel',), # index=757 - ('recreational vehicle', 'RV', 'R.V.'), # index=758 - ('reel',), # index=759 - ('reflex camera',), # index=760 - ('refrigerator', 'icebox'), # index=761 - ('remote control', 'remote'), # index=762 - ('restaurant', 'eating house', 'eating place', 'eatery'), # index=763 - ('revolver', 'six-gun', 'six-shooter'), # index=764 - ('rifle',), # index=765 - ('rocking chair', 'rocker'), # index=766 - ('rotisserie',), # index=767 - ('rubber eraser', 'rubber', 'pencil eraser'), # index=768 - ('rugby ball',), # index=769 - ('rule', 'ruler'), # index=770 - ('running shoe',), # index=771 - ('safe',), # index=772 - ('safety pin',), # index=773 - ('saltshaker', 'salt shaker'), # index=774 - ('sandal',), # index=775 - ('sarong',), # index=776 - ('sax', 'saxophone'), # index=777 - ('scabbard',), # index=778 - ('scale', 'weighing machine'), # index=779 - ('school bus',), # index=780 - ('schooner',), # index=781 - ('scoreboard',), # index=782 - ('screen', 'CRT screen'), # index=783 - ('screw',), # index=784 - ('screwdriver',), # index=785 - ('seat belt', 'seatbelt'), # index=786 - ('sewing machine',), # index=787 - ('shield', 'buckler'), # index=788 - ('shoe shop', 'shoe-shop', 'shoe store'), # index=789 - ('shoji',), # index=790 - ('shopping basket',), # index=791 - ('shopping cart',), # index=792 - ('shovel',), # index=793 - ('shower cap',), # index=794 - ('shower curtain',), # index=795 - ('ski',), # index=796 - ('ski mask',), # index=797 - ('sleeping bag',), # index=798 - ('slide rule', 'slipstick'), # index=799 - ('sliding door',), # index=800 - ('slot', 'one-armed bandit'), # index=801 - ('snorkel',), # index=802 - ('snowmobile',), # index=803 - ('snowplow', 'snowplough'), # index=804 - ('soap dispenser',), # index=805 - ('soccer ball',), # index=806 - ('sock',), # index=807 - ('solar dish', 'solar collector', 'solar furnace'), # index=808 - ('sombrero',), # index=809 - ('soup bowl',), # index=810 - ('space bar',), # index=811 - ('space heater',), # index=812 - ('space shuttle',), # index=813 - ('spatula',), # index=814 - ('speedboat',), # index=815 - ('spider web', "spider's web"), # index=816 - ('spindle',), # index=817 - ('sports car', 'sport car'), # index=818 - ('spotlight', 'spot'), # index=819 - ('stage',), # index=820 - ('steam locomotive',), # index=821 - ('steel arch bridge',), # index=822 - ('steel drum',), # index=823 - ('stethoscope',), # index=824 - ('stole',), # index=825 - ('stone wall',), # index=826 - ('stopwatch', 'stop watch'), # index=827 - ('stove',), # index=828 - ('strainer',), # index=829 - ('streetcar', 'tram', 'tramcar', 'trolley', 'trolley car'), # index=830 - ('stretcher',), # index=831 - ('studio couch', 'day bed'), # index=832 - ('stupa', 'tope'), # index=833 - ('submarine', 'pigboat', 'sub', 'U-boat'), # index=834 - ('suit', 'suit of clothes'), # index=835 - ('sundial',), # index=836 - ('sunglass',), # index=837 - ('sunglasses', 'dark glasses', 'shades'), # index=838 - ('sunscreen', 'sunblock', 'sun blocker'), # index=839 - ('suspension bridge',), # index=840 - ('swab', 'swob', 'mop'), # index=841 - ('sweatshirt',), # index=842 - ('swimming trunks', 'bathing trunks'), # index=843 - ('swing',), # index=844 - ('switch', 'electric switch', 'electrical switch'), # index=845 - ('syringe',), # index=846 - ('table lamp',), # index=847 - ('tank', 'army tank', 'armored combat vehicle', - 'armoured combat vehicle'), # index=848 - ('tape player',), # index=849 - ('teapot',), # index=850 - ('teddy', 'teddy bear'), # index=851 - ('television', 'television system'), # index=852 - ('tennis ball',), # index=853 - ('thatch', 'thatched roof'), # index=854 - ('theater curtain', 'theatre curtain'), # index=855 - ('thimble',), # index=856 - ('thresher', 'thrasher', 'threshing machine'), # index=857 - ('throne',), # index=858 - ('tile roof',), # index=859 - ('toaster',), # index=860 - ('tobacco shop', 'tobacconist shop', 'tobacconist'), # index=861 - ('toilet seat',), # index=862 - ('torch',), # index=863 - ('totem pole',), # index=864 - ('tow truck', 'tow car', 'wrecker'), # index=865 - ('toyshop',), # index=866 - ('tractor',), # index=867 - ('trailer truck', 'tractor trailer', 'trucking rig', 'rig', - 'articulated lorry', 'semi'), # index=868 - ('tray',), # index=869 - ('trench coat',), # index=870 - ('tricycle', 'trike', 'velocipede'), # index=871 - ('trimaran',), # index=872 - ('tripod',), # index=873 - ('triumphal arch',), # index=874 - ('trolleybus', 'trolley coach', 'trackless trolley'), # index=875 - ('trombone',), # index=876 - ('tub', 'vat'), # index=877 - ('turnstile',), # index=878 - ('typewriter keyboard',), # index=879 - ('umbrella',), # index=880 - ('unicycle', 'monocycle'), # index=881 - ('upright', 'upright piano'), # index=882 - ('vacuum', 'vacuum cleaner'), # index=883 - ('vase',), # index=884 - ('vault',), # index=885 - ('velvet',), # index=886 - ('vending machine',), # index=887 - ('vestment',), # index=888 - ('viaduct',), # index=889 - ('violin', 'fiddle'), # index=890 - ('volleyball',), # index=891 - ('waffle iron',), # index=892 - ('wall clock',), # index=893 - ('wallet', 'billfold', 'notecase', 'pocketbook'), # index=894 - ('wardrobe', 'closet', 'press'), # index=895 - ('warplane', 'military plane'), # index=896 - ('washbasin', 'handbasin', 'washbowl', 'lavabo', - 'wash-hand basin'), # index=897 - ('washer', 'automatic washer', 'washing machine'), # index=898 - ('water bottle',), # index=899 - ('water jug',), # index=900 - ('water tower',), # index=901 - ('whiskey jug',), # index=902 - ('whistle',), # index=903 - ('wig',), # index=904 - ('window screen',), # index=905 - ('window shade',), # index=906 - ('Windsor tie',), # index=907 - ('wine bottle',), # index=908 - ('wing',), # index=909 - ('wok',), # index=910 - ('wooden spoon',), # index=911 - ('wool', 'woolen', 'woollen'), # index=912 - ('worm fence', 'snake fence', 'snake-rail fence', - 'Virginia fence'), # index=913 - ('wreck',), # index=914 - ('yawl',), # index=915 - ('yurt',), # index=916 - ('web site', 'website', 'internet site', 'site'), # index=917 - ('comic book',), # index=918 - ('crossword puzzle', 'crossword'), # index=919 - ('street sign',), # index=920 - ('traffic light', 'traffic signal', 'stoplight'), # index=921 - ('book jacket', 'dust cover', 'dust jacket', 'dust wrapper'), # index=922 - ('menu',), # index=923 - ('plate',), # index=924 - ('guacamole',), # index=925 - ('consomme',), # index=926 - ('hot pot', 'hotpot'), # index=927 - ('trifle',), # index=928 - ('ice cream', 'icecream'), # index=929 - ('ice lolly', 'lolly', 'lollipop', 'popsicle'), # index=930 - ('French loaf',), # index=931 - ('bagel', 'beigel'), # index=932 - ('pretzel',), # index=933 - ('cheeseburger',), # index=934 - ('hotdog', 'hot dog', 'red hot'), # index=935 - ('mashed potato',), # index=936 - ('head cabbage',), # index=937 - ('broccoli',), # index=938 - ('cauliflower',), # index=939 - ('zucchini', 'courgette'), # index=940 - ('spaghetti squash',), # index=941 - ('acorn squash',), # index=942 - ('butternut squash',), # index=943 - ('cucumber', 'cuke'), # index=944 - ('artichoke', 'globe artichoke'), # index=945 - ('bell pepper',), # index=946 - ('cardoon',), # index=947 - ('mushroom',), # index=948 - ('Granny Smith',), # index=949 - ('strawberry',), # index=950 - ('orange',), # index=951 - ('lemon',), # index=952 - ('fig',), # index=953 - ('pineapple', 'ananas'), # index=954 - ('banana',), # index=955 - ('jackfruit', 'jak', 'jack'), # index=956 - ('custard apple',), # index=957 - ('pomegranate',), # index=958 - ('hay',), # index=959 - ('carbonara',), # index=960 - ('chocolate sauce', 'chocolate syrup'), # index=961 - ('dough',), # index=962 - ('meat loaf', 'meatloaf'), # index=963 - ('pizza', 'pizza pie'), # index=964 - ('potpie',), # index=965 - ('burrito',), # index=966 - ('red wine',), # index=967 - ('espresso',), # index=968 - ('cup',), # index=969 - ('eggnog',), # index=970 - ('alp',), # index=971 - ('bubble',), # index=972 - ('cliff', 'drop', 'drop-off'), # index=973 - ('coral reef',), # index=974 - ('geyser',), # index=975 - ('lakeside', 'lakeshore'), # index=976 - ('promontory', 'headland', 'head', 'foreland'), # index=977 - ('sandbar', 'sand bar'), # index=978 - ('seashore', 'coast', 'seacoast', 'sea-coast'), # index=979 - ('valley', 'vale'), # index=980 - ('volcano',), # index=981 - ('ballplayer', 'baseball player'), # index=982 - ('groom', 'bridegroom'), # index=983 - ('scuba diver',), # index=984 - ('rapeseed',), # index=985 - ('daisy',), # index=986 - ("yellow lady's slipper", 'yellow lady-slipper', 'Cypripedium calceolus', - 'Cypripedium parviflorum'), # index=987 - ('corn',), # index=988 - ('acorn',), # index=989 - ('hip', 'rose hip', 'rosehip'), # index=990 - ('buckeye', 'horse chestnut', 'conker'), # index=991 - ('coral fungus',), # index=992 - ('agaric',), # index=993 - ('gyromitra',), # index=994 - ('stinkhorn', 'carrion fungus'), # index=995 - ('earthstar',), # index=996 - ('hen-of-the-woods', 'hen of the woods', 'Polyporus frondosus', - 'Grifola frondosa'), # index=997 - ('bolete',), # index=998 - ('ear', 'spike', 'capitulum'), # index=999 - ('toilet tissue', 'toilet paper', 'bathroom tissue'), # index=1000 -) diff --git a/src/aiy/vision/models/object_detection.py b/src/aiy/vision/models/object_detection.py deleted file mode 100644 index 47d264f0..00000000 --- a/src/aiy/vision/models/object_detection.py +++ /dev/null @@ -1,230 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""API for Object Detection tasks.""" -import math -import sys - -from aiy.vision.inference import ModelDescriptor -from aiy.vision.models import utils -from aiy.vision.models.object_detection_anchors import ANCHORS - -_COMPUTE_GRAPH_NAME = 'mobilenet_ssd_256res_0.125_person_cat_dog.binaryproto' -_NUM_ANCHORS = len(ANCHORS) -_MACHINE_EPS = sys.float_info.epsilon - - -class Object(object): - """Object detection result.""" - BACKGROUND = 0 - PERSON = 1 - CAT = 2 - DOG = 3 - - _LABELS = { - BACKGROUND: 'BACKGROUND', - PERSON: 'PERSON', - CAT: 'CAT', - DOG: 'DOG', - } - - def __init__(self, bounding_box, kind, score): - """Initialization. - - Args: - bounding_box: a tuple of 4 ints, (x, y, width, height) order. - kind: int, tells what object is in the bounding box. - score: float, confidence score. - """ - self.bounding_box = bounding_box - self.kind = kind - self.score = score - - def __str__(self): - return 'kind=%s(%d), score=%f, bbox=%s' % (self._LABELS[self.kind], - self.kind, self.score, - str(self.bounding_box)) - - -def _decode_detection_result(logit_scores, box_encodings, anchors, - score_threshold, image_size, offset): - """Decodes result as bounding boxes. - - Args: - logit_scores: list of scores - box_encodings: list of bounding boxes - anchors: list of anchors - score_threshold: float, bounding box candidates below this threshold will - be rejected. - image_size: (width, height) - offset: (x, y) - Returns: - A list of ObjectDetection.Result. - """ - assert len(box_encodings) == 4 * _NUM_ANCHORS - assert len(logit_scores) == 4 * _NUM_ANCHORS - - x0, y0 = offset - width, height = image_size - objs = [] - - score_threshold = max(score_threshold, _MACHINE_EPS) - logit_score_threshold = math.log(score_threshold / (1 - score_threshold)) - for i in range(_NUM_ANCHORS): - logits = logit_scores[4 * i: 4 * (i + 1)] - max_logit_score = max(logits) - max_score_index = logits.index(max_logit_score) - # Skip if max score is below threshold or max score is 'background'. - if max_score_index == 0 or max_logit_score <= logit_score_threshold: - continue - - box_encoding = box_encodings[4 * i: 4 * (i + 1)] - xmin, ymin, xmax, ymax = _decode_box_encoding(box_encoding, anchors[i]) - x = int(x0 + xmin * width) - y = int(y0 + ymin * height) - w = int((xmax - xmin) * width) - h = int((ymax - ymin) * height) - max_score = 1.0 / (1.0 + math.exp(-max_logit_score)) - objs.append(Object((x, y, w, h), max_score_index, max_score)) - return objs - - -def _clamp(value): - """Clamps value to range [0.0, 1.0].""" - return min(max(0.0, value), 1.0) - - -def _decode_box_encoding(box_encoding, anchor): - """Decodes bounding box encoding. - - Args: - box_encoding: a tuple of 4 floats. - anchor: a tuple of 4 floats. - Returns: - A tuple of 4 floats (xmin, ymin, xmax, ymax), each has range [0.0, 1.0]. - """ - assert len(box_encoding) == 4 - assert len(anchor) == 4 - y_scale = 10.0 - x_scale = 10.0 - height_scale = 5.0 - width_scale = 5.0 - - rel_y_translation = box_encoding[0] / y_scale - rel_x_translation = box_encoding[1] / x_scale - rel_height_dilation = box_encoding[2] / height_scale - rel_width_dilation = box_encoding[3] / width_scale - - anchor_ymin, anchor_xmin, anchor_ymax, anchor_xmax = anchor - anchor_ycenter = (anchor_ymax + anchor_ymin) / 2 - anchor_xcenter = (anchor_xmax + anchor_xmin) / 2 - anchor_height = anchor_ymax - anchor_ymin - anchor_width = anchor_xmax - anchor_xmin - - ycenter = anchor_ycenter + anchor_height * rel_y_translation - xcenter = anchor_xcenter + anchor_width * rel_x_translation - height = math.exp(rel_height_dilation) * anchor_height - width = math.exp(rel_width_dilation) * anchor_width - - # Clamp value to [0.0, 1.0] range, otherwise, part of the bounding box may - # fall outside of the image. - xmin = _clamp(xcenter - width / 2) - ymin = _clamp(ycenter - height / 2) - xmax = _clamp(xcenter + width / 2) - ymax = _clamp(ycenter + height / 2) - - return (xmin, ymin, xmax, ymax) - - -def _area(box): - _, _, width, height = box - area = width * height - assert area >= 0 - return area - - -def _intersection_area(box1, box2): - x1, y1, width1, height1 = box1 - x2, y2, width2, height2 = box2 - x = max(x1, x2) - y = max(y1, y2) - width = max(min(x1 + width1, x2 + width2) - x, 0) - height = max(min(y1 + height1, y2 + height2) - y, 0) - area = width * height - assert area >= 0 - return area - - -def _overlap_ratio(box1, box2): - """Computes overlap ratio of two bounding boxes. - - Args: - box1: (x, y, width, height). - box2: (x, y, width, height). - - Returns: - float, represents overlap ratio between given boxes. - """ - intersection_area = _intersection_area(box1, box2) - union_area = _area(box1) + _area(box2) - intersection_area - assert union_area >= 0 - if union_area > 0: - return float(intersection_area) / float(union_area) - return 1.0 - - -def _non_maximum_suppression(objs, overlap_threshold=0.5): - """Runs Non Maximum Suppression. - - Removes candidate that overlaps with existing candidate who has higher - score. - - Args: - objs: list of ObjectDetection.Object - overlap_threshold: float - Returns: - A list of ObjectDetection.Object - """ - objs = sorted(objs, key=lambda x: x.score, reverse=True) - for i in range(len(objs)): - if objs[i].score < 0.0: - continue - # Suppress any nearby bounding boxes having lower score than boxes[i] - for j in range(i + 1, len(objs)): - if objs[j].score < 0.0: - continue - if _overlap_ratio(objs[i].bounding_box, - objs[j].bounding_box) > overlap_threshold: - objs[j].score = -1.0 # Suppress box - - return [obj for obj in objs if obj.score >= 0.0] # Exclude suppressed boxes - - -def model(): - return ModelDescriptor( - name='object_detection', - input_shape=(1, 256, 256, 3), - input_normalizer=(128.0, 128.0), - compute_graph=utils.load_compute_graph(_COMPUTE_GRAPH_NAME)) - - -# TODO: check all tensor shapes -def get_objects(result, score_threshold=0.3, offset=(0, 0)): - assert len(result.tensors) == 2 - logit_scores = tuple(result.tensors['concat_1'].data) - box_encodings = tuple(result.tensors['concat'].data) - - size = (result.window.width, result.window.height) - objs = _decode_detection_result(logit_scores, box_encodings, ANCHORS, - score_threshold, size, offset) - return _non_maximum_suppression(objs) diff --git a/src/aiy/vision/models/object_detection_anchors.py b/src/aiy/vision/models/object_detection_anchors.py deleted file mode 100644 index dd2b7d2c..00000000 --- a/src/aiy/vision/models/object_detection_anchors.py +++ /dev/null @@ -1,1295 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Predefined anchors for object detection model.""" - -ANCHORS = ( - (-0.018750000745, -0.018750000745, 0.08124999702, 0.08124999702), - (-0.039460681379, -0.11017136276, 0.10196068138, 0.17267136276), - (-0.11017136276, -0.039460681379, 0.17267136276, 0.10196068138), - (-0.018750000745, 0.043749999255, 0.08124999702, 0.14374999702), - (-0.039460681379, -0.047671362758, 0.10196068138, 0.23517136276), - (-0.11017136276, 0.023039318621, 0.17267136276, 0.16446068883), - (-0.018750000745, 0.10625000298, 0.08124999702, 0.20624999702), - (-0.039460681379, 0.014828637242, 0.10196068138, 0.29767137766), - (-0.11017136276, 0.085539318621, 0.17267136276, 0.22696068883), - (-0.018750000745, 0.16875000298, 0.08124999702, 0.26875001192), - (-0.039460681379, 0.077328637242, 0.10196068138, 0.36017137766), - (-0.11017136276, 0.14803931117, 0.17267136276, 0.28946068883), - (-0.018750000745, 0.23125000298, 0.08124999702, 0.33125001192), - (-0.039460681379, 0.13982863724, 0.10196068138, 0.42267137766), - (-0.11017136276, 0.21053931117, 0.17267136276, 0.35196068883), - (-0.018750000745, 0.29374998808, 0.08124999702, 0.39375001192), - (-0.039460681379, 0.20232863724, 0.10196068138, 0.48517137766), - (-0.11017136276, 0.27303931117, 0.17267136276, 0.41446068883), - (-0.018750000745, 0.35624998808, 0.08124999702, 0.45625001192), - (-0.039460681379, 0.26482862234, 0.10196068138, 0.54767137766), - (-0.11017136276, 0.33553931117, 0.17267136276, 0.47696068883), - (-0.018750000745, 0.41874998808, 0.08124999702, 0.51875001192), - (-0.039460681379, 0.32732862234, 0.10196068138, 0.61017137766), - (-0.11017136276, 0.39803931117, 0.17267136276, 0.53946065903), - (-0.018750000745, 0.48124998808, 0.08124999702, 0.58125001192), - (-0.039460681379, 0.38982862234, 0.10196068138, 0.67267137766), - (-0.11017136276, 0.46053931117, 0.17267136276, 0.60196065903), - (-0.018750000745, 0.54374998808, 0.08124999702, 0.64375001192), - (-0.039460681379, 0.45232862234, 0.10196068138, 0.73517137766), - (-0.11017136276, 0.52303934097, 0.17267136276, 0.66446065903), - (-0.018750000745, 0.60624998808, 0.08124999702, 0.70625001192), - (-0.039460681379, 0.51482862234, 0.10196068138, 0.79767137766), - (-0.11017136276, 0.58553934097, 0.17267136276, 0.72696065903), - (-0.018750000745, 0.66874998808, 0.08124999702, 0.76875001192), - (-0.039460681379, 0.57732862234, 0.10196068138, 0.86017137766), - (-0.11017136276, 0.64803934097, 0.17267136276, 0.78946065903), - (-0.018750000745, 0.73124998808, 0.08124999702, 0.83125001192), - (-0.039460681379, 0.63982862234, 0.10196068138, 0.92267137766), - (-0.11017136276, 0.71053934097, 0.17267136276, 0.85196065903), - (-0.018750000745, 0.79374998808, 0.08124999702, 0.89375001192), - (-0.039460681379, 0.70232862234, 0.10196068138, 0.98517137766), - (-0.11017136276, 0.77303934097, 0.17267136276, 0.91446065903), - (-0.018750000745, 0.85624998808, 0.08124999702, 0.95625001192), - (-0.039460681379, 0.76482862234, 0.10196068138, 1.0476713181), - (-0.11017136276, 0.83553934097, 0.17267136276, 0.97696065903), - (-0.018750000745, 0.91874998808, 0.08124999702, 1.0187499523), - (-0.039460681379, 0.82732862234, 0.10196068138, 1.1101713181), - (-0.11017136276, 0.89803934097, 0.17267136276, 1.039460659), - (0.043749999255, -0.018750000745, 0.14374999702, 0.08124999702), - (0.023039318621, -0.11017136276, 0.16446068883, 0.17267136276), - (-0.047671362758, -0.039460681379, 0.23517136276, 0.10196068138), - (0.043749999255, 0.043749999255, 0.14374999702, 0.14374999702), - (0.023039318621, -0.047671362758, 0.16446068883, 0.23517136276), - (-0.047671362758, 0.023039318621, 0.23517136276, 0.16446068883), - (0.043749999255, 0.10625000298, 0.14374999702, 0.20624999702), - (0.023039318621, 0.014828637242, 0.16446068883, 0.29767137766), - (-0.047671362758, 0.085539318621, 0.23517136276, 0.22696068883), - (0.043749999255, 0.16875000298, 0.14374999702, 0.26875001192), - (0.023039318621, 0.077328637242, 0.16446068883, 0.36017137766), - (-0.047671362758, 0.14803931117, 0.23517136276, 0.28946068883), - (0.043749999255, 0.23125000298, 0.14374999702, 0.33125001192), - (0.023039318621, 0.13982863724, 0.16446068883, 0.42267137766), - (-0.047671362758, 0.21053931117, 0.23517136276, 0.35196068883), - (0.043749999255, 0.29374998808, 0.14374999702, 0.39375001192), - (0.023039318621, 0.20232863724, 0.16446068883, 0.48517137766), - (-0.047671362758, 0.27303931117, 0.23517136276, 0.41446068883), - (0.043749999255, 0.35624998808, 0.14374999702, 0.45625001192), - (0.023039318621, 0.26482862234, 0.16446068883, 0.54767137766), - (-0.047671362758, 0.33553931117, 0.23517136276, 0.47696068883), - (0.043749999255, 0.41874998808, 0.14374999702, 0.51875001192), - (0.023039318621, 0.32732862234, 0.16446068883, 0.61017137766), - (-0.047671362758, 0.39803931117, 0.23517136276, 0.53946065903), - (0.043749999255, 0.48124998808, 0.14374999702, 0.58125001192), - (0.023039318621, 0.38982862234, 0.16446068883, 0.67267137766), - (-0.047671362758, 0.46053931117, 0.23517136276, 0.60196065903), - (0.043749999255, 0.54374998808, 0.14374999702, 0.64375001192), - (0.023039318621, 0.45232862234, 0.16446068883, 0.73517137766), - (-0.047671362758, 0.52303934097, 0.23517136276, 0.66446065903), - (0.043749999255, 0.60624998808, 0.14374999702, 0.70625001192), - (0.023039318621, 0.51482862234, 0.16446068883, 0.79767137766), - (-0.047671362758, 0.58553934097, 0.23517136276, 0.72696065903), - (0.043749999255, 0.66874998808, 0.14374999702, 0.76875001192), - (0.023039318621, 0.57732862234, 0.16446068883, 0.86017137766), - (-0.047671362758, 0.64803934097, 0.23517136276, 0.78946065903), - (0.043749999255, 0.73124998808, 0.14374999702, 0.83125001192), - (0.023039318621, 0.63982862234, 0.16446068883, 0.92267137766), - (-0.047671362758, 0.71053934097, 0.23517136276, 0.85196065903), - (0.043749999255, 0.79374998808, 0.14374999702, 0.89375001192), - (0.023039318621, 0.70232862234, 0.16446068883, 0.98517137766), - (-0.047671362758, 0.77303934097, 0.23517136276, 0.91446065903), - (0.043749999255, 0.85624998808, 0.14374999702, 0.95625001192), - (0.023039318621, 0.76482862234, 0.16446068883, 1.0476713181), - (-0.047671362758, 0.83553934097, 0.23517136276, 0.97696065903), - (0.043749999255, 0.91874998808, 0.14374999702, 1.0187499523), - (0.023039318621, 0.82732862234, 0.16446068883, 1.1101713181), - (-0.047671362758, 0.89803934097, 0.23517136276, 1.039460659), - (0.10625000298, -0.018750000745, 0.20624999702, 0.08124999702), - (0.085539318621, -0.11017136276, 0.22696068883, 0.17267136276), - (0.014828637242, -0.039460681379, 0.29767137766, 0.10196068138), - (0.10625000298, 0.043749999255, 0.20624999702, 0.14374999702), - (0.085539318621, -0.047671362758, 0.22696068883, 0.23517136276), - (0.014828637242, 0.023039318621, 0.29767137766, 0.16446068883), - (0.10625000298, 0.10625000298, 0.20624999702, 0.20624999702), - (0.085539318621, 0.014828637242, 0.22696068883, 0.29767137766), - (0.014828637242, 0.085539318621, 0.29767137766, 0.22696068883), - (0.10625000298, 0.16875000298, 0.20624999702, 0.26875001192), - (0.085539318621, 0.077328637242, 0.22696068883, 0.36017137766), - (0.014828637242, 0.14803931117, 0.29767137766, 0.28946068883), - (0.10625000298, 0.23125000298, 0.20624999702, 0.33125001192), - (0.085539318621, 0.13982863724, 0.22696068883, 0.42267137766), - (0.014828637242, 0.21053931117, 0.29767137766, 0.35196068883), - (0.10625000298, 0.29374998808, 0.20624999702, 0.39375001192), - (0.085539318621, 0.20232863724, 0.22696068883, 0.48517137766), - (0.014828637242, 0.27303931117, 0.29767137766, 0.41446068883), - (0.10625000298, 0.35624998808, 0.20624999702, 0.45625001192), - (0.085539318621, 0.26482862234, 0.22696068883, 0.54767137766), - (0.014828637242, 0.33553931117, 0.29767137766, 0.47696068883), - (0.10625000298, 0.41874998808, 0.20624999702, 0.51875001192), - (0.085539318621, 0.32732862234, 0.22696068883, 0.61017137766), - (0.014828637242, 0.39803931117, 0.29767137766, 0.53946065903), - (0.10625000298, 0.48124998808, 0.20624999702, 0.58125001192), - (0.085539318621, 0.38982862234, 0.22696068883, 0.67267137766), - (0.014828637242, 0.46053931117, 0.29767137766, 0.60196065903), - (0.10625000298, 0.54374998808, 0.20624999702, 0.64375001192), - (0.085539318621, 0.45232862234, 0.22696068883, 0.73517137766), - (0.014828637242, 0.52303934097, 0.29767137766, 0.66446065903), - (0.10625000298, 0.60624998808, 0.20624999702, 0.70625001192), - (0.085539318621, 0.51482862234, 0.22696068883, 0.79767137766), - (0.014828637242, 0.58553934097, 0.29767137766, 0.72696065903), - (0.10625000298, 0.66874998808, 0.20624999702, 0.76875001192), - (0.085539318621, 0.57732862234, 0.22696068883, 0.86017137766), - (0.014828637242, 0.64803934097, 0.29767137766, 0.78946065903), - (0.10625000298, 0.73124998808, 0.20624999702, 0.83125001192), - (0.085539318621, 0.63982862234, 0.22696068883, 0.92267137766), - (0.014828637242, 0.71053934097, 0.29767137766, 0.85196065903), - (0.10625000298, 0.79374998808, 0.20624999702, 0.89375001192), - (0.085539318621, 0.70232862234, 0.22696068883, 0.98517137766), - (0.014828637242, 0.77303934097, 0.29767137766, 0.91446065903), - (0.10625000298, 0.85624998808, 0.20624999702, 0.95625001192), - (0.085539318621, 0.76482862234, 0.22696068883, 1.0476713181), - (0.014828637242, 0.83553934097, 0.29767137766, 0.97696065903), - (0.10625000298, 0.91874998808, 0.20624999702, 1.0187499523), - (0.085539318621, 0.82732862234, 0.22696068883, 1.1101713181), - (0.014828637242, 0.89803934097, 0.29767137766, 1.039460659), - (0.16875000298, -0.018750000745, 0.26875001192, 0.08124999702), - (0.14803931117, -0.11017136276, 0.28946068883, 0.17267136276), - (0.077328637242, -0.039460681379, 0.36017137766, 0.10196068138), - (0.16875000298, 0.043749999255, 0.26875001192, 0.14374999702), - (0.14803931117, -0.047671362758, 0.28946068883, 0.23517136276), - (0.077328637242, 0.023039318621, 0.36017137766, 0.16446068883), - (0.16875000298, 0.10625000298, 0.26875001192, 0.20624999702), - (0.14803931117, 0.014828637242, 0.28946068883, 0.29767137766), - (0.077328637242, 0.085539318621, 0.36017137766, 0.22696068883), - (0.16875000298, 0.16875000298, 0.26875001192, 0.26875001192), - (0.14803931117, 0.077328637242, 0.28946068883, 0.36017137766), - (0.077328637242, 0.14803931117, 0.36017137766, 0.28946068883), - (0.16875000298, 0.23125000298, 0.26875001192, 0.33125001192), - (0.14803931117, 0.13982863724, 0.28946068883, 0.42267137766), - (0.077328637242, 0.21053931117, 0.36017137766, 0.35196068883), - (0.16875000298, 0.29374998808, 0.26875001192, 0.39375001192), - (0.14803931117, 0.20232863724, 0.28946068883, 0.48517137766), - (0.077328637242, 0.27303931117, 0.36017137766, 0.41446068883), - (0.16875000298, 0.35624998808, 0.26875001192, 0.45625001192), - (0.14803931117, 0.26482862234, 0.28946068883, 0.54767137766), - (0.077328637242, 0.33553931117, 0.36017137766, 0.47696068883), - (0.16875000298, 0.41874998808, 0.26875001192, 0.51875001192), - (0.14803931117, 0.32732862234, 0.28946068883, 0.61017137766), - (0.077328637242, 0.39803931117, 0.36017137766, 0.53946065903), - (0.16875000298, 0.48124998808, 0.26875001192, 0.58125001192), - (0.14803931117, 0.38982862234, 0.28946068883, 0.67267137766), - (0.077328637242, 0.46053931117, 0.36017137766, 0.60196065903), - (0.16875000298, 0.54374998808, 0.26875001192, 0.64375001192), - (0.14803931117, 0.45232862234, 0.28946068883, 0.73517137766), - (0.077328637242, 0.52303934097, 0.36017137766, 0.66446065903), - (0.16875000298, 0.60624998808, 0.26875001192, 0.70625001192), - (0.14803931117, 0.51482862234, 0.28946068883, 0.79767137766), - (0.077328637242, 0.58553934097, 0.36017137766, 0.72696065903), - (0.16875000298, 0.66874998808, 0.26875001192, 0.76875001192), - (0.14803931117, 0.57732862234, 0.28946068883, 0.86017137766), - (0.077328637242, 0.64803934097, 0.36017137766, 0.78946065903), - (0.16875000298, 0.73124998808, 0.26875001192, 0.83125001192), - (0.14803931117, 0.63982862234, 0.28946068883, 0.92267137766), - (0.077328637242, 0.71053934097, 0.36017137766, 0.85196065903), - (0.16875000298, 0.79374998808, 0.26875001192, 0.89375001192), - (0.14803931117, 0.70232862234, 0.28946068883, 0.98517137766), - (0.077328637242, 0.77303934097, 0.36017137766, 0.91446065903), - (0.16875000298, 0.85624998808, 0.26875001192, 0.95625001192), - (0.14803931117, 0.76482862234, 0.28946068883, 1.0476713181), - (0.077328637242, 0.83553934097, 0.36017137766, 0.97696065903), - (0.16875000298, 0.91874998808, 0.26875001192, 1.0187499523), - (0.14803931117, 0.82732862234, 0.28946068883, 1.1101713181), - (0.077328637242, 0.89803934097, 0.36017137766, 1.039460659), - (0.23125000298, -0.018750000745, 0.33125001192, 0.08124999702), - (0.21053931117, -0.11017136276, 0.35196068883, 0.17267136276), - (0.13982863724, -0.039460681379, 0.42267137766, 0.10196068138), - (0.23125000298, 0.043749999255, 0.33125001192, 0.14374999702), - (0.21053931117, -0.047671362758, 0.35196068883, 0.23517136276), - (0.13982863724, 0.023039318621, 0.42267137766, 0.16446068883), - (0.23125000298, 0.10625000298, 0.33125001192, 0.20624999702), - (0.21053931117, 0.014828637242, 0.35196068883, 0.29767137766), - (0.13982863724, 0.085539318621, 0.42267137766, 0.22696068883), - (0.23125000298, 0.16875000298, 0.33125001192, 0.26875001192), - (0.21053931117, 0.077328637242, 0.35196068883, 0.36017137766), - (0.13982863724, 0.14803931117, 0.42267137766, 0.28946068883), - (0.23125000298, 0.23125000298, 0.33125001192, 0.33125001192), - (0.21053931117, 0.13982863724, 0.35196068883, 0.42267137766), - (0.13982863724, 0.21053931117, 0.42267137766, 0.35196068883), - (0.23125000298, 0.29374998808, 0.33125001192, 0.39375001192), - (0.21053931117, 0.20232863724, 0.35196068883, 0.48517137766), - (0.13982863724, 0.27303931117, 0.42267137766, 0.41446068883), - (0.23125000298, 0.35624998808, 0.33125001192, 0.45625001192), - (0.21053931117, 0.26482862234, 0.35196068883, 0.54767137766), - (0.13982863724, 0.33553931117, 0.42267137766, 0.47696068883), - (0.23125000298, 0.41874998808, 0.33125001192, 0.51875001192), - (0.21053931117, 0.32732862234, 0.35196068883, 0.61017137766), - (0.13982863724, 0.39803931117, 0.42267137766, 0.53946065903), - (0.23125000298, 0.48124998808, 0.33125001192, 0.58125001192), - (0.21053931117, 0.38982862234, 0.35196068883, 0.67267137766), - (0.13982863724, 0.46053931117, 0.42267137766, 0.60196065903), - (0.23125000298, 0.54374998808, 0.33125001192, 0.64375001192), - (0.21053931117, 0.45232862234, 0.35196068883, 0.73517137766), - (0.13982863724, 0.52303934097, 0.42267137766, 0.66446065903), - (0.23125000298, 0.60624998808, 0.33125001192, 0.70625001192), - (0.21053931117, 0.51482862234, 0.35196068883, 0.79767137766), - (0.13982863724, 0.58553934097, 0.42267137766, 0.72696065903), - (0.23125000298, 0.66874998808, 0.33125001192, 0.76875001192), - (0.21053931117, 0.57732862234, 0.35196068883, 0.86017137766), - (0.13982863724, 0.64803934097, 0.42267137766, 0.78946065903), - (0.23125000298, 0.73124998808, 0.33125001192, 0.83125001192), - (0.21053931117, 0.63982862234, 0.35196068883, 0.92267137766), - (0.13982863724, 0.71053934097, 0.42267137766, 0.85196065903), - (0.23125000298, 0.79374998808, 0.33125001192, 0.89375001192), - (0.21053931117, 0.70232862234, 0.35196068883, 0.98517137766), - (0.13982863724, 0.77303934097, 0.42267137766, 0.91446065903), - (0.23125000298, 0.85624998808, 0.33125001192, 0.95625001192), - (0.21053931117, 0.76482862234, 0.35196068883, 1.0476713181), - (0.13982863724, 0.83553934097, 0.42267137766, 0.97696065903), - (0.23125000298, 0.91874998808, 0.33125001192, 1.0187499523), - (0.21053931117, 0.82732862234, 0.35196068883, 1.1101713181), - (0.13982863724, 0.89803934097, 0.42267137766, 1.039460659), - (0.29374998808, -0.018750000745, 0.39375001192, 0.08124999702), - (0.27303931117, -0.11017136276, 0.41446068883, 0.17267136276), - (0.20232863724, -0.039460681379, 0.48517137766, 0.10196068138), - (0.29374998808, 0.043749999255, 0.39375001192, 0.14374999702), - (0.27303931117, -0.047671362758, 0.41446068883, 0.23517136276), - (0.20232863724, 0.023039318621, 0.48517137766, 0.16446068883), - (0.29374998808, 0.10625000298, 0.39375001192, 0.20624999702), - (0.27303931117, 0.014828637242, 0.41446068883, 0.29767137766), - (0.20232863724, 0.085539318621, 0.48517137766, 0.22696068883), - (0.29374998808, 0.16875000298, 0.39375001192, 0.26875001192), - (0.27303931117, 0.077328637242, 0.41446068883, 0.36017137766), - (0.20232863724, 0.14803931117, 0.48517137766, 0.28946068883), - (0.29374998808, 0.23125000298, 0.39375001192, 0.33125001192), - (0.27303931117, 0.13982863724, 0.41446068883, 0.42267137766), - (0.20232863724, 0.21053931117, 0.48517137766, 0.35196068883), - (0.29374998808, 0.29374998808, 0.39375001192, 0.39375001192), - (0.27303931117, 0.20232863724, 0.41446068883, 0.48517137766), - (0.20232863724, 0.27303931117, 0.48517137766, 0.41446068883), - (0.29374998808, 0.35624998808, 0.39375001192, 0.45625001192), - (0.27303931117, 0.26482862234, 0.41446068883, 0.54767137766), - (0.20232863724, 0.33553931117, 0.48517137766, 0.47696068883), - (0.29374998808, 0.41874998808, 0.39375001192, 0.51875001192), - (0.27303931117, 0.32732862234, 0.41446068883, 0.61017137766), - (0.20232863724, 0.39803931117, 0.48517137766, 0.53946065903), - (0.29374998808, 0.48124998808, 0.39375001192, 0.58125001192), - (0.27303931117, 0.38982862234, 0.41446068883, 0.67267137766), - (0.20232863724, 0.46053931117, 0.48517137766, 0.60196065903), - (0.29374998808, 0.54374998808, 0.39375001192, 0.64375001192), - (0.27303931117, 0.45232862234, 0.41446068883, 0.73517137766), - (0.20232863724, 0.52303934097, 0.48517137766, 0.66446065903), - (0.29374998808, 0.60624998808, 0.39375001192, 0.70625001192), - (0.27303931117, 0.51482862234, 0.41446068883, 0.79767137766), - (0.20232863724, 0.58553934097, 0.48517137766, 0.72696065903), - (0.29374998808, 0.66874998808, 0.39375001192, 0.76875001192), - (0.27303931117, 0.57732862234, 0.41446068883, 0.86017137766), - (0.20232863724, 0.64803934097, 0.48517137766, 0.78946065903), - (0.29374998808, 0.73124998808, 0.39375001192, 0.83125001192), - (0.27303931117, 0.63982862234, 0.41446068883, 0.92267137766), - (0.20232863724, 0.71053934097, 0.48517137766, 0.85196065903), - (0.29374998808, 0.79374998808, 0.39375001192, 0.89375001192), - (0.27303931117, 0.70232862234, 0.41446068883, 0.98517137766), - (0.20232863724, 0.77303934097, 0.48517137766, 0.91446065903), - (0.29374998808, 0.85624998808, 0.39375001192, 0.95625001192), - (0.27303931117, 0.76482862234, 0.41446068883, 1.0476713181), - (0.20232863724, 0.83553934097, 0.48517137766, 0.97696065903), - (0.29374998808, 0.91874998808, 0.39375001192, 1.0187499523), - (0.27303931117, 0.82732862234, 0.41446068883, 1.1101713181), - (0.20232863724, 0.89803934097, 0.48517137766, 1.039460659), - (0.35624998808, -0.018750000745, 0.45625001192, 0.08124999702), - (0.33553931117, -0.11017136276, 0.47696068883, 0.17267136276), - (0.26482862234, -0.039460681379, 0.54767137766, 0.10196068138), - (0.35624998808, 0.043749999255, 0.45625001192, 0.14374999702), - (0.33553931117, -0.047671362758, 0.47696068883, 0.23517136276), - (0.26482862234, 0.023039318621, 0.54767137766, 0.16446068883), - (0.35624998808, 0.10625000298, 0.45625001192, 0.20624999702), - (0.33553931117, 0.014828637242, 0.47696068883, 0.29767137766), - (0.26482862234, 0.085539318621, 0.54767137766, 0.22696068883), - (0.35624998808, 0.16875000298, 0.45625001192, 0.26875001192), - (0.33553931117, 0.077328637242, 0.47696068883, 0.36017137766), - (0.26482862234, 0.14803931117, 0.54767137766, 0.28946068883), - (0.35624998808, 0.23125000298, 0.45625001192, 0.33125001192), - (0.33553931117, 0.13982863724, 0.47696068883, 0.42267137766), - (0.26482862234, 0.21053931117, 0.54767137766, 0.35196068883), - (0.35624998808, 0.29374998808, 0.45625001192, 0.39375001192), - (0.33553931117, 0.20232863724, 0.47696068883, 0.48517137766), - (0.26482862234, 0.27303931117, 0.54767137766, 0.41446068883), - (0.35624998808, 0.35624998808, 0.45625001192, 0.45625001192), - (0.33553931117, 0.26482862234, 0.47696068883, 0.54767137766), - (0.26482862234, 0.33553931117, 0.54767137766, 0.47696068883), - (0.35624998808, 0.41874998808, 0.45625001192, 0.51875001192), - (0.33553931117, 0.32732862234, 0.47696068883, 0.61017137766), - (0.26482862234, 0.39803931117, 0.54767137766, 0.53946065903), - (0.35624998808, 0.48124998808, 0.45625001192, 0.58125001192), - (0.33553931117, 0.38982862234, 0.47696068883, 0.67267137766), - (0.26482862234, 0.46053931117, 0.54767137766, 0.60196065903), - (0.35624998808, 0.54374998808, 0.45625001192, 0.64375001192), - (0.33553931117, 0.45232862234, 0.47696068883, 0.73517137766), - (0.26482862234, 0.52303934097, 0.54767137766, 0.66446065903), - (0.35624998808, 0.60624998808, 0.45625001192, 0.70625001192), - (0.33553931117, 0.51482862234, 0.47696068883, 0.79767137766), - (0.26482862234, 0.58553934097, 0.54767137766, 0.72696065903), - (0.35624998808, 0.66874998808, 0.45625001192, 0.76875001192), - (0.33553931117, 0.57732862234, 0.47696068883, 0.86017137766), - (0.26482862234, 0.64803934097, 0.54767137766, 0.78946065903), - (0.35624998808, 0.73124998808, 0.45625001192, 0.83125001192), - (0.33553931117, 0.63982862234, 0.47696068883, 0.92267137766), - (0.26482862234, 0.71053934097, 0.54767137766, 0.85196065903), - (0.35624998808, 0.79374998808, 0.45625001192, 0.89375001192), - (0.33553931117, 0.70232862234, 0.47696068883, 0.98517137766), - (0.26482862234, 0.77303934097, 0.54767137766, 0.91446065903), - (0.35624998808, 0.85624998808, 0.45625001192, 0.95625001192), - (0.33553931117, 0.76482862234, 0.47696068883, 1.0476713181), - (0.26482862234, 0.83553934097, 0.54767137766, 0.97696065903), - (0.35624998808, 0.91874998808, 0.45625001192, 1.0187499523), - (0.33553931117, 0.82732862234, 0.47696068883, 1.1101713181), - (0.26482862234, 0.89803934097, 0.54767137766, 1.039460659), - (0.41874998808, -0.018750000745, 0.51875001192, 0.08124999702), - (0.39803931117, -0.11017136276, 0.53946065903, 0.17267136276), - (0.32732862234, -0.039460681379, 0.61017137766, 0.10196068138), - (0.41874998808, 0.043749999255, 0.51875001192, 0.14374999702), - (0.39803931117, -0.047671362758, 0.53946065903, 0.23517136276), - (0.32732862234, 0.023039318621, 0.61017137766, 0.16446068883), - (0.41874998808, 0.10625000298, 0.51875001192, 0.20624999702), - (0.39803931117, 0.014828637242, 0.53946065903, 0.29767137766), - (0.32732862234, 0.085539318621, 0.61017137766, 0.22696068883), - (0.41874998808, 0.16875000298, 0.51875001192, 0.26875001192), - (0.39803931117, 0.077328637242, 0.53946065903, 0.36017137766), - (0.32732862234, 0.14803931117, 0.61017137766, 0.28946068883), - (0.41874998808, 0.23125000298, 0.51875001192, 0.33125001192), - (0.39803931117, 0.13982863724, 0.53946065903, 0.42267137766), - (0.32732862234, 0.21053931117, 0.61017137766, 0.35196068883), - (0.41874998808, 0.29374998808, 0.51875001192, 0.39375001192), - (0.39803931117, 0.20232863724, 0.53946065903, 0.48517137766), - (0.32732862234, 0.27303931117, 0.61017137766, 0.41446068883), - (0.41874998808, 0.35624998808, 0.51875001192, 0.45625001192), - (0.39803931117, 0.26482862234, 0.53946065903, 0.54767137766), - (0.32732862234, 0.33553931117, 0.61017137766, 0.47696068883), - (0.41874998808, 0.41874998808, 0.51875001192, 0.51875001192), - (0.39803931117, 0.32732862234, 0.53946065903, 0.61017137766), - (0.32732862234, 0.39803931117, 0.61017137766, 0.53946065903), - (0.41874998808, 0.48124998808, 0.51875001192, 0.58125001192), - (0.39803931117, 0.38982862234, 0.53946065903, 0.67267137766), - (0.32732862234, 0.46053931117, 0.61017137766, 0.60196065903), - (0.41874998808, 0.54374998808, 0.51875001192, 0.64375001192), - (0.39803931117, 0.45232862234, 0.53946065903, 0.73517137766), - (0.32732862234, 0.52303934097, 0.61017137766, 0.66446065903), - (0.41874998808, 0.60624998808, 0.51875001192, 0.70625001192), - (0.39803931117, 0.51482862234, 0.53946065903, 0.79767137766), - (0.32732862234, 0.58553934097, 0.61017137766, 0.72696065903), - (0.41874998808, 0.66874998808, 0.51875001192, 0.76875001192), - (0.39803931117, 0.57732862234, 0.53946065903, 0.86017137766), - (0.32732862234, 0.64803934097, 0.61017137766, 0.78946065903), - (0.41874998808, 0.73124998808, 0.51875001192, 0.83125001192), - (0.39803931117, 0.63982862234, 0.53946065903, 0.92267137766), - (0.32732862234, 0.71053934097, 0.61017137766, 0.85196065903), - (0.41874998808, 0.79374998808, 0.51875001192, 0.89375001192), - (0.39803931117, 0.70232862234, 0.53946065903, 0.98517137766), - (0.32732862234, 0.77303934097, 0.61017137766, 0.91446065903), - (0.41874998808, 0.85624998808, 0.51875001192, 0.95625001192), - (0.39803931117, 0.76482862234, 0.53946065903, 1.0476713181), - (0.32732862234, 0.83553934097, 0.61017137766, 0.97696065903), - (0.41874998808, 0.91874998808, 0.51875001192, 1.0187499523), - (0.39803931117, 0.82732862234, 0.53946065903, 1.1101713181), - (0.32732862234, 0.89803934097, 0.61017137766, 1.039460659), - (0.48124998808, -0.018750000745, 0.58125001192, 0.08124999702), - (0.46053931117, -0.11017136276, 0.60196065903, 0.17267136276), - (0.38982862234, -0.039460681379, 0.67267137766, 0.10196068138), - (0.48124998808, 0.043749999255, 0.58125001192, 0.14374999702), - (0.46053931117, -0.047671362758, 0.60196065903, 0.23517136276), - (0.38982862234, 0.023039318621, 0.67267137766, 0.16446068883), - (0.48124998808, 0.10625000298, 0.58125001192, 0.20624999702), - (0.46053931117, 0.014828637242, 0.60196065903, 0.29767137766), - (0.38982862234, 0.085539318621, 0.67267137766, 0.22696068883), - (0.48124998808, 0.16875000298, 0.58125001192, 0.26875001192), - (0.46053931117, 0.077328637242, 0.60196065903, 0.36017137766), - (0.38982862234, 0.14803931117, 0.67267137766, 0.28946068883), - (0.48124998808, 0.23125000298, 0.58125001192, 0.33125001192), - (0.46053931117, 0.13982863724, 0.60196065903, 0.42267137766), - (0.38982862234, 0.21053931117, 0.67267137766, 0.35196068883), - (0.48124998808, 0.29374998808, 0.58125001192, 0.39375001192), - (0.46053931117, 0.20232863724, 0.60196065903, 0.48517137766), - (0.38982862234, 0.27303931117, 0.67267137766, 0.41446068883), - (0.48124998808, 0.35624998808, 0.58125001192, 0.45625001192), - (0.46053931117, 0.26482862234, 0.60196065903, 0.54767137766), - (0.38982862234, 0.33553931117, 0.67267137766, 0.47696068883), - (0.48124998808, 0.41874998808, 0.58125001192, 0.51875001192), - (0.46053931117, 0.32732862234, 0.60196065903, 0.61017137766), - (0.38982862234, 0.39803931117, 0.67267137766, 0.53946065903), - (0.48124998808, 0.48124998808, 0.58125001192, 0.58125001192), - (0.46053931117, 0.38982862234, 0.60196065903, 0.67267137766), - (0.38982862234, 0.46053931117, 0.67267137766, 0.60196065903), - (0.48124998808, 0.54374998808, 0.58125001192, 0.64375001192), - (0.46053931117, 0.45232862234, 0.60196065903, 0.73517137766), - (0.38982862234, 0.52303934097, 0.67267137766, 0.66446065903), - (0.48124998808, 0.60624998808, 0.58125001192, 0.70625001192), - (0.46053931117, 0.51482862234, 0.60196065903, 0.79767137766), - (0.38982862234, 0.58553934097, 0.67267137766, 0.72696065903), - (0.48124998808, 0.66874998808, 0.58125001192, 0.76875001192), - (0.46053931117, 0.57732862234, 0.60196065903, 0.86017137766), - (0.38982862234, 0.64803934097, 0.67267137766, 0.78946065903), - (0.48124998808, 0.73124998808, 0.58125001192, 0.83125001192), - (0.46053931117, 0.63982862234, 0.60196065903, 0.92267137766), - (0.38982862234, 0.71053934097, 0.67267137766, 0.85196065903), - (0.48124998808, 0.79374998808, 0.58125001192, 0.89375001192), - (0.46053931117, 0.70232862234, 0.60196065903, 0.98517137766), - (0.38982862234, 0.77303934097, 0.67267137766, 0.91446065903), - (0.48124998808, 0.85624998808, 0.58125001192, 0.95625001192), - (0.46053931117, 0.76482862234, 0.60196065903, 1.0476713181), - (0.38982862234, 0.83553934097, 0.67267137766, 0.97696065903), - (0.48124998808, 0.91874998808, 0.58125001192, 1.0187499523), - (0.46053931117, 0.82732862234, 0.60196065903, 1.1101713181), - (0.38982862234, 0.89803934097, 0.67267137766, 1.039460659), - (0.54374998808, -0.018750000745, 0.64375001192, 0.08124999702), - (0.52303934097, -0.11017136276, 0.66446065903, 0.17267136276), - (0.45232862234, -0.039460681379, 0.73517137766, 0.10196068138), - (0.54374998808, 0.043749999255, 0.64375001192, 0.14374999702), - (0.52303934097, -0.047671362758, 0.66446065903, 0.23517136276), - (0.45232862234, 0.023039318621, 0.73517137766, 0.16446068883), - (0.54374998808, 0.10625000298, 0.64375001192, 0.20624999702), - (0.52303934097, 0.014828637242, 0.66446065903, 0.29767137766), - (0.45232862234, 0.085539318621, 0.73517137766, 0.22696068883), - (0.54374998808, 0.16875000298, 0.64375001192, 0.26875001192), - (0.52303934097, 0.077328637242, 0.66446065903, 0.36017137766), - (0.45232862234, 0.14803931117, 0.73517137766, 0.28946068883), - (0.54374998808, 0.23125000298, 0.64375001192, 0.33125001192), - (0.52303934097, 0.13982863724, 0.66446065903, 0.42267137766), - (0.45232862234, 0.21053931117, 0.73517137766, 0.35196068883), - (0.54374998808, 0.29374998808, 0.64375001192, 0.39375001192), - (0.52303934097, 0.20232863724, 0.66446065903, 0.48517137766), - (0.45232862234, 0.27303931117, 0.73517137766, 0.41446068883), - (0.54374998808, 0.35624998808, 0.64375001192, 0.45625001192), - (0.52303934097, 0.26482862234, 0.66446065903, 0.54767137766), - (0.45232862234, 0.33553931117, 0.73517137766, 0.47696068883), - (0.54374998808, 0.41874998808, 0.64375001192, 0.51875001192), - (0.52303934097, 0.32732862234, 0.66446065903, 0.61017137766), - (0.45232862234, 0.39803931117, 0.73517137766, 0.53946065903), - (0.54374998808, 0.48124998808, 0.64375001192, 0.58125001192), - (0.52303934097, 0.38982862234, 0.66446065903, 0.67267137766), - (0.45232862234, 0.46053931117, 0.73517137766, 0.60196065903), - (0.54374998808, 0.54374998808, 0.64375001192, 0.64375001192), - (0.52303934097, 0.45232862234, 0.66446065903, 0.73517137766), - (0.45232862234, 0.52303934097, 0.73517137766, 0.66446065903), - (0.54374998808, 0.60624998808, 0.64375001192, 0.70625001192), - (0.52303934097, 0.51482862234, 0.66446065903, 0.79767137766), - (0.45232862234, 0.58553934097, 0.73517137766, 0.72696065903), - (0.54374998808, 0.66874998808, 0.64375001192, 0.76875001192), - (0.52303934097, 0.57732862234, 0.66446065903, 0.86017137766), - (0.45232862234, 0.64803934097, 0.73517137766, 0.78946065903), - (0.54374998808, 0.73124998808, 0.64375001192, 0.83125001192), - (0.52303934097, 0.63982862234, 0.66446065903, 0.92267137766), - (0.45232862234, 0.71053934097, 0.73517137766, 0.85196065903), - (0.54374998808, 0.79374998808, 0.64375001192, 0.89375001192), - (0.52303934097, 0.70232862234, 0.66446065903, 0.98517137766), - (0.45232862234, 0.77303934097, 0.73517137766, 0.91446065903), - (0.54374998808, 0.85624998808, 0.64375001192, 0.95625001192), - (0.52303934097, 0.76482862234, 0.66446065903, 1.0476713181), - (0.45232862234, 0.83553934097, 0.73517137766, 0.97696065903), - (0.54374998808, 0.91874998808, 0.64375001192, 1.0187499523), - (0.52303934097, 0.82732862234, 0.66446065903, 1.1101713181), - (0.45232862234, 0.89803934097, 0.73517137766, 1.039460659), - (0.60624998808, -0.018750000745, 0.70625001192, 0.08124999702), - (0.58553934097, -0.11017136276, 0.72696065903, 0.17267136276), - (0.51482862234, -0.039460681379, 0.79767137766, 0.10196068138), - (0.60624998808, 0.043749999255, 0.70625001192, 0.14374999702), - (0.58553934097, -0.047671362758, 0.72696065903, 0.23517136276), - (0.51482862234, 0.023039318621, 0.79767137766, 0.16446068883), - (0.60624998808, 0.10625000298, 0.70625001192, 0.20624999702), - (0.58553934097, 0.014828637242, 0.72696065903, 0.29767137766), - (0.51482862234, 0.085539318621, 0.79767137766, 0.22696068883), - (0.60624998808, 0.16875000298, 0.70625001192, 0.26875001192), - (0.58553934097, 0.077328637242, 0.72696065903, 0.36017137766), - (0.51482862234, 0.14803931117, 0.79767137766, 0.28946068883), - (0.60624998808, 0.23125000298, 0.70625001192, 0.33125001192), - (0.58553934097, 0.13982863724, 0.72696065903, 0.42267137766), - (0.51482862234, 0.21053931117, 0.79767137766, 0.35196068883), - (0.60624998808, 0.29374998808, 0.70625001192, 0.39375001192), - (0.58553934097, 0.20232863724, 0.72696065903, 0.48517137766), - (0.51482862234, 0.27303931117, 0.79767137766, 0.41446068883), - (0.60624998808, 0.35624998808, 0.70625001192, 0.45625001192), - (0.58553934097, 0.26482862234, 0.72696065903, 0.54767137766), - (0.51482862234, 0.33553931117, 0.79767137766, 0.47696068883), - (0.60624998808, 0.41874998808, 0.70625001192, 0.51875001192), - (0.58553934097, 0.32732862234, 0.72696065903, 0.61017137766), - (0.51482862234, 0.39803931117, 0.79767137766, 0.53946065903), - (0.60624998808, 0.48124998808, 0.70625001192, 0.58125001192), - (0.58553934097, 0.38982862234, 0.72696065903, 0.67267137766), - (0.51482862234, 0.46053931117, 0.79767137766, 0.60196065903), - (0.60624998808, 0.54374998808, 0.70625001192, 0.64375001192), - (0.58553934097, 0.45232862234, 0.72696065903, 0.73517137766), - (0.51482862234, 0.52303934097, 0.79767137766, 0.66446065903), - (0.60624998808, 0.60624998808, 0.70625001192, 0.70625001192), - (0.58553934097, 0.51482862234, 0.72696065903, 0.79767137766), - (0.51482862234, 0.58553934097, 0.79767137766, 0.72696065903), - (0.60624998808, 0.66874998808, 0.70625001192, 0.76875001192), - (0.58553934097, 0.57732862234, 0.72696065903, 0.86017137766), - (0.51482862234, 0.64803934097, 0.79767137766, 0.78946065903), - (0.60624998808, 0.73124998808, 0.70625001192, 0.83125001192), - (0.58553934097, 0.63982862234, 0.72696065903, 0.92267137766), - (0.51482862234, 0.71053934097, 0.79767137766, 0.85196065903), - (0.60624998808, 0.79374998808, 0.70625001192, 0.89375001192), - (0.58553934097, 0.70232862234, 0.72696065903, 0.98517137766), - (0.51482862234, 0.77303934097, 0.79767137766, 0.91446065903), - (0.60624998808, 0.85624998808, 0.70625001192, 0.95625001192), - (0.58553934097, 0.76482862234, 0.72696065903, 1.0476713181), - (0.51482862234, 0.83553934097, 0.79767137766, 0.97696065903), - (0.60624998808, 0.91874998808, 0.70625001192, 1.0187499523), - (0.58553934097, 0.82732862234, 0.72696065903, 1.1101713181), - (0.51482862234, 0.89803934097, 0.79767137766, 1.039460659), - (0.66874998808, -0.018750000745, 0.76875001192, 0.08124999702), - (0.64803934097, -0.11017136276, 0.78946065903, 0.17267136276), - (0.57732862234, -0.039460681379, 0.86017137766, 0.10196068138), - (0.66874998808, 0.043749999255, 0.76875001192, 0.14374999702), - (0.64803934097, -0.047671362758, 0.78946065903, 0.23517136276), - (0.57732862234, 0.023039318621, 0.86017137766, 0.16446068883), - (0.66874998808, 0.10625000298, 0.76875001192, 0.20624999702), - (0.64803934097, 0.014828637242, 0.78946065903, 0.29767137766), - (0.57732862234, 0.085539318621, 0.86017137766, 0.22696068883), - (0.66874998808, 0.16875000298, 0.76875001192, 0.26875001192), - (0.64803934097, 0.077328637242, 0.78946065903, 0.36017137766), - (0.57732862234, 0.14803931117, 0.86017137766, 0.28946068883), - (0.66874998808, 0.23125000298, 0.76875001192, 0.33125001192), - (0.64803934097, 0.13982863724, 0.78946065903, 0.42267137766), - (0.57732862234, 0.21053931117, 0.86017137766, 0.35196068883), - (0.66874998808, 0.29374998808, 0.76875001192, 0.39375001192), - (0.64803934097, 0.20232863724, 0.78946065903, 0.48517137766), - (0.57732862234, 0.27303931117, 0.86017137766, 0.41446068883), - (0.66874998808, 0.35624998808, 0.76875001192, 0.45625001192), - (0.64803934097, 0.26482862234, 0.78946065903, 0.54767137766), - (0.57732862234, 0.33553931117, 0.86017137766, 0.47696068883), - (0.66874998808, 0.41874998808, 0.76875001192, 0.51875001192), - (0.64803934097, 0.32732862234, 0.78946065903, 0.61017137766), - (0.57732862234, 0.39803931117, 0.86017137766, 0.53946065903), - (0.66874998808, 0.48124998808, 0.76875001192, 0.58125001192), - (0.64803934097, 0.38982862234, 0.78946065903, 0.67267137766), - (0.57732862234, 0.46053931117, 0.86017137766, 0.60196065903), - (0.66874998808, 0.54374998808, 0.76875001192, 0.64375001192), - (0.64803934097, 0.45232862234, 0.78946065903, 0.73517137766), - (0.57732862234, 0.52303934097, 0.86017137766, 0.66446065903), - (0.66874998808, 0.60624998808, 0.76875001192, 0.70625001192), - (0.64803934097, 0.51482862234, 0.78946065903, 0.79767137766), - (0.57732862234, 0.58553934097, 0.86017137766, 0.72696065903), - (0.66874998808, 0.66874998808, 0.76875001192, 0.76875001192), - (0.64803934097, 0.57732862234, 0.78946065903, 0.86017137766), - (0.57732862234, 0.64803934097, 0.86017137766, 0.78946065903), - (0.66874998808, 0.73124998808, 0.76875001192, 0.83125001192), - (0.64803934097, 0.63982862234, 0.78946065903, 0.92267137766), - (0.57732862234, 0.71053934097, 0.86017137766, 0.85196065903), - (0.66874998808, 0.79374998808, 0.76875001192, 0.89375001192), - (0.64803934097, 0.70232862234, 0.78946065903, 0.98517137766), - (0.57732862234, 0.77303934097, 0.86017137766, 0.91446065903), - (0.66874998808, 0.85624998808, 0.76875001192, 0.95625001192), - (0.64803934097, 0.76482862234, 0.78946065903, 1.0476713181), - (0.57732862234, 0.83553934097, 0.86017137766, 0.97696065903), - (0.66874998808, 0.91874998808, 0.76875001192, 1.0187499523), - (0.64803934097, 0.82732862234, 0.78946065903, 1.1101713181), - (0.57732862234, 0.89803934097, 0.86017137766, 1.039460659), - (0.73124998808, -0.018750000745, 0.83125001192, 0.08124999702), - (0.71053934097, -0.11017136276, 0.85196065903, 0.17267136276), - (0.63982862234, -0.039460681379, 0.92267137766, 0.10196068138), - (0.73124998808, 0.043749999255, 0.83125001192, 0.14374999702), - (0.71053934097, -0.047671362758, 0.85196065903, 0.23517136276), - (0.63982862234, 0.023039318621, 0.92267137766, 0.16446068883), - (0.73124998808, 0.10625000298, 0.83125001192, 0.20624999702), - (0.71053934097, 0.014828637242, 0.85196065903, 0.29767137766), - (0.63982862234, 0.085539318621, 0.92267137766, 0.22696068883), - (0.73124998808, 0.16875000298, 0.83125001192, 0.26875001192), - (0.71053934097, 0.077328637242, 0.85196065903, 0.36017137766), - (0.63982862234, 0.14803931117, 0.92267137766, 0.28946068883), - (0.73124998808, 0.23125000298, 0.83125001192, 0.33125001192), - (0.71053934097, 0.13982863724, 0.85196065903, 0.42267137766), - (0.63982862234, 0.21053931117, 0.92267137766, 0.35196068883), - (0.73124998808, 0.29374998808, 0.83125001192, 0.39375001192), - (0.71053934097, 0.20232863724, 0.85196065903, 0.48517137766), - (0.63982862234, 0.27303931117, 0.92267137766, 0.41446068883), - (0.73124998808, 0.35624998808, 0.83125001192, 0.45625001192), - (0.71053934097, 0.26482862234, 0.85196065903, 0.54767137766), - (0.63982862234, 0.33553931117, 0.92267137766, 0.47696068883), - (0.73124998808, 0.41874998808, 0.83125001192, 0.51875001192), - (0.71053934097, 0.32732862234, 0.85196065903, 0.61017137766), - (0.63982862234, 0.39803931117, 0.92267137766, 0.53946065903), - (0.73124998808, 0.48124998808, 0.83125001192, 0.58125001192), - (0.71053934097, 0.38982862234, 0.85196065903, 0.67267137766), - (0.63982862234, 0.46053931117, 0.92267137766, 0.60196065903), - (0.73124998808, 0.54374998808, 0.83125001192, 0.64375001192), - (0.71053934097, 0.45232862234, 0.85196065903, 0.73517137766), - (0.63982862234, 0.52303934097, 0.92267137766, 0.66446065903), - (0.73124998808, 0.60624998808, 0.83125001192, 0.70625001192), - (0.71053934097, 0.51482862234, 0.85196065903, 0.79767137766), - (0.63982862234, 0.58553934097, 0.92267137766, 0.72696065903), - (0.73124998808, 0.66874998808, 0.83125001192, 0.76875001192), - (0.71053934097, 0.57732862234, 0.85196065903, 0.86017137766), - (0.63982862234, 0.64803934097, 0.92267137766, 0.78946065903), - (0.73124998808, 0.73124998808, 0.83125001192, 0.83125001192), - (0.71053934097, 0.63982862234, 0.85196065903, 0.92267137766), - (0.63982862234, 0.71053934097, 0.92267137766, 0.85196065903), - (0.73124998808, 0.79374998808, 0.83125001192, 0.89375001192), - (0.71053934097, 0.70232862234, 0.85196065903, 0.98517137766), - (0.63982862234, 0.77303934097, 0.92267137766, 0.91446065903), - (0.73124998808, 0.85624998808, 0.83125001192, 0.95625001192), - (0.71053934097, 0.76482862234, 0.85196065903, 1.0476713181), - (0.63982862234, 0.83553934097, 0.92267137766, 0.97696065903), - (0.73124998808, 0.91874998808, 0.83125001192, 1.0187499523), - (0.71053934097, 0.82732862234, 0.85196065903, 1.1101713181), - (0.63982862234, 0.89803934097, 0.92267137766, 1.039460659), - (0.79374998808, -0.018750000745, 0.89375001192, 0.08124999702), - (0.77303934097, -0.11017136276, 0.91446065903, 0.17267136276), - (0.70232862234, -0.039460681379, 0.98517137766, 0.10196068138), - (0.79374998808, 0.043749999255, 0.89375001192, 0.14374999702), - (0.77303934097, -0.047671362758, 0.91446065903, 0.23517136276), - (0.70232862234, 0.023039318621, 0.98517137766, 0.16446068883), - (0.79374998808, 0.10625000298, 0.89375001192, 0.20624999702), - (0.77303934097, 0.014828637242, 0.91446065903, 0.29767137766), - (0.70232862234, 0.085539318621, 0.98517137766, 0.22696068883), - (0.79374998808, 0.16875000298, 0.89375001192, 0.26875001192), - (0.77303934097, 0.077328637242, 0.91446065903, 0.36017137766), - (0.70232862234, 0.14803931117, 0.98517137766, 0.28946068883), - (0.79374998808, 0.23125000298, 0.89375001192, 0.33125001192), - (0.77303934097, 0.13982863724, 0.91446065903, 0.42267137766), - (0.70232862234, 0.21053931117, 0.98517137766, 0.35196068883), - (0.79374998808, 0.29374998808, 0.89375001192, 0.39375001192), - (0.77303934097, 0.20232863724, 0.91446065903, 0.48517137766), - (0.70232862234, 0.27303931117, 0.98517137766, 0.41446068883), - (0.79374998808, 0.35624998808, 0.89375001192, 0.45625001192), - (0.77303934097, 0.26482862234, 0.91446065903, 0.54767137766), - (0.70232862234, 0.33553931117, 0.98517137766, 0.47696068883), - (0.79374998808, 0.41874998808, 0.89375001192, 0.51875001192), - (0.77303934097, 0.32732862234, 0.91446065903, 0.61017137766), - (0.70232862234, 0.39803931117, 0.98517137766, 0.53946065903), - (0.79374998808, 0.48124998808, 0.89375001192, 0.58125001192), - (0.77303934097, 0.38982862234, 0.91446065903, 0.67267137766), - (0.70232862234, 0.46053931117, 0.98517137766, 0.60196065903), - (0.79374998808, 0.54374998808, 0.89375001192, 0.64375001192), - (0.77303934097, 0.45232862234, 0.91446065903, 0.73517137766), - (0.70232862234, 0.52303934097, 0.98517137766, 0.66446065903), - (0.79374998808, 0.60624998808, 0.89375001192, 0.70625001192), - (0.77303934097, 0.51482862234, 0.91446065903, 0.79767137766), - (0.70232862234, 0.58553934097, 0.98517137766, 0.72696065903), - (0.79374998808, 0.66874998808, 0.89375001192, 0.76875001192), - (0.77303934097, 0.57732862234, 0.91446065903, 0.86017137766), - (0.70232862234, 0.64803934097, 0.98517137766, 0.78946065903), - (0.79374998808, 0.73124998808, 0.89375001192, 0.83125001192), - (0.77303934097, 0.63982862234, 0.91446065903, 0.92267137766), - (0.70232862234, 0.71053934097, 0.98517137766, 0.85196065903), - (0.79374998808, 0.79374998808, 0.89375001192, 0.89375001192), - (0.77303934097, 0.70232862234, 0.91446065903, 0.98517137766), - (0.70232862234, 0.77303934097, 0.98517137766, 0.91446065903), - (0.79374998808, 0.85624998808, 0.89375001192, 0.95625001192), - (0.77303934097, 0.76482862234, 0.91446065903, 1.0476713181), - (0.70232862234, 0.83553934097, 0.98517137766, 0.97696065903), - (0.79374998808, 0.91874998808, 0.89375001192, 1.0187499523), - (0.77303934097, 0.82732862234, 0.91446065903, 1.1101713181), - (0.70232862234, 0.89803934097, 0.98517137766, 1.039460659), - (0.85624998808, -0.018750000745, 0.95625001192, 0.08124999702), - (0.83553934097, -0.11017136276, 0.97696065903, 0.17267136276), - (0.76482862234, -0.039460681379, 1.0476713181, 0.10196068138), - (0.85624998808, 0.043749999255, 0.95625001192, 0.14374999702), - (0.83553934097, -0.047671362758, 0.97696065903, 0.23517136276), - (0.76482862234, 0.023039318621, 1.0476713181, 0.16446068883), - (0.85624998808, 0.10625000298, 0.95625001192, 0.20624999702), - (0.83553934097, 0.014828637242, 0.97696065903, 0.29767137766), - (0.76482862234, 0.085539318621, 1.0476713181, 0.22696068883), - (0.85624998808, 0.16875000298, 0.95625001192, 0.26875001192), - (0.83553934097, 0.077328637242, 0.97696065903, 0.36017137766), - (0.76482862234, 0.14803931117, 1.0476713181, 0.28946068883), - (0.85624998808, 0.23125000298, 0.95625001192, 0.33125001192), - (0.83553934097, 0.13982863724, 0.97696065903, 0.42267137766), - (0.76482862234, 0.21053931117, 1.0476713181, 0.35196068883), - (0.85624998808, 0.29374998808, 0.95625001192, 0.39375001192), - (0.83553934097, 0.20232863724, 0.97696065903, 0.48517137766), - (0.76482862234, 0.27303931117, 1.0476713181, 0.41446068883), - (0.85624998808, 0.35624998808, 0.95625001192, 0.45625001192), - (0.83553934097, 0.26482862234, 0.97696065903, 0.54767137766), - (0.76482862234, 0.33553931117, 1.0476713181, 0.47696068883), - (0.85624998808, 0.41874998808, 0.95625001192, 0.51875001192), - (0.83553934097, 0.32732862234, 0.97696065903, 0.61017137766), - (0.76482862234, 0.39803931117, 1.0476713181, 0.53946065903), - (0.85624998808, 0.48124998808, 0.95625001192, 0.58125001192), - (0.83553934097, 0.38982862234, 0.97696065903, 0.67267137766), - (0.76482862234, 0.46053931117, 1.0476713181, 0.60196065903), - (0.85624998808, 0.54374998808, 0.95625001192, 0.64375001192), - (0.83553934097, 0.45232862234, 0.97696065903, 0.73517137766), - (0.76482862234, 0.52303934097, 1.0476713181, 0.66446065903), - (0.85624998808, 0.60624998808, 0.95625001192, 0.70625001192), - (0.83553934097, 0.51482862234, 0.97696065903, 0.79767137766), - (0.76482862234, 0.58553934097, 1.0476713181, 0.72696065903), - (0.85624998808, 0.66874998808, 0.95625001192, 0.76875001192), - (0.83553934097, 0.57732862234, 0.97696065903, 0.86017137766), - (0.76482862234, 0.64803934097, 1.0476713181, 0.78946065903), - (0.85624998808, 0.73124998808, 0.95625001192, 0.83125001192), - (0.83553934097, 0.63982862234, 0.97696065903, 0.92267137766), - (0.76482862234, 0.71053934097, 1.0476713181, 0.85196065903), - (0.85624998808, 0.79374998808, 0.95625001192, 0.89375001192), - (0.83553934097, 0.70232862234, 0.97696065903, 0.98517137766), - (0.76482862234, 0.77303934097, 1.0476713181, 0.91446065903), - (0.85624998808, 0.85624998808, 0.95625001192, 0.95625001192), - (0.83553934097, 0.76482862234, 0.97696065903, 1.0476713181), - (0.76482862234, 0.83553934097, 1.0476713181, 0.97696065903), - (0.85624998808, 0.91874998808, 0.95625001192, 1.0187499523), - (0.83553934097, 0.82732862234, 0.97696065903, 1.1101713181), - (0.76482862234, 0.89803934097, 1.0476713181, 1.039460659), - (0.91874998808, -0.018750000745, 1.0187499523, 0.08124999702), - (0.89803934097, -0.11017136276, 1.039460659, 0.17267136276), - (0.82732862234, -0.039460681379, 1.1101713181, 0.10196068138), - (0.91874998808, 0.043749999255, 1.0187499523, 0.14374999702), - (0.89803934097, -0.047671362758, 1.039460659, 0.23517136276), - (0.82732862234, 0.023039318621, 1.1101713181, 0.16446068883), - (0.91874998808, 0.10625000298, 1.0187499523, 0.20624999702), - (0.89803934097, 0.014828637242, 1.039460659, 0.29767137766), - (0.82732862234, 0.085539318621, 1.1101713181, 0.22696068883), - (0.91874998808, 0.16875000298, 1.0187499523, 0.26875001192), - (0.89803934097, 0.077328637242, 1.039460659, 0.36017137766), - (0.82732862234, 0.14803931117, 1.1101713181, 0.28946068883), - (0.91874998808, 0.23125000298, 1.0187499523, 0.33125001192), - (0.89803934097, 0.13982863724, 1.039460659, 0.42267137766), - (0.82732862234, 0.21053931117, 1.1101713181, 0.35196068883), - (0.91874998808, 0.29374998808, 1.0187499523, 0.39375001192), - (0.89803934097, 0.20232863724, 1.039460659, 0.48517137766), - (0.82732862234, 0.27303931117, 1.1101713181, 0.41446068883), - (0.91874998808, 0.35624998808, 1.0187499523, 0.45625001192), - (0.89803934097, 0.26482862234, 1.039460659, 0.54767137766), - (0.82732862234, 0.33553931117, 1.1101713181, 0.47696068883), - (0.91874998808, 0.41874998808, 1.0187499523, 0.51875001192), - (0.89803934097, 0.32732862234, 1.039460659, 0.61017137766), - (0.82732862234, 0.39803931117, 1.1101713181, 0.53946065903), - (0.91874998808, 0.48124998808, 1.0187499523, 0.58125001192), - (0.89803934097, 0.38982862234, 1.039460659, 0.67267137766), - (0.82732862234, 0.46053931117, 1.1101713181, 0.60196065903), - (0.91874998808, 0.54374998808, 1.0187499523, 0.64375001192), - (0.89803934097, 0.45232862234, 1.039460659, 0.73517137766), - (0.82732862234, 0.52303934097, 1.1101713181, 0.66446065903), - (0.91874998808, 0.60624998808, 1.0187499523, 0.70625001192), - (0.89803934097, 0.51482862234, 1.039460659, 0.79767137766), - (0.82732862234, 0.58553934097, 1.1101713181, 0.72696065903), - (0.91874998808, 0.66874998808, 1.0187499523, 0.76875001192), - (0.89803934097, 0.57732862234, 1.039460659, 0.86017137766), - (0.82732862234, 0.64803934097, 1.1101713181, 0.78946065903), - (0.91874998808, 0.73124998808, 1.0187499523, 0.83125001192), - (0.89803934097, 0.63982862234, 1.039460659, 0.92267137766), - (0.82732862234, 0.71053934097, 1.1101713181, 0.85196065903), - (0.91874998808, 0.79374998808, 1.0187499523, 0.89375001192), - (0.89803934097, 0.70232862234, 1.039460659, 0.98517137766), - (0.82732862234, 0.77303934097, 1.1101713181, 0.91446065903), - (0.91874998808, 0.85624998808, 1.0187499523, 0.95625001192), - (0.89803934097, 0.76482862234, 1.039460659, 1.0476713181), - (0.82732862234, 0.83553934097, 1.1101713181, 0.97696065903), - (0.91874998808, 0.91874998808, 1.0187499523, 1.0187499523), - (0.89803934097, 0.82732862234, 1.039460659, 1.1101713181), - (0.82732862234, 0.89803934097, 1.1101713181, 1.039460659), - (-0.13125000894, -0.13124997914, 0.25625002384, 0.25624996424), - (-0.074501946568, -0.21150383353, 0.19950194657, 0.33650383353), - (-0.21150389314, -0.074501916766, 0.33650389314, 0.19950191677), - (-0.049361616373, -0.27308481932, 0.17436161637, 0.39808481932), - (-0.27310159802, -0.049356020987, 0.39810159802, 0.17435601354), - (-0.17351509631, -0.17351509631, 0.29851508141, 0.29851508141), - (-0.13125000894, -0.0062499791384, 0.25625002384, 0.38124996424), - (-0.074501946568, -0.086503833532, 0.19950194657, 0.46150383353), - (-0.21150389314, 0.050498083234, 0.33650389314, 0.32450193167), - (-0.049361616373, -0.14808481932, 0.17436161637, 0.52308481932), - (-0.27310159802, 0.075643979013, 0.39810159802, 0.29935601354), - (-0.17351509631, -0.048515096307, 0.29851508141, 0.42351508141), - (-0.13125000894, 0.11875002086, 0.25625002384, 0.50624996424), - (-0.074501946568, 0.038496166468, 0.19950194657, 0.58650386333), - (-0.21150389314, 0.17549808323, 0.33650389314, 0.44950193167), - (-0.049361616373, -0.023084819317, 0.17436161637, 0.64808481932), - (-0.27310159802, 0.20064398646, 0.39810159802, 0.42435601354), - (-0.17351509631, 0.076484903693, 0.29851508141, 0.54851508141), - (-0.13125000894, 0.24375002086, 0.25625002384, 0.63124996424), - (-0.074501946568, 0.16349616647, 0.19950194657, 0.71150386333), - (-0.21150389314, 0.30049806833, 0.33650389314, 0.57450193167), - (-0.049361616373, 0.10191518068, 0.17436161637, 0.77308481932), - (-0.27310159802, 0.32564398646, 0.39810159802, 0.54935604334), - (-0.17351509631, 0.20148490369, 0.29851508141, 0.67351508141), - (-0.13125000894, 0.36875003576, 0.25625002384, 0.75624996424), - (-0.074501946568, 0.28849616647, 0.19950194657, 0.83650386333), - (-0.21150389314, 0.42549806833, 0.33650389314, 0.69950193167), - (-0.049361616373, 0.22691518068, 0.17436161637, 0.89808481932), - (-0.27310159802, 0.45064398646, 0.39810159802, 0.67435604334), - (-0.17351509631, 0.32648491859, 0.29851508141, 0.79851508141), - (-0.13125000894, 0.49375003576, 0.25625002384, 0.88124996424), - (-0.074501946568, 0.41349616647, 0.19950194657, 0.96150386333), - (-0.21150389314, 0.55049806833, 0.33650389314, 0.82450193167), - (-0.049361616373, 0.35191518068, 0.17436161637, 1.0230848789), - (-0.27310159802, 0.57564395666, 0.39810159802, 0.79935604334), - (-0.17351509631, 0.45148491859, 0.29851508141, 0.92351508141), - (-0.13125000894, 0.61875003576, 0.25625002384, 1.0062500238), - (-0.074501946568, 0.53849613667, 0.19950194657, 1.0865038633), - (-0.21150389314, 0.67549806833, 0.33650389314, 0.94950193167), - (-0.049361616373, 0.47691518068, 0.17436161637, 1.1480848789), - (-0.27310159802, 0.70064395666, 0.39810159802, 0.92435604334), - (-0.17351509631, 0.57648491859, 0.29851508141, 1.0485150814), - (-0.13125000894, 0.74375003576, 0.25625002384, 1.1312500238), - (-0.074501946568, 0.66349613667, 0.19950194657, 1.2115038633), - (-0.21150389314, 0.80049806833, 0.33650389314, 1.0745018721), - (-0.049361616373, 0.60191518068, 0.17436161637, 1.2730848789), - (-0.27310159802, 0.82564395666, 0.39810159802, 1.0493559837), - (-0.17351509631, 0.70148491859, 0.29851508141, 1.1735150814), - (-0.0062500089407, -0.13124997914, 0.38125002384, 0.25624996424), - (0.050498053432, -0.21150383353, 0.32450193167, 0.33650383353), - (-0.086503893137, -0.074501916766, 0.46150389314, 0.19950191677), - (0.075638383627, -0.27308481932, 0.29936161637, 0.39808481932), - (-0.14810159802, -0.049356020987, 0.52310156822, 0.17435601354), - (-0.048515096307, -0.17351509631, 0.42351508141, 0.29851508141), - (-0.0062500089407, -0.0062499791384, 0.38125002384, 0.38124996424), - (0.050498053432, -0.086503833532, 0.32450193167, 0.46150383353), - (-0.086503893137, 0.050498083234, 0.46150389314, 0.32450193167), - (0.075638383627, -0.14808481932, 0.29936161637, 0.52308481932), - (-0.14810159802, 0.075643979013, 0.52310156822, 0.29935601354), - (-0.048515096307, -0.048515096307, 0.42351508141, 0.42351508141), - (-0.0062500089407, 0.11875002086, 0.38125002384, 0.50624996424), - (0.050498053432, 0.038496166468, 0.32450193167, 0.58650386333), - (-0.086503893137, 0.17549808323, 0.46150389314, 0.44950193167), - (0.075638383627, -0.023084819317, 0.29936161637, 0.64808481932), - (-0.14810159802, 0.20064398646, 0.52310156822, 0.42435601354), - (-0.048515096307, 0.076484903693, 0.42351508141, 0.54851508141), - (-0.0062500089407, 0.24375002086, 0.38125002384, 0.63124996424), - (0.050498053432, 0.16349616647, 0.32450193167, 0.71150386333), - (-0.086503893137, 0.30049806833, 0.46150389314, 0.57450193167), - (0.075638383627, 0.10191518068, 0.29936161637, 0.77308481932), - (-0.14810159802, 0.32564398646, 0.52310156822, 0.54935604334), - (-0.048515096307, 0.20148490369, 0.42351508141, 0.67351508141), - (-0.0062500089407, 0.36875003576, 0.38125002384, 0.75624996424), - (0.050498053432, 0.28849616647, 0.32450193167, 0.83650386333), - (-0.086503893137, 0.42549806833, 0.46150389314, 0.69950193167), - (0.075638383627, 0.22691518068, 0.29936161637, 0.89808481932), - (-0.14810159802, 0.45064398646, 0.52310156822, 0.67435604334), - (-0.048515096307, 0.32648491859, 0.42351508141, 0.79851508141), - (-0.0062500089407, 0.49375003576, 0.38125002384, 0.88124996424), - (0.050498053432, 0.41349616647, 0.32450193167, 0.96150386333), - (-0.086503893137, 0.55049806833, 0.46150389314, 0.82450193167), - (0.075638383627, 0.35191518068, 0.29936161637, 1.0230848789), - (-0.14810159802, 0.57564395666, 0.52310156822, 0.79935604334), - (-0.048515096307, 0.45148491859, 0.42351508141, 0.92351508141), - (-0.0062500089407, 0.61875003576, 0.38125002384, 1.0062500238), - (0.050498053432, 0.53849613667, 0.32450193167, 1.0865038633), - (-0.086503893137, 0.67549806833, 0.46150389314, 0.94950193167), - (0.075638383627, 0.47691518068, 0.29936161637, 1.1480848789), - (-0.14810159802, 0.70064395666, 0.52310156822, 0.92435604334), - (-0.048515096307, 0.57648491859, 0.42351508141, 1.0485150814), - (-0.0062500089407, 0.74375003576, 0.38125002384, 1.1312500238), - (0.050498053432, 0.66349613667, 0.32450193167, 1.2115038633), - (-0.086503893137, 0.80049806833, 0.46150389314, 1.0745018721), - (0.075638383627, 0.60191518068, 0.29936161637, 1.2730848789), - (-0.14810159802, 0.82564395666, 0.52310156822, 1.0493559837), - (-0.048515096307, 0.70148491859, 0.42351508141, 1.1735150814), - (0.11874999106, -0.13124997914, 0.50625002384, 0.25624996424), - (0.17549805343, -0.21150383353, 0.44950193167, 0.33650383353), - (0.038496106863, -0.074501916766, 0.58650386333, 0.19950191677), - (0.20063838363, -0.27308481932, 0.42436161637, 0.39808481932), - (-0.023101598024, -0.049356020987, 0.64810156822, 0.17435601354), - (0.076484903693, -0.17351509631, 0.54851508141, 0.29851508141), - (0.11874999106, -0.0062499791384, 0.50625002384, 0.38124996424), - (0.17549805343, -0.086503833532, 0.44950193167, 0.46150383353), - (0.038496106863, 0.050498083234, 0.58650386333, 0.32450193167), - (0.20063838363, -0.14808481932, 0.42436161637, 0.52308481932), - (-0.023101598024, 0.075643979013, 0.64810156822, 0.29935601354), - (0.076484903693, -0.048515096307, 0.54851508141, 0.42351508141), - (0.11874999106, 0.11875002086, 0.50625002384, 0.50624996424), - (0.17549805343, 0.038496166468, 0.44950193167, 0.58650386333), - (0.038496106863, 0.17549808323, 0.58650386333, 0.44950193167), - (0.20063838363, -0.023084819317, 0.42436161637, 0.64808481932), - (-0.023101598024, 0.20064398646, 0.64810156822, 0.42435601354), - (0.076484903693, 0.076484903693, 0.54851508141, 0.54851508141), - (0.11874999106, 0.24375002086, 0.50625002384, 0.63124996424), - (0.17549805343, 0.16349616647, 0.44950193167, 0.71150386333), - (0.038496106863, 0.30049806833, 0.58650386333, 0.57450193167), - (0.20063838363, 0.10191518068, 0.42436161637, 0.77308481932), - (-0.023101598024, 0.32564398646, 0.64810156822, 0.54935604334), - (0.076484903693, 0.20148490369, 0.54851508141, 0.67351508141), - (0.11874999106, 0.36875003576, 0.50625002384, 0.75624996424), - (0.17549805343, 0.28849616647, 0.44950193167, 0.83650386333), - (0.038496106863, 0.42549806833, 0.58650386333, 0.69950193167), - (0.20063838363, 0.22691518068, 0.42436161637, 0.89808481932), - (-0.023101598024, 0.45064398646, 0.64810156822, 0.67435604334), - (0.076484903693, 0.32648491859, 0.54851508141, 0.79851508141), - (0.11874999106, 0.49375003576, 0.50625002384, 0.88124996424), - (0.17549805343, 0.41349616647, 0.44950193167, 0.96150386333), - (0.038496106863, 0.55049806833, 0.58650386333, 0.82450193167), - (0.20063838363, 0.35191518068, 0.42436161637, 1.0230848789), - (-0.023101598024, 0.57564395666, 0.64810156822, 0.79935604334), - (0.076484903693, 0.45148491859, 0.54851508141, 0.92351508141), - (0.11874999106, 0.61875003576, 0.50625002384, 1.0062500238), - (0.17549805343, 0.53849613667, 0.44950193167, 1.0865038633), - (0.038496106863, 0.67549806833, 0.58650386333, 0.94950193167), - (0.20063838363, 0.47691518068, 0.42436161637, 1.1480848789), - (-0.023101598024, 0.70064395666, 0.64810156822, 0.92435604334), - (0.076484903693, 0.57648491859, 0.54851508141, 1.0485150814), - (0.11874999106, 0.74375003576, 0.50625002384, 1.1312500238), - (0.17549805343, 0.66349613667, 0.44950193167, 1.2115038633), - (0.038496106863, 0.80049806833, 0.58650386333, 1.0745018721), - (0.20063838363, 0.60191518068, 0.42436161637, 1.2730848789), - (-0.023101598024, 0.82564395666, 0.64810156822, 1.0493559837), - (0.076484903693, 0.70148491859, 0.54851508141, 1.1735150814), - (0.24374999106, -0.13124997914, 0.63125002384, 0.25624996424), - (0.30049806833, -0.21150383353, 0.57450193167, 0.33650383353), - (0.16349610686, -0.074501916766, 0.71150386333, 0.19950191677), - (0.32563838363, -0.27308481932, 0.54936158657, 0.39808481932), - (0.10189840198, -0.049356020987, 0.77310156822, 0.17435601354), - (0.20148490369, -0.17351509631, 0.67351508141, 0.29851508141), - (0.24374999106, -0.0062499791384, 0.63125002384, 0.38124996424), - (0.30049806833, -0.086503833532, 0.57450193167, 0.46150383353), - (0.16349610686, 0.050498083234, 0.71150386333, 0.32450193167), - (0.32563838363, -0.14808481932, 0.54936158657, 0.52308481932), - (0.10189840198, 0.075643979013, 0.77310156822, 0.29935601354), - (0.20148490369, -0.048515096307, 0.67351508141, 0.42351508141), - (0.24374999106, 0.11875002086, 0.63125002384, 0.50624996424), - (0.30049806833, 0.038496166468, 0.57450193167, 0.58650386333), - (0.16349610686, 0.17549808323, 0.71150386333, 0.44950193167), - (0.32563838363, -0.023084819317, 0.54936158657, 0.64808481932), - (0.10189840198, 0.20064398646, 0.77310156822, 0.42435601354), - (0.20148490369, 0.076484903693, 0.67351508141, 0.54851508141), - (0.24374999106, 0.24375002086, 0.63125002384, 0.63124996424), - (0.30049806833, 0.16349616647, 0.57450193167, 0.71150386333), - (0.16349610686, 0.30049806833, 0.71150386333, 0.57450193167), - (0.32563838363, 0.10191518068, 0.54936158657, 0.77308481932), - (0.10189840198, 0.32564398646, 0.77310156822, 0.54935604334), - (0.20148490369, 0.20148490369, 0.67351508141, 0.67351508141), - (0.24374999106, 0.36875003576, 0.63125002384, 0.75624996424), - (0.30049806833, 0.28849616647, 0.57450193167, 0.83650386333), - (0.16349610686, 0.42549806833, 0.71150386333, 0.69950193167), - (0.32563838363, 0.22691518068, 0.54936158657, 0.89808481932), - (0.10189840198, 0.45064398646, 0.77310156822, 0.67435604334), - (0.20148490369, 0.32648491859, 0.67351508141, 0.79851508141), - (0.24374999106, 0.49375003576, 0.63125002384, 0.88124996424), - (0.30049806833, 0.41349616647, 0.57450193167, 0.96150386333), - (0.16349610686, 0.55049806833, 0.71150386333, 0.82450193167), - (0.32563838363, 0.35191518068, 0.54936158657, 1.0230848789), - (0.10189840198, 0.57564395666, 0.77310156822, 0.79935604334), - (0.20148490369, 0.45148491859, 0.67351508141, 0.92351508141), - (0.24374999106, 0.61875003576, 0.63125002384, 1.0062500238), - (0.30049806833, 0.53849613667, 0.57450193167, 1.0865038633), - (0.16349610686, 0.67549806833, 0.71150386333, 0.94950193167), - (0.32563838363, 0.47691518068, 0.54936158657, 1.1480848789), - (0.10189840198, 0.70064395666, 0.77310156822, 0.92435604334), - (0.20148490369, 0.57648491859, 0.67351508141, 1.0485150814), - (0.24374999106, 0.74375003576, 0.63125002384, 1.1312500238), - (0.30049806833, 0.66349613667, 0.57450193167, 1.2115038633), - (0.16349610686, 0.80049806833, 0.71150386333, 1.0745018721), - (0.32563838363, 0.60191518068, 0.54936158657, 1.2730848789), - (0.10189840198, 0.82564395666, 0.77310156822, 1.0493559837), - (0.20148490369, 0.70148491859, 0.67351508141, 1.1735150814), - (0.36874997616, -0.13124997914, 0.75625002384, 0.25624996424), - (0.42549806833, -0.21150383353, 0.69950193167, 0.33650383353), - (0.28849610686, -0.074501916766, 0.83650386333, 0.19950191677), - (0.45063838363, -0.27308481932, 0.67436158657, 0.39808481932), - (0.22689840198, -0.049356020987, 0.89810156822, 0.17435601354), - (0.32648491859, -0.17351509631, 0.79851508141, 0.29851508141), - (0.36874997616, -0.0062499791384, 0.75625002384, 0.38124996424), - (0.42549806833, -0.086503833532, 0.69950193167, 0.46150383353), - (0.28849610686, 0.050498083234, 0.83650386333, 0.32450193167), - (0.45063838363, -0.14808481932, 0.67436158657, 0.52308481932), - (0.22689840198, 0.075643979013, 0.89810156822, 0.29935601354), - (0.32648491859, -0.048515096307, 0.79851508141, 0.42351508141), - (0.36874997616, 0.11875002086, 0.75625002384, 0.50624996424), - (0.42549806833, 0.038496166468, 0.69950193167, 0.58650386333), - (0.28849610686, 0.17549808323, 0.83650386333, 0.44950193167), - (0.45063838363, -0.023084819317, 0.67436158657, 0.64808481932), - (0.22689840198, 0.20064398646, 0.89810156822, 0.42435601354), - (0.32648491859, 0.076484903693, 0.79851508141, 0.54851508141), - (0.36874997616, 0.24375002086, 0.75625002384, 0.63124996424), - (0.42549806833, 0.16349616647, 0.69950193167, 0.71150386333), - (0.28849610686, 0.30049806833, 0.83650386333, 0.57450193167), - (0.45063838363, 0.10191518068, 0.67436158657, 0.77308481932), - (0.22689840198, 0.32564398646, 0.89810156822, 0.54935604334), - (0.32648491859, 0.20148490369, 0.79851508141, 0.67351508141), - (0.36874997616, 0.36875003576, 0.75625002384, 0.75624996424), - (0.42549806833, 0.28849616647, 0.69950193167, 0.83650386333), - (0.28849610686, 0.42549806833, 0.83650386333, 0.69950193167), - (0.45063838363, 0.22691518068, 0.67436158657, 0.89808481932), - (0.22689840198, 0.45064398646, 0.89810156822, 0.67435604334), - (0.32648491859, 0.32648491859, 0.79851508141, 0.79851508141), - (0.36874997616, 0.49375003576, 0.75625002384, 0.88124996424), - (0.42549806833, 0.41349616647, 0.69950193167, 0.96150386333), - (0.28849610686, 0.55049806833, 0.83650386333, 0.82450193167), - (0.45063838363, 0.35191518068, 0.67436158657, 1.0230848789), - (0.22689840198, 0.57564395666, 0.89810156822, 0.79935604334), - (0.32648491859, 0.45148491859, 0.79851508141, 0.92351508141), - (0.36874997616, 0.61875003576, 0.75625002384, 1.0062500238), - (0.42549806833, 0.53849613667, 0.69950193167, 1.0865038633), - (0.28849610686, 0.67549806833, 0.83650386333, 0.94950193167), - (0.45063838363, 0.47691518068, 0.67436158657, 1.1480848789), - (0.22689840198, 0.70064395666, 0.89810156822, 0.92435604334), - (0.32648491859, 0.57648491859, 0.79851508141, 1.0485150814), - (0.36874997616, 0.74375003576, 0.75625002384, 1.1312500238), - (0.42549806833, 0.66349613667, 0.69950193167, 1.2115038633), - (0.28849610686, 0.80049806833, 0.83650386333, 1.0745018721), - (0.45063838363, 0.60191518068, 0.67436158657, 1.2730848789), - (0.22689840198, 0.82564395666, 0.89810156822, 1.0493559837), - (0.32648491859, 0.70148491859, 0.79851508141, 1.1735150814), - (0.49374997616, -0.13124997914, 0.88125002384, 0.25624996424), - (0.55049806833, -0.21150383353, 0.82450193167, 0.33650383353), - (0.41349610686, -0.074501916766, 0.96150386333, 0.19950191677), - (0.57563841343, -0.27308481932, 0.79936158657, 0.39808481932), - (0.35189840198, -0.049356020987, 1.0231015682, 0.17435601354), - (0.45148491859, -0.17351509631, 0.92351508141, 0.29851508141), - (0.49374997616, -0.0062499791384, 0.88125002384, 0.38124996424), - (0.55049806833, -0.086503833532, 0.82450193167, 0.46150383353), - (0.41349610686, 0.050498083234, 0.96150386333, 0.32450193167), - (0.57563841343, -0.14808481932, 0.79936158657, 0.52308481932), - (0.35189840198, 0.075643979013, 1.0231015682, 0.29935601354), - (0.45148491859, -0.048515096307, 0.92351508141, 0.42351508141), - (0.49374997616, 0.11875002086, 0.88125002384, 0.50624996424), - (0.55049806833, 0.038496166468, 0.82450193167, 0.58650386333), - (0.41349610686, 0.17549808323, 0.96150386333, 0.44950193167), - (0.57563841343, -0.023084819317, 0.79936158657, 0.64808481932), - (0.35189840198, 0.20064398646, 1.0231015682, 0.42435601354), - (0.45148491859, 0.076484903693, 0.92351508141, 0.54851508141), - (0.49374997616, 0.24375002086, 0.88125002384, 0.63124996424), - (0.55049806833, 0.16349616647, 0.82450193167, 0.71150386333), - (0.41349610686, 0.30049806833, 0.96150386333, 0.57450193167), - (0.57563841343, 0.10191518068, 0.79936158657, 0.77308481932), - (0.35189840198, 0.32564398646, 1.0231015682, 0.54935604334), - (0.45148491859, 0.20148490369, 0.92351508141, 0.67351508141), - (0.49374997616, 0.36875003576, 0.88125002384, 0.75624996424), - (0.55049806833, 0.28849616647, 0.82450193167, 0.83650386333), - (0.41349610686, 0.42549806833, 0.96150386333, 0.69950193167), - (0.57563841343, 0.22691518068, 0.79936158657, 0.89808481932), - (0.35189840198, 0.45064398646, 1.0231015682, 0.67435604334), - (0.45148491859, 0.32648491859, 0.92351508141, 0.79851508141), - (0.49374997616, 0.49375003576, 0.88125002384, 0.88124996424), - (0.55049806833, 0.41349616647, 0.82450193167, 0.96150386333), - (0.41349610686, 0.55049806833, 0.96150386333, 0.82450193167), - (0.57563841343, 0.35191518068, 0.79936158657, 1.0230848789), - (0.35189840198, 0.57564395666, 1.0231015682, 0.79935604334), - (0.45148491859, 0.45148491859, 0.92351508141, 0.92351508141), - (0.49374997616, 0.61875003576, 0.88125002384, 1.0062500238), - (0.55049806833, 0.53849613667, 0.82450193167, 1.0865038633), - (0.41349610686, 0.67549806833, 0.96150386333, 0.94950193167), - (0.57563841343, 0.47691518068, 0.79936158657, 1.1480848789), - (0.35189840198, 0.70064395666, 1.0231015682, 0.92435604334), - (0.45148491859, 0.57648491859, 0.92351508141, 1.0485150814), - (0.49374997616, 0.74375003576, 0.88125002384, 1.1312500238), - (0.55049806833, 0.66349613667, 0.82450193167, 1.2115038633), - (0.41349610686, 0.80049806833, 0.96150386333, 1.0745018721), - (0.57563841343, 0.60191518068, 0.79936158657, 1.2730848789), - (0.35189840198, 0.82564395666, 1.0231015682, 1.0493559837), - (0.45148491859, 0.70148491859, 0.92351508141, 1.1735150814), - (0.61874997616, -0.13124997914, 1.0062500238, 0.25624996424), - (0.67549806833, -0.21150383353, 0.94950193167, 0.33650383353), - (0.53849613667, -0.074501916766, 1.0865038633, 0.19950191677), - (0.70063841343, -0.27308481932, 0.92436158657, 0.39808481932), - (0.47689840198, -0.049356020987, 1.1481015682, 0.17435601354), - (0.57648491859, -0.17351509631, 1.0485150814, 0.29851508141), - (0.61874997616, -0.0062499791384, 1.0062500238, 0.38124996424), - (0.67549806833, -0.086503833532, 0.94950193167, 0.46150383353), - (0.53849613667, 0.050498083234, 1.0865038633, 0.32450193167), - (0.70063841343, -0.14808481932, 0.92436158657, 0.52308481932), - (0.47689840198, 0.075643979013, 1.1481015682, 0.29935601354), - (0.57648491859, -0.048515096307, 1.0485150814, 0.42351508141), - (0.61874997616, 0.11875002086, 1.0062500238, 0.50624996424), - (0.67549806833, 0.038496166468, 0.94950193167, 0.58650386333), - (0.53849613667, 0.17549808323, 1.0865038633, 0.44950193167), - (0.70063841343, -0.023084819317, 0.92436158657, 0.64808481932), - (0.47689840198, 0.20064398646, 1.1481015682, 0.42435601354), - (0.57648491859, 0.076484903693, 1.0485150814, 0.54851508141), - (0.61874997616, 0.24375002086, 1.0062500238, 0.63124996424), - (0.67549806833, 0.16349616647, 0.94950193167, 0.71150386333), - (0.53849613667, 0.30049806833, 1.0865038633, 0.57450193167), - (0.70063841343, 0.10191518068, 0.92436158657, 0.77308481932), - (0.47689840198, 0.32564398646, 1.1481015682, 0.54935604334), - (0.57648491859, 0.20148490369, 1.0485150814, 0.67351508141), - (0.61874997616, 0.36875003576, 1.0062500238, 0.75624996424), - (0.67549806833, 0.28849616647, 0.94950193167, 0.83650386333), - (0.53849613667, 0.42549806833, 1.0865038633, 0.69950193167), - (0.70063841343, 0.22691518068, 0.92436158657, 0.89808481932), - (0.47689840198, 0.45064398646, 1.1481015682, 0.67435604334), - (0.57648491859, 0.32648491859, 1.0485150814, 0.79851508141), - (0.61874997616, 0.49375003576, 1.0062500238, 0.88124996424), - (0.67549806833, 0.41349616647, 0.94950193167, 0.96150386333), - (0.53849613667, 0.55049806833, 1.0865038633, 0.82450193167), - (0.70063841343, 0.35191518068, 0.92436158657, 1.0230848789), - (0.47689840198, 0.57564395666, 1.1481015682, 0.79935604334), - (0.57648491859, 0.45148491859, 1.0485150814, 0.92351508141), - (0.61874997616, 0.61875003576, 1.0062500238, 1.0062500238), - (0.67549806833, 0.53849613667, 0.94950193167, 1.0865038633), - (0.53849613667, 0.67549806833, 1.0865038633, 0.94950193167), - (0.70063841343, 0.47691518068, 0.92436158657, 1.1480848789), - (0.47689840198, 0.70064395666, 1.1481015682, 0.92435604334), - (0.57648491859, 0.57648491859, 1.0485150814, 1.0485150814), - (0.61874997616, 0.74375003576, 1.0062500238, 1.1312500238), - (0.67549806833, 0.66349613667, 0.94950193167, 1.2115038633), - (0.53849613667, 0.80049806833, 1.0865038633, 1.0745018721), - (0.70063841343, 0.60191518068, 0.92436158657, 1.2730848789), - (0.47689840198, 0.82564395666, 1.1481015682, 1.0493559837), - (0.57648491859, 0.70148491859, 1.0485150814, 1.1735150814), - (0.74374997616, -0.13124997914, 1.1312500238, 0.25624996424), - (0.80049806833, -0.21150383353, 1.0745019913, 0.33650383353), - (0.66349613667, -0.074501916766, 1.2115038633, 0.19950191677), - (0.82563841343, -0.27308481932, 1.0493615866, 0.39808481932), - (0.60189843178, -0.049356020987, 1.2731015682, 0.17435601354), - (0.70148491859, -0.17351509631, 1.1735150814, 0.29851508141), - (0.74374997616, -0.0062499791384, 1.1312500238, 0.38124996424), - (0.80049806833, -0.086503833532, 1.0745019913, 0.46150383353), - (0.66349613667, 0.050498083234, 1.2115038633, 0.32450193167), - (0.82563841343, -0.14808481932, 1.0493615866, 0.52308481932), - (0.60189843178, 0.075643979013, 1.2731015682, 0.29935601354), - (0.70148491859, -0.048515096307, 1.1735150814, 0.42351508141), - (0.74374997616, 0.11875002086, 1.1312500238, 0.50624996424), - (0.80049806833, 0.038496166468, 1.0745019913, 0.58650386333), - (0.66349613667, 0.17549808323, 1.2115038633, 0.44950193167), - (0.82563841343, -0.023084819317, 1.0493615866, 0.64808481932), - (0.60189843178, 0.20064398646, 1.2731015682, 0.42435601354), - (0.70148491859, 0.076484903693, 1.1735150814, 0.54851508141), - (0.74374997616, 0.24375002086, 1.1312500238, 0.63124996424), - (0.80049806833, 0.16349616647, 1.0745019913, 0.71150386333), - (0.66349613667, 0.30049806833, 1.2115038633, 0.57450193167), - (0.82563841343, 0.10191518068, 1.0493615866, 0.77308481932), - (0.60189843178, 0.32564398646, 1.2731015682, 0.54935604334), - (0.70148491859, 0.20148490369, 1.1735150814, 0.67351508141), - (0.74374997616, 0.36875003576, 1.1312500238, 0.75624996424), - (0.80049806833, 0.28849616647, 1.0745019913, 0.83650386333), - (0.66349613667, 0.42549806833, 1.2115038633, 0.69950193167), - (0.82563841343, 0.22691518068, 1.0493615866, 0.89808481932), - (0.60189843178, 0.45064398646, 1.2731015682, 0.67435604334), - (0.70148491859, 0.32648491859, 1.1735150814, 0.79851508141), - (0.74374997616, 0.49375003576, 1.1312500238, 0.88124996424), - (0.80049806833, 0.41349616647, 1.0745019913, 0.96150386333), - (0.66349613667, 0.55049806833, 1.2115038633, 0.82450193167), - (0.82563841343, 0.35191518068, 1.0493615866, 1.0230848789), - (0.60189843178, 0.57564395666, 1.2731015682, 0.79935604334), - (0.70148491859, 0.45148491859, 1.1735150814, 0.92351508141), - (0.74374997616, 0.61875003576, 1.1312500238, 1.0062500238), - (0.80049806833, 0.53849613667, 1.0745019913, 1.0865038633), - (0.66349613667, 0.67549806833, 1.2115038633, 0.94950193167), - (0.82563841343, 0.47691518068, 1.0493615866, 1.1480848789), - (0.60189843178, 0.70064395666, 1.2731015682, 0.92435604334), - (0.70148491859, 0.57648491859, 1.1735150814, 1.0485150814), - (0.74374997616, 0.74375003576, 1.1312500238, 1.1312500238), - (0.80049806833, 0.66349613667, 1.0745019913, 1.2115038633), - (0.66349613667, 0.80049806833, 1.2115038633, 1.0745018721), - (0.82563841343, 0.60191518068, 1.0493615866, 1.2730848789), - (0.60189843178, 0.82564395666, 1.2731015682, 1.0493559837), - (0.70148491859, 0.70148491859, 1.1735150814, 1.1735150814), - (-0.16250002384, -0.16249996424, 0.41250002384, 0.41249996424), - (-0.078293219209, -0.28158634901, 0.32829320431, 0.53158634901), - (-0.28158643842, -0.078293174505, 0.53158640862, 0.32829317451), - (-0.040988206863, -0.37296459079, 0.29098820686, 0.62296462059), - (-0.37298947573, -0.040979906917, 0.62298947573, 0.29097992182), - (-0.20607307553, -0.20607307553, 0.45607307553, 0.45607307553), - (-0.16250002384, 0.087500035763, 0.41250002384, 0.66249996424), - (-0.078293219209, -0.03158634901, 0.32829320431, 0.78158634901), - (-0.28158643842, 0.17170682549, 0.53158640862, 0.57829320431), - (-0.040988206863, -0.12296459079, 0.29098820686, 0.87296462059), - (-0.37298947573, 0.20902009308, 0.62298947573, 0.54097992182), - (-0.20607307553, 0.043926924467, 0.45607307553, 0.70607304573), - (-0.16250002384, 0.33750003576, 0.41250002384, 0.91249996424), - (-0.078293219209, 0.21841365099, 0.32829320431, 1.0315864086), - (-0.28158643842, 0.42170682549, 0.53158640862, 0.82829320431), - (-0.040988206863, 0.12703540921, 0.29098820686, 1.1229646206), - (-0.37298947573, 0.45902007818, 0.62298947573, 0.79097992182), - (-0.20607307553, 0.29392692447, 0.45607307553, 0.95607304573), - (-0.16250002384, 0.58750003576, 0.41250002384, 1.1624999046), - (-0.078293219209, 0.46841365099, 0.32829320431, 1.2815864086), - (-0.28158643842, 0.67170679569, 0.53158640862, 1.0782932043), - (-0.040988206863, 0.37703540921, 0.29098820686, 1.3729646206), - (-0.37298947573, 0.70902007818, 0.62298947573, 1.0409798622), - (-0.20607307553, 0.54392695427, 0.45607307553, 1.2060730457), - (0.087499976158, -0.16249996424, 0.66250002384, 0.41249996424), - (0.17170678079, -0.28158634901, 0.57829320431, 0.53158634901), - (-0.031586438417, -0.078293174505, 0.78158640862, 0.32829317451), - (0.20901179314, -0.37296459079, 0.54098820686, 0.62296462059), - (-0.12298947573, -0.040979906917, 0.87298947573, 0.29097992182), - (0.043926924467, -0.20607307553, 0.70607304573, 0.45607307553), - (0.087499976158, 0.087500035763, 0.66250002384, 0.66249996424), - (0.17170678079, -0.03158634901, 0.57829320431, 0.78158634901), - (-0.031586438417, 0.17170682549, 0.78158640862, 0.57829320431), - (0.20901179314, -0.12296459079, 0.54098820686, 0.87296462059), - (-0.12298947573, 0.20902009308, 0.87298947573, 0.54097992182), - (0.043926924467, 0.043926924467, 0.70607304573, 0.70607304573), - (0.087499976158, 0.33750003576, 0.66250002384, 0.91249996424), - (0.17170678079, 0.21841365099, 0.57829320431, 1.0315864086), - (-0.031586438417, 0.42170682549, 0.78158640862, 0.82829320431), - (0.20901179314, 0.12703540921, 0.54098820686, 1.1229646206), - (-0.12298947573, 0.45902007818, 0.87298947573, 0.79097992182), - (0.043926924467, 0.29392692447, 0.70607304573, 0.95607304573), - (0.087499976158, 0.58750003576, 0.66250002384, 1.1624999046), - (0.17170678079, 0.46841365099, 0.57829320431, 1.2815864086), - (-0.031586438417, 0.67170679569, 0.78158640862, 1.0782932043), - (0.20901179314, 0.37703540921, 0.54098820686, 1.3729646206), - (-0.12298947573, 0.70902007818, 0.87298947573, 1.0409798622), - (0.043926924467, 0.54392695427, 0.70607304573, 1.2060730457), - (0.33749997616, -0.16249996424, 0.91250002384, 0.41249996424), - (0.42170679569, -0.28158634901, 0.82829320431, 0.53158634901), - (0.21841356158, -0.078293174505, 1.0315864086, 0.32829317451), - (0.45901179314, -0.37296459079, 0.79098820686, 0.62296462059), - (0.12701052427, -0.040979906917, 1.1229894161, 0.29097992182), - (0.29392692447, -0.20607307553, 0.95607304573, 0.45607307553), - (0.33749997616, 0.087500035763, 0.91250002384, 0.66249996424), - (0.42170679569, -0.03158634901, 0.82829320431, 0.78158634901), - (0.21841356158, 0.17170682549, 1.0315864086, 0.57829320431), - (0.45901179314, -0.12296459079, 0.79098820686, 0.87296462059), - (0.12701052427, 0.20902009308, 1.1229894161, 0.54097992182), - (0.29392692447, 0.043926924467, 0.95607304573, 0.70607304573), - (0.33749997616, 0.33750003576, 0.91250002384, 0.91249996424), - (0.42170679569, 0.21841365099, 0.82829320431, 1.0315864086), - (0.21841356158, 0.42170682549, 1.0315864086, 0.82829320431), - (0.45901179314, 0.12703540921, 0.79098820686, 1.1229646206), - (0.12701052427, 0.45902007818, 1.1229894161, 0.79097992182), - (0.29392692447, 0.29392692447, 0.95607304573, 0.95607304573), - (0.33749997616, 0.58750003576, 0.91250002384, 1.1624999046), - (0.42170679569, 0.46841365099, 0.82829320431, 1.2815864086), - (0.21841356158, 0.67170679569, 1.0315864086, 1.0782932043), - (0.45901179314, 0.37703540921, 0.79098820686, 1.3729646206), - (0.12701052427, 0.70902007818, 1.1229894161, 1.0409798622), - (0.29392692447, 0.54392695427, 0.95607304573, 1.2060730457), - (0.58749997616, -0.16249996424, 1.1625000238, 0.41249996424), - (0.67170679569, -0.28158634901, 1.0782932043, 0.53158634901), - (0.46841356158, -0.078293174505, 1.2815864086, 0.32829317451), - (0.70901179314, -0.37296459079, 1.0409882069, 0.62296462059), - (0.37701052427, -0.040979906917, 1.3729894161, 0.29097992182), - (0.54392695427, -0.20607307553, 1.2060730457, 0.45607307553), - (0.58749997616, 0.087500035763, 1.1625000238, 0.66249996424), - (0.67170679569, -0.03158634901, 1.0782932043, 0.78158634901), - (0.46841356158, 0.17170682549, 1.2815864086, 0.57829320431), - (0.70901179314, -0.12296459079, 1.0409882069, 0.87296462059), - (0.37701052427, 0.20902009308, 1.3729894161, 0.54097992182), - (0.54392695427, 0.043926924467, 1.2060730457, 0.70607304573), - (0.58749997616, 0.33750003576, 1.1625000238, 0.91249996424), - (0.67170679569, 0.21841365099, 1.0782932043, 1.0315864086), - (0.46841356158, 0.42170682549, 1.2815864086, 0.82829320431), - (0.70901179314, 0.12703540921, 1.0409882069, 1.1229646206), - (0.37701052427, 0.45902007818, 1.3729894161, 0.79097992182), - (0.54392695427, 0.29392692447, 1.2060730457, 0.95607304573), - (0.58749997616, 0.58750003576, 1.1625000238, 1.1624999046), - (0.67170679569, 0.46841365099, 1.0782932043, 1.2815864086), - (0.46841356158, 0.67170679569, 1.2815864086, 1.0782932043), - (0.70901179314, 0.37703540921, 1.0409882069, 1.3729646206), - (0.37701052427, 0.70902007818, 1.3729894161, 1.0409798622), - (0.54392695427, 0.54392695427, 1.2060730457, 1.2060730457), - (-0.13125002384, -0.13124996424, 0.63125002384, 0.63124996424), - (-0.019584476948, -0.28916883469, 0.51958447695, 0.78916883469), - (-0.2891689539, -0.019584417343, 0.7891689539, 0.51958441734), - (0.029885202646, -0.41034436226, 0.47011479735, 0.91034436226), - (-0.41037738323, 0.029896214604, 0.91037738323, 0.4701038003), - (-0.17555111647, -0.17555111647, 0.67555111647, 0.67555111647), - (-0.13125002384, 0.36875003576, 0.63125002384, 1.1312499046), - (-0.019584476948, 0.21083116531, 0.51958447695, 1.2891688347), - (-0.2891689539, 0.48041558266, 0.7891689539, 1.0195844173), - (0.029885202646, 0.089655637741, 0.47011479735, 1.4103443623), - (-0.41037738323, 0.5298961997, 0.91037738323, 0.9701038003), - (-0.17555111647, 0.32444888353, 0.67555111647, 1.1755511761), - (0.36874997616, -0.13124996424, 1.1312500238, 0.63124996424), - (0.48041552305, -0.28916883469, 1.0195844173, 0.78916883469), - (0.2108310461, -0.019584417343, 1.2891689539, 0.51958441734), - (0.52988517284, -0.41034436226, 0.97011482716, 0.91034436226), - (0.089622616768, 0.029896214604, 1.4103773832, 0.4701038003), - (0.32444888353, -0.17555111647, 1.1755511761, 0.67555111647), - (0.36874997616, 0.36875003576, 1.1312500238, 1.1312499046), - (0.48041552305, 0.21083116531, 1.0195844173, 1.2891688347), - (0.2108310461, 0.48041558266, 1.2891689539, 1.0195844173), - (0.52988517284, 0.089655637741, 0.97011482716, 1.4103443623), - (0.089622616768, 0.5298961997, 1.4103773832, 0.9701038003), - (0.32444888353, 0.32444888353, 1.1755511761, 1.1755511761), - (0.024999976158, 0.025000035763, 0.97500002384, 0.97499996424), - (0.16412425041, -0.17175137997, 0.83587574959, 1.17175138), - (-0.17175149918, 0.16412431002, 1.1717514992, 0.83587568998), - (0.22575861216, -0.32272410393, 0.77424138784, 1.3227241039), - (-0.32276523113, 0.22577232122, 1.3227652311, 0.77422767878), - (0.012660294771, 0.012660294771, 0.98733973503, 0.98733973503), -) diff --git a/src/aiy/vision/models/utils.py b/src/aiy/vision/models/utils.py deleted file mode 100644 index 007705c5..00000000 --- a/src/aiy/vision/models/utils.py +++ /dev/null @@ -1,9 +0,0 @@ -"""Utility to load compute graphs from diffrent sources.""" - -import os - - -def load_compute_graph(name): - path = os.environ.get('VISION_BONNET_MODELS_PATH', '/opt/aiy/models') - with open(os.path.join(path, name), 'rb') as f: - return f.read() diff --git a/src/aiy/vision/pins.py b/src/aiy/vision/pins.py deleted file mode 100644 index da2b7937..00000000 --- a/src/aiy/vision/pins.py +++ /dev/null @@ -1,673 +0,0 @@ -"""Pin definitions for use with gpiozero devices. - -Defines pin objects, and overrides the pin factory used by gpiozero devices to -support the pins routed through the hat. Should not disrupt usage of other pins. -""" - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -import os -from collections import namedtuple -from copy import deepcopy -from os import listdir -import time -from gpiozero import Device -from gpiozero import Factory -from gpiozero import Pin -from gpiozero.exc import GPIOPinInUse -from gpiozero.exc import InputDeviceError -from gpiozero.exc import PinFixedPull -from gpiozero.exc import PinInvalidBounce -from gpiozero.exc import PinInvalidEdges -from gpiozero.exc import PinPWMUnsupported -from gpiozero.exc import PinSetInput -from gpiozero.exc import PinUnsupported -from gpiozero.threads import GPIOThread - - -def _detect_gpio_offset(module_path): - for folder in listdir(module_path): - try: - with open('%s/%s/base' % (module_path, folder), 'r') as offset: - return int(offset.read()) - except IOError: - pass - return None - - -_FsNodeSpec = namedtuple('_FsNodeSpec', ['pin', 'name']) - -VISIONBONNET_PRODUCT = r"AIY VisionBonnet" -VOICEBONNET_PROUDCT = r"AIY VoiceBonnet" - -MCU_I2C_ADDRESS_DICT = { - VISIONBONNET_PRODUCT: 0x51, - VOICEBONNET_PROUDCT: 0x52 -} - -HAT_PRODUCT_NAME_PATH = "/sys/firmware/devicetree/base/hat/product" - - -def _get_product_name(): - if not os.path.exists(HAT_PRODUCT_NAME_PATH): - raise IOError('Hat not found.') - with open(HAT_PRODUCT_NAME_PATH, "r") as f: - hat_product_name = str(f.read()).strip("\x00").strip() - return hat_product_name - - -def _get_i2c_address(): - mcu_i2c_address = MCU_I2C_ADDRESS_DICT.get(_get_product_name()) - if mcu_i2c_address is None: - raise ValueError('I2C address undetermined.') - return mcu_i2c_address - - -class GpioSpec(_FsNodeSpec): - _MODULE_PATH = '/sys/bus/i2c/drivers/aiy-io-i2c/1-00%2X/gpio-aiy-io/gpio' % _get_i2c_address() - _PIN_OFFSET = _detect_gpio_offset(_MODULE_PATH) - - def __new__(cls, pin, name): - return super(GpioSpec, cls).__new__(cls, GpioSpec._PIN_OFFSET + pin, name) - - def __str__(self): - return 'gpio %s (%d)' % (self.name, self.pin - self._PIN_OFFSET) - - -class PwmSpec(_FsNodeSpec): - - def __str__(self): - return 'pwm %d' % self.pin - - -AIYPinSpec = namedtuple('AIYPinSpec', ['gpio_spec', 'pwm_spec']) - -PIN_A = AIYPinSpec(GpioSpec(2, 'AIY_USER0'), PwmSpec(0, 'pwm0')) -PIN_B = AIYPinSpec(GpioSpec(3, 'AIY_USER1'), PwmSpec(1, 'pwm1')) -PIN_C = AIYPinSpec(GpioSpec(8, 'AIY_USER2'), PwmSpec(2, 'pwm2')) -PIN_D = AIYPinSpec(GpioSpec(9, 'AIY_USER3'), PwmSpec(3, 'pwm3')) -LED_1 = AIYPinSpec(GpioSpec(13, 'AIY_LED0'), None) -LED_2 = AIYPinSpec(GpioSpec(14, 'AIY_LED1'), None) - -BUZZER_GPIO_PIN = 22 -BUTTON_GPIO_PIN = 23 - -_NS_PER_SECOND = 1000000000 - - -class SysFsPin(object): - """Generic SysFsPin which implements generic SysFs driver functionality.""" - - def __init__(self, spec, fs_root): - self._pin = spec.pin - self._name = spec.name - self._fs_root = fs_root - # Ensure things start out unexported. - try: - self.unexport() - except IOError: - pass - - def set_function(self, function): - raise NotImplementedError('Setting function not supported') - - def get_function(self): - raise NotImplementedError('Getting function not supported') - - def export(self): - try: - with open(self.root_path('export'), 'w') as export: - export.write('%d' % self._pin) - except IOError: - raise GPIOPinInUse('Pin already in use') - - def unexport(self): - with open(self.root_path('unexport'), 'w') as unexport: - unexport.write('%d' % self._pin) - - def open(self): - self.export() - - def close(self): - self.unexport() - - def wait_for_permissions(self, prop): - """Wait for write permissions on the given property. - - We must wait because the the file system needs to grant permissions for the - newly created node.""" - while True: - try: - with open(self.property_path(prop), 'w'): - pass - return - except IOError: - time.sleep(.01) - - def get_value(self): - raise NotImplementedError('Value getting not implemented') - - def set_value(self, value): - raise NotImplementedError('Value setting not implemented') - - def write_property(self, prop, value): - """Writes the given sysfs node property to the pin.""" - with open(self.property_path(prop), 'w') as node: - node.write(value) - - def read_property(self, prop): - """Reads the given sysfs node property from the pin.""" - with open(self.property_path(prop), 'r') as node: - return node.read() - - def root_path(self, node): - return '%s/%s' % (self._fs_root, node) - - def property_path(self, prop): - return '%s/%s/%s' % (self._fs_root, self._name, prop) - - -class SysFsGpioPin(SysFsPin): - """SysFs support for GPIO pins. - - Supports the SysFs node for GPIO control. - """ - _FS_ROOT = '/sys/class/gpio' - - def __init__(self, spec): - super(SysFsGpioPin, self).__init__(spec, self._FS_ROOT) - if not isinstance(spec, GpioSpec): - raise TypeError('Pin specification not compatible with SysFS GPIO') - self._spec = spec - self._out = False - self._value = None - - def _get_direction(self): - return self.read_property('direction') - - def _set_direction(self, direction): - if direction not in ('in', 'out'): - raise ValueError('Direction must be either in or out') - self.write_property('direction', direction) - - def _get_value(self): - return self.read_property('value') - - def _set_value(self, value): - self.write_property('value', value) - - def _get_active_low(self): - return self.read_property('active_low') - - def _set_active_low(self, active_low): - self.write_property('active_low', '1' if active_low else '0') - - def set_function(self, function): - if function == 'input': - self._set_direction('in') - self._out = False - elif function == 'output': - self._set_direction('out') - self._out = True - else: - raise ValueError('pin function must be either input or output') - - def get_function(self): - direction = self._get_direction() - if direction == 'input': - return 'in' - if direction == 'output': - return 'out' - - def set_value(self, value): - if not self._out: - raise PinSetInput('Pin is not open for output') - self._set_value('1' if value else '0') - self._value = value - - def get_value(self): - if self._out: - return self._value - return bool(int(self._get_value())) - - def open(self): - super(SysFsGpioPin, self).open() - self.wait_for_permissions('active_low') - self.wait_for_permissions('direction') - # GPIO pins on the hat seem to be inverted by default. - self._set_active_low(True) - - def close(self): - # Restore the default direction (turns off LED) before closing. - self._set_direction('in') - super(SysFsGpioPin, self).close() - - -class SysFsPwmPin(SysFsPin): - """SysFs support for PWM pins. - - Supports the SysFs node for pwm control. - """ - _FS_ROOT = '/sys/class/pwm/pwmchip0' - - class PwmState(object): - """Container for the state of the pwm. - - Used to recover after disable/enable and ensure consistency. - """ - - def __init__(self): - self.duty_cycle = 0 - self.period_ns = _NS_PER_SECOND / 50 - self.enabled = False - self.function = None - - def __init__(self, spec): - super(SysFsPwmPin, self).__init__(spec, self._FS_ROOT) - if not isinstance(spec, PwmSpec): - raise TypeError('Pin specification not compatible with SysFS PWM') - if spec.pin < 0 or spec.pin > 3: - raise ValueError('Pin must be between 0 and 3 (inclusive)') - self._spec = spec - self._state = SysFsPwmPin.PwmState() - - def _set_enabled(self, enabled): - self.write_property('enable', '1' if enabled else '0') - self._state.enabled = enabled - - def _get_enabled(self): - return int(self.read_property('enable')) != 0 - - def _set_period_ns(self, period_ns): - self.write_property('period', '%d' % period_ns) - self._state.period_ns = int(period_ns) - - def _get_period_ns(self): - return int(self.read_property('period')) - - def _set_duty_cycle(self, duty_cycle): - self.write_property('duty_cycle', '%d' % duty_cycle) - self._state.duty_cycle = duty_cycle - - def _get_duty_cycle(self): - return int(self.read_property('duty_cycle')) - - def _update_state(self, new_state): - # Each time we enable, we need to first re-set the period and duty cycle (in - # that order). - if new_state.period_ns != self._state.period_ns or (not self._state.enabled - and new_state.enabled): - self._set_period_ns(new_state.period_ns) - if new_state.duty_cycle != self._state.duty_cycle or ( - not self._state.enabled and new_state.enabled): - self._set_duty_cycle(new_state.duty_cycle) - if new_state.enabled != self._state.enabled: - self._set_enabled(new_state.enabled) - - def _read_state(self): - self._state.period_ns = self._get_period_ns() - self._state.enabled = self._get_enabled() - self._state.duty_cycle = self._get_duty_cycle() - - def set_function(self, function): - if function != 'pwm' and function != 'output': - raise ValueError( - 'PWM pins only support pwm and output functionality') - self._state.function = function - - def get_function(self): - return self._state.function - - def get_value(self): - return self._state.duty_cycle / self._state.period_ns - - def set_value(self, value): - new_state = deepcopy(self._state) - if value is None: - new_state.enabled = False - else: - new_state.enabled = True - new_state.duty_cycle = value * self._state.period_ns - self._update_state(new_state) - - def set_period_ns(self, period_ns): - new_state = deepcopy(self._state) - new_state.period_ns = period_ns - self._update_state(new_state) - - def get_period_ns(self): - return self._state.period_ns - - def open(self): - super(SysFsPwmPin, self).open() - self.wait_for_permissions('period') - self.wait_for_permissions('enable') - self._read_state() - new_state = deepcopy(self._state) - new_state.period_ns = _NS_PER_SECOND / 50 - new_state.enabled = True - self._update_state(new_state) - - def close(self): - self._set_enabled(False) - super(SysFsPwmPin, self).close() - - -# Debounce by making sure the last change wasn't less than d_time in the past -> -# should be agnostic to direction. -class DebouncingPoller(object): - """Manages debouncing and polling a function periodically in the background. - - Calls a given getter periodically and when the debounced value changes such - that detector(old, new) returns true, the callback is called. Only runs while - detector, getter, and callback are set. - """ - _MIN_POLL_INTERVAL = .0001 - - def __init__(self, value_getter, callback, detector=lambda old, new: True): - self._poll_thread = None - self._debounce_time = .001 - self._poll_interval = .00051 - self._getter = value_getter - self._detector = detector - self._callback = callback - - @property - def poll_interval(self): - return self._poll_interval - - @poll_interval.setter - def poll_interval(self, interval): - self._poll_interval = max(interval, self._MIN_POLL_INTERVAL) - self.restart_polling() - - @property - def debounce_time(self): - return self._debounce_time - - @debounce_time.setter - def debounce_time(self, debounce_time): - self._debounce_time = debounce_time - self.restart_polling() - - @property - def callback(self): - return self._callback - - @callback.setter - def callback(self, callback): - self.stop_polling() - self._callback = callback - self.try_start_polling() - - @property - def detector(self): - return self._detector - - @detector.setter - def detector(self, detector): - self._detector = detector - self.restart_polling() - - def try_start_polling(self): - if (not self._poll_thread and self._getter and self._callback and - self._detector): - self._poll_thread = GPIOThread( - target=self._poll, - args=(self._poll_interval, self._debounce_time, self._getter, - self._detector, self._callback)) - self._poll_thread.start() - - def stop_polling(self): - if self._poll_thread: - self._poll_thread.stop() - self._poll_thread = None - - def restart_polling(self): - self.stop_polling() - self.try_start_polling() - - # Only called from the polling thread. - def _poll(self, poll_interval, debounce_interval, getter, detector, callback): - """Debounces and monitors the value retrieved by _getter. - - Triggers callback if detector(old_value, new_value) returns true. - Args: - poll_interval: positive float, time in seconds between polling the getter. - debounce_interval: positive float, time in seconds to wait after a change - to allow a future change to the value to trigger the callback. - getter: function() -> value, gets the value. This will be called - periodically and the value type will be the same type passed to the - detector function. - detector: function(old, new) -> bool, filters changes to determine when - the callback should be called. Can be used for edge detection - callback: function() to be invoked when detector conditions are met. - """ - last_time = time.time() - last_value = getter() - while not self._poll_thread.stopping.wait(poll_interval): - value = getter() - new_time = time.time() - if not debounce_interval or (new_time - last_time) > debounce_interval: - if detector(last_value, value): - callback() - last_value = value - last_time = new_time - - -class HatPin(Pin): - """A Pin implemenation that supports pins controlled by the hat's MCU. - - Only one HatPin should exist at a given time for a given pin system wide. - Behavior is completely unpredictable if more than one pin exists concurrently. - If the factory is used for construction there are protections in place to - prevent this, however if multiple programs are running simultaneously the - protections do not limit cross program duplication. - """ - _EDGE_DETECTORS = { - 'both': lambda old, new: old != new, - 'rising': lambda old, new: not old and new, - 'falling': lambda old, new: old and not new, - None: None, - } - - def __init__(self, spec, pwm=False): - super(HatPin, self).__init__() - self.gpio_pin = None - self.pwm_pin = None - self.pwm_active = False - self.gpio_active = False - if spec.gpio_spec is not None: - self.gpio_pin = SysFsGpioPin(spec.gpio_spec) - - if spec.pwm_spec is not None: - self.pwm_pin = SysFsPwmPin(spec.pwm_spec) - - self._closed = False - self._poller = DebouncingPoller(self._get_state, None) - self._edges = None - self._set_bounce(.001) - # Start out with gpio enabled for compatibility. - self._enable_gpio() - - def _enable_pwm(self): - if self._closed: - return - if self.pwm_pin is None: - raise PinPWMUnsupported( - 'PWM was enabled, but is not supported on pin %r' % self.pwm_pin) - self._disable_gpio() - if not self.pwm_active: - self.pwm_pin.open() - self.pwm_active = True - - def _disable_pwm(self): - if self.pwm_active and self.pwm_pin is not None: - self.pwm_pin.close() - self.pwm_active = False - - def _enable_gpio(self): - if self._closed: - return - if self.gpio_pin is None: - raise PinUnsupported( - 'GPIO was enabled, but is not supported on pin %r' % self.gpio_pin) - self._disable_pwm() - if not self.gpio_active: - self.gpio_pin.open() - self.gpio_active = True - - def _disable_gpio(self): - if self.gpio_active and self.gpio_pin is not None: - self.gpio_pin.close() - self.gpio_active = False - - def close(self): - self._closed = True - self._poller.stop_polling() - self._disable_pwm() - self._disable_gpio() - - def _active_pin(self): - if self.pwm_active: - return self.pwm_pin - if self.gpio_active: - return self.gpio_pin - return None - - def _get_function(self): - return self._active_pin().get_function() - - def _set_function(self, value): - if value == 'input': - if self.pwm_active: - raise InputDeviceError('PWM Pin cannot be set to input') - self._enable_gpio() - elif value == 'pwm': - if self.gpio_active: - raise PinPWMUnsupported('GPIO Pin cannot be set to pwm') - self._enable_pwm() - elif self._active_pin() is None: - self._enable_gpio() - - if value != 'input': - self._poller.stop_polling() - self._active_pin().set_function(value) - - def _get_state(self): - return self._active_pin().get_value() - - def _set_state(self, state): - self._active_pin().set_value(state) - - def _get_frequency(self): - if self.pwm_pin is None or not self.pwm_active: - return None - return _NS_PER_SECOND / self.pwm_pin.get_period_ns() - - def _set_frequency(self, frequency): - if frequency is None: - self._enable_gpio() - else: - self._enable_pwm() - self.pwm_pin.set_period_ns(_NS_PER_SECOND / frequency) - - def _set_pull(self, pull): - if pull != 'up': - raise PinFixedPull( - 'Only pull up is supported right now (%s)' % pull) - - def _get_pull(self): - return 'up' - - def _set_edges(self, edges): - if edges not in HatPin._EDGE_DETECTORS.keys(): - raise PinInvalidEdges( - 'Edge must be "both", "falling", "rising", or None') - self._poller.detector = HatPin._EDGE_DETECTORS[edges] - self._edges = edges - - def _get_edges(self): - return self._edges - - def _set_when_changed(self, callback): - self._poller.callback = callback - - def _get_when_changed(self): - return self._poller.callback - - def set_poll_interval(self, poll_interval): - """Sets the time between polling the pin value. - - If a debounce time is set, this will be set to .51 * the debounce time. - There is a natural minimum value of _MIN_POLL_INTERVAL to which all smaller - values will be clipped. - Args: - poll_interval: positve float, time in seconds between polling the pin. - """ - self._poller.poll_interval = poll_interval - - def _set_bounce(self, debounce_time): - if debounce_time is None: - self._poller.debounce_time = debounce_time - elif debounce_time < 0: - raise PinInvalidBounce('Bounce must be positive.') - else: - self._poller.debounce_time = debounce_time - self.set_poll_interval(debounce_time * .51) - - def _get_bounce(self): - return self._poller.debounce_time - - -class HybridFactory(Factory): - """Factory for selecting between other factories based on priority/success.""" - - def __init__(self, *factories): - super(HybridFactory, self).__init__() - self.factories = factories - - def close(self): - for factory in self.factories: - factory.close() - - def pin(self, spec): - for factory in self.factories: - try: - # Try to make the pin from each factory (in order), until one works. - return factory.pin(spec) - except (TypeError, ValueError): - pass - raise TypeError( - 'No registered factory was able to construct a pin for the given ' - 'specification') - - -class HatFactory(Factory): - """Factory for pins accessed through the hat's MCU.""" - pins = {} - - def __init__(self): - super(HatFactory, self).__init__() - - self.pins = HatFactory.pins - - def close(self): - for pin in self.pins.values(): - pin.close() - - def pin(self, spec): - if spec in self.pins: - return self.pins.get(spec) - if isinstance(spec, AIYPinSpec): - pin = HatPin(spec) - self.pins[spec] = pin - return pin - raise TypeError('Hat factory invoked on non-hat pin') - - -# This overrides the default factory being used by all gpiozero devices. It will -# defer to the previous default for all non-hat pins. -hat_factory = HatFactory() -Device.pin_factory = HybridFactory(hat_factory, Device.pin_factory) diff --git a/src/aiy/vision/proto/__init__.py b/src/aiy/vision/proto/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/aiy/vision/proto/protocol_pb2.py b/src/aiy/vision/proto/protocol_pb2.py deleted file mode 100644 index 17879726..00000000 --- a/src/aiy/vision/proto/protocol_pb2.py +++ /dev/null @@ -1,1324 +0,0 @@ -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: protocol.proto - -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) -from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection -from google.protobuf import symbol_database as _symbol_database -from google.protobuf import descriptor_pb2 -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor.FileDescriptor( - name='protocol.proto', - package='spacepark.vision', - syntax='proto3', - serialized_pb=_b('\n\x0eprotocol.proto\x12\x10spacepark.vision\"@\n\tRectangle\x12\t\n\x01x\x18\x01 \x01(\x05\x12\t\n\x01y\x18\x02 \x01(\x05\x12\r\n\x05width\x18\x03 \x01(\x05\x12\x0e\n\x06height\x18\x04 \x01(\x05\"J\n\x0bTensorShape\x12\r\n\x05\x62\x61tch\x18\x01 \x01(\x05\x12\x0e\n\x06height\x18\x02 \x01(\x05\x12\r\n\x05width\x18\x03 \x01(\x05\x12\r\n\x05\x64\x65pth\x18\x04 \x01(\x05\"H\n\nByteTensor\x12,\n\x05shape\x18\x01 \x01(\x0b\x32\x1d.spacepark.vision.TensorShape\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"I\n\x0b\x46loatTensor\x12,\n\x05shape\x18\x01 \x01(\x0b\x32\x1d.spacepark.vision.TensorShape\x12\x0c\n\x04\x64\x61ta\x18\x02 \x03(\x02\"0\n\x10TensorNormalizer\x12\x0c\n\x04mean\x18\x01 \x01(\x02\x12\x0e\n\x06stddev\x18\x02 \x01(\x02\"\xd5\n\n\x07Request\x12\x39\n\nload_model\x18\x01 \x01(\x0b\x32#.spacepark.vision.Request.LoadModelH\x00\x12=\n\x0cunload_model\x18\x02 \x01(\x0b\x32%.spacepark.vision.Request.UnloadModelH\x00\x12\x43\n\x0fimage_inference\x18\x03 \x01(\x0b\x32(.spacepark.vision.Request.ImageInferenceH\x00\x12P\n\x16start_camera_inference\x18\x04 \x01(\x0b\x32..spacepark.vision.Request.StartCameraInferenceH\x00\x12\x45\n\x10\x63\x61mera_inference\x18\x05 \x01(\x0b\x32).spacepark.vision.Request.CameraInferenceH\x00\x12N\n\x15stop_camera_inference\x18\x06 \x01(\x0b\x32-.spacepark.vision.Request.StopCameraInferenceH\x00\x12\x44\n\x10get_camera_state\x18\x07 \x01(\x0b\x32(.spacepark.vision.Request.GetCameraStateH\x00\x12>\n\rimu_self_test\x18\x08 \x01(\x0b\x32%.spacepark.vision.Request.ImuSelfTestH\x00\x12\x46\n\x11get_firmware_info\x18\t \x01(\x0b\x32).spacepark.vision.Request.GetFirmwareInfoH\x00\x1a\xa8\x01\n\tLoadModel\x12\x12\n\nmodel_name\x18\x01 \x01(\t\x12\x32\n\x0binput_shape\x18\x02 \x01(\x0b\x32\x1d.spacepark.vision.TensorShape\x12<\n\x10input_normalizer\x18\x03 \x01(\x0b\x32\".spacepark.vision.TensorNormalizer\x12\x15\n\rcompute_graph\x18\x04 \x01(\x0c\x1a!\n\x0bUnloadModel\x12\x12\n\nmodel_name\x18\x01 \x01(\t\x1a\xc7\x01\n\x0eImageInference\x12\x12\n\nmodel_name\x18\x01 \x01(\t\x12,\n\x06tensor\x18\x02 \x01(\x0b\x32\x1c.spacepark.vision.ByteTensor\x12\x44\n\x06params\x18\x03 \x03(\x0b\x32\x34.spacepark.vision.Request.ImageInference.ParamsEntry\x1a-\n\x0bParamsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\xd2\x01\n\x14StartCameraInference\x12\x12\n\nmodel_name\x18\x01 \x01(\t\x12+\n\x06window\x18\x02 \x01(\x0b\x32\x1b.spacepark.vision.Rectangle\x12J\n\x06params\x18\x03 \x03(\x0b\x32:.spacepark.vision.Request.StartCameraInference.ParamsEntry\x1a-\n\x0bParamsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x11\n\x0f\x43\x61meraInference\x1a\x15\n\x13StopCameraInference\x1a\x10\n\x0eGetCameraState\x1a\r\n\x0bImuSelfTest\x1a\x11\n\x0fGetFirmwareInfoB\t\n\x07request\"\xa9\x03\n\x0fInferenceResult\x12\x12\n\nmodel_name\x18\x01 \x01(\t\x12\r\n\x05width\x18\x02 \x01(\x05\x12\x0e\n\x06height\x18\x03 \x01(\x05\x12+\n\x06window\x18\x04 \x01(\x0b\x32\x1b.spacepark.vision.Rectangle\x12\x13\n\x0b\x64uration_ms\x18\x05 \x01(\x05\x12?\n\x07tensors\x18\x06 \x03(\x0b\x32..spacepark.vision.InferenceResult.TensorsEntry\x12\x36\n\x05\x66rame\x18\x07 \x01(\x0b\x32\'.spacepark.vision.InferenceResult.Frame\x1aM\n\x0cTensorsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12,\n\x05value\x18\x02 \x01(\x0b\x32\x1d.spacepark.vision.FloatTensor:\x02\x38\x01\x1aY\n\x05\x46rame\x12\r\n\x05index\x18\x01 \x01(\x05\x12\x14\n\x0ctimestamp_us\x18\x02 \x01(\x03\x12+\n\x05image\x18\x03 \x01(\x0b\x32\x1c.spacepark.vision.ByteTensor\"=\n\x0b\x43\x61meraState\x12\x0f\n\x07running\x18\x01 \x01(\x08\x12\r\n\x05width\x18\x02 \x01(\x05\x12\x0e\n\x06height\x18\x03 \x01(\x05\"<\n\x0c\x46irmwareInfo\x12\x15\n\rmajor_version\x18\x01 \x01(\x05\x12\x15\n\rminor_version\x18\x02 \x01(\x05\"\xe4\x02\n\x08Response\x12\x31\n\x06status\x18\x01 \x01(\x0b\x32!.spacepark.vision.Response.Status\x12=\n\x10inference_result\x18\x02 \x01(\x0b\x32!.spacepark.vision.InferenceResultH\x00\x12\x35\n\x0c\x63\x61mera_state\x18\x03 \x01(\x0b\x32\x1d.spacepark.vision.CameraStateH\x00\x12\x37\n\rfirmware_info\x18\x04 \x01(\x0b\x32\x1e.spacepark.vision.FirmwareInfoH\x00\x1aj\n\x06Status\x12\x34\n\x04\x63ode\x18\x01 \x01(\x0e\x32&.spacepark.vision.Response.Status.Code\x12\x0f\n\x07message\x18\x02 \x01(\t\"\x19\n\x04\x43ode\x12\x06\n\x02OK\x10\x00\x12\t\n\x05\x45RROR\x10\x01\x42\n\n\x08responseb\x06proto3') -) - - - -_RESPONSE_STATUS_CODE = _descriptor.EnumDescriptor( - name='Code', - full_name='spacepark.vision.Response.Status.Code', - filename=None, - file=DESCRIPTOR, - values=[ - _descriptor.EnumValueDescriptor( - name='OK', index=0, number=0, - options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='ERROR', index=1, number=1, - options=None, - type=None), - ], - containing_type=None, - options=None, - serialized_start=2618, - serialized_end=2643, -) -_sym_db.RegisterEnumDescriptor(_RESPONSE_STATUS_CODE) - - -_RECTANGLE = _descriptor.Descriptor( - name='Rectangle', - full_name='spacepark.vision.Rectangle', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='x', full_name='spacepark.vision.Rectangle.x', index=0, - number=1, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='y', full_name='spacepark.vision.Rectangle.y', index=1, - number=2, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='width', full_name='spacepark.vision.Rectangle.width', index=2, - number=3, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='height', full_name='spacepark.vision.Rectangle.height', index=3, - number=4, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=36, - serialized_end=100, -) - - -_TENSORSHAPE = _descriptor.Descriptor( - name='TensorShape', - full_name='spacepark.vision.TensorShape', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='batch', full_name='spacepark.vision.TensorShape.batch', index=0, - number=1, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='height', full_name='spacepark.vision.TensorShape.height', index=1, - number=2, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='width', full_name='spacepark.vision.TensorShape.width', index=2, - number=3, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='depth', full_name='spacepark.vision.TensorShape.depth', index=3, - number=4, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=102, - serialized_end=176, -) - - -_BYTETENSOR = _descriptor.Descriptor( - name='ByteTensor', - full_name='spacepark.vision.ByteTensor', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='shape', full_name='spacepark.vision.ByteTensor.shape', index=0, - number=1, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='data', full_name='spacepark.vision.ByteTensor.data', index=1, - number=2, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=178, - serialized_end=250, -) - - -_FLOATTENSOR = _descriptor.Descriptor( - name='FloatTensor', - full_name='spacepark.vision.FloatTensor', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='shape', full_name='spacepark.vision.FloatTensor.shape', index=0, - number=1, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='data', full_name='spacepark.vision.FloatTensor.data', index=1, - number=2, type=2, cpp_type=6, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=252, - serialized_end=325, -) - - -_TENSORNORMALIZER = _descriptor.Descriptor( - name='TensorNormalizer', - full_name='spacepark.vision.TensorNormalizer', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='mean', full_name='spacepark.vision.TensorNormalizer.mean', index=0, - number=1, type=2, cpp_type=6, label=1, - has_default_value=False, default_value=float(0), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='stddev', full_name='spacepark.vision.TensorNormalizer.stddev', index=1, - number=2, type=2, cpp_type=6, label=1, - has_default_value=False, default_value=float(0), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=327, - serialized_end=375, -) - - -_REQUEST_LOADMODEL = _descriptor.Descriptor( - name='LoadModel', - full_name='spacepark.vision.Request.LoadModel', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='model_name', full_name='spacepark.vision.Request.LoadModel.model_name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='input_shape', full_name='spacepark.vision.Request.LoadModel.input_shape', index=1, - number=2, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='input_normalizer', full_name='spacepark.vision.Request.LoadModel.input_normalizer', index=2, - number=3, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='compute_graph', full_name='spacepark.vision.Request.LoadModel.compute_graph', index=3, - number=4, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1020, - serialized_end=1188, -) - -_REQUEST_UNLOADMODEL = _descriptor.Descriptor( - name='UnloadModel', - full_name='spacepark.vision.Request.UnloadModel', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='model_name', full_name='spacepark.vision.Request.UnloadModel.model_name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1190, - serialized_end=1223, -) - -_REQUEST_IMAGEINFERENCE_PARAMSENTRY = _descriptor.Descriptor( - name='ParamsEntry', - full_name='spacepark.vision.Request.ImageInference.ParamsEntry', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='key', full_name='spacepark.vision.Request.ImageInference.ParamsEntry.key', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='value', full_name='spacepark.vision.Request.ImageInference.ParamsEntry.value', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')), - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1380, - serialized_end=1425, -) - -_REQUEST_IMAGEINFERENCE = _descriptor.Descriptor( - name='ImageInference', - full_name='spacepark.vision.Request.ImageInference', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='model_name', full_name='spacepark.vision.Request.ImageInference.model_name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='tensor', full_name='spacepark.vision.Request.ImageInference.tensor', index=1, - number=2, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='params', full_name='spacepark.vision.Request.ImageInference.params', index=2, - number=3, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[_REQUEST_IMAGEINFERENCE_PARAMSENTRY, ], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1226, - serialized_end=1425, -) - -_REQUEST_STARTCAMERAINFERENCE_PARAMSENTRY = _descriptor.Descriptor( - name='ParamsEntry', - full_name='spacepark.vision.Request.StartCameraInference.ParamsEntry', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='key', full_name='spacepark.vision.Request.StartCameraInference.ParamsEntry.key', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='value', full_name='spacepark.vision.Request.StartCameraInference.ParamsEntry.value', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')), - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1380, - serialized_end=1425, -) - -_REQUEST_STARTCAMERAINFERENCE = _descriptor.Descriptor( - name='StartCameraInference', - full_name='spacepark.vision.Request.StartCameraInference', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='model_name', full_name='spacepark.vision.Request.StartCameraInference.model_name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='window', full_name='spacepark.vision.Request.StartCameraInference.window', index=1, - number=2, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='params', full_name='spacepark.vision.Request.StartCameraInference.params', index=2, - number=3, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[_REQUEST_STARTCAMERAINFERENCE_PARAMSENTRY, ], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1428, - serialized_end=1638, -) - -_REQUEST_CAMERAINFERENCE = _descriptor.Descriptor( - name='CameraInference', - full_name='spacepark.vision.Request.CameraInference', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1640, - serialized_end=1657, -) - -_REQUEST_STOPCAMERAINFERENCE = _descriptor.Descriptor( - name='StopCameraInference', - full_name='spacepark.vision.Request.StopCameraInference', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1659, - serialized_end=1680, -) - -_REQUEST_GETCAMERASTATE = _descriptor.Descriptor( - name='GetCameraState', - full_name='spacepark.vision.Request.GetCameraState', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1682, - serialized_end=1698, -) - -_REQUEST_IMUSELFTEST = _descriptor.Descriptor( - name='ImuSelfTest', - full_name='spacepark.vision.Request.ImuSelfTest', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1700, - serialized_end=1713, -) - -_REQUEST_GETFIRMWAREINFO = _descriptor.Descriptor( - name='GetFirmwareInfo', - full_name='spacepark.vision.Request.GetFirmwareInfo', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1715, - serialized_end=1732, -) - -_REQUEST = _descriptor.Descriptor( - name='Request', - full_name='spacepark.vision.Request', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='load_model', full_name='spacepark.vision.Request.load_model', index=0, - number=1, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='unload_model', full_name='spacepark.vision.Request.unload_model', index=1, - number=2, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='image_inference', full_name='spacepark.vision.Request.image_inference', index=2, - number=3, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='start_camera_inference', full_name='spacepark.vision.Request.start_camera_inference', index=3, - number=4, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='camera_inference', full_name='spacepark.vision.Request.camera_inference', index=4, - number=5, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='stop_camera_inference', full_name='spacepark.vision.Request.stop_camera_inference', index=5, - number=6, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='get_camera_state', full_name='spacepark.vision.Request.get_camera_state', index=6, - number=7, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='imu_self_test', full_name='spacepark.vision.Request.imu_self_test', index=7, - number=8, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='get_firmware_info', full_name='spacepark.vision.Request.get_firmware_info', index=8, - number=9, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[_REQUEST_LOADMODEL, _REQUEST_UNLOADMODEL, _REQUEST_IMAGEINFERENCE, _REQUEST_STARTCAMERAINFERENCE, _REQUEST_CAMERAINFERENCE, _REQUEST_STOPCAMERAINFERENCE, _REQUEST_GETCAMERASTATE, _REQUEST_IMUSELFTEST, _REQUEST_GETFIRMWAREINFO, ], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - _descriptor.OneofDescriptor( - name='request', full_name='spacepark.vision.Request.request', - index=0, containing_type=None, fields=[]), - ], - serialized_start=378, - serialized_end=1743, -) - - -_INFERENCERESULT_TENSORSENTRY = _descriptor.Descriptor( - name='TensorsEntry', - full_name='spacepark.vision.InferenceResult.TensorsEntry', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='key', full_name='spacepark.vision.InferenceResult.TensorsEntry.key', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='value', full_name='spacepark.vision.InferenceResult.TensorsEntry.value', index=1, - number=2, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')), - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=2003, - serialized_end=2080, -) - -_INFERENCERESULT_FRAME = _descriptor.Descriptor( - name='Frame', - full_name='spacepark.vision.InferenceResult.Frame', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='index', full_name='spacepark.vision.InferenceResult.Frame.index', index=0, - number=1, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='timestamp_us', full_name='spacepark.vision.InferenceResult.Frame.timestamp_us', index=1, - number=2, type=3, cpp_type=2, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='image', full_name='spacepark.vision.InferenceResult.Frame.image', index=2, - number=3, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=2082, - serialized_end=2171, -) - -_INFERENCERESULT = _descriptor.Descriptor( - name='InferenceResult', - full_name='spacepark.vision.InferenceResult', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='model_name', full_name='spacepark.vision.InferenceResult.model_name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='width', full_name='spacepark.vision.InferenceResult.width', index=1, - number=2, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='height', full_name='spacepark.vision.InferenceResult.height', index=2, - number=3, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='window', full_name='spacepark.vision.InferenceResult.window', index=3, - number=4, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='duration_ms', full_name='spacepark.vision.InferenceResult.duration_ms', index=4, - number=5, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='tensors', full_name='spacepark.vision.InferenceResult.tensors', index=5, - number=6, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='frame', full_name='spacepark.vision.InferenceResult.frame', index=6, - number=7, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[_INFERENCERESULT_TENSORSENTRY, _INFERENCERESULT_FRAME, ], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1746, - serialized_end=2171, -) - - -_CAMERASTATE = _descriptor.Descriptor( - name='CameraState', - full_name='spacepark.vision.CameraState', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='running', full_name='spacepark.vision.CameraState.running', index=0, - number=1, type=8, cpp_type=7, label=1, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='width', full_name='spacepark.vision.CameraState.width', index=1, - number=2, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='height', full_name='spacepark.vision.CameraState.height', index=2, - number=3, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=2173, - serialized_end=2234, -) - - -_FIRMWAREINFO = _descriptor.Descriptor( - name='FirmwareInfo', - full_name='spacepark.vision.FirmwareInfo', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='major_version', full_name='spacepark.vision.FirmwareInfo.major_version', index=0, - number=1, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='minor_version', full_name='spacepark.vision.FirmwareInfo.minor_version', index=1, - number=2, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=2236, - serialized_end=2296, -) - - -_RESPONSE_STATUS = _descriptor.Descriptor( - name='Status', - full_name='spacepark.vision.Response.Status', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='code', full_name='spacepark.vision.Response.Status.code', index=0, - number=1, type=14, cpp_type=8, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='message', full_name='spacepark.vision.Response.Status.message', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - _RESPONSE_STATUS_CODE, - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=2537, - serialized_end=2643, -) - -_RESPONSE = _descriptor.Descriptor( - name='Response', - full_name='spacepark.vision.Response', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='status', full_name='spacepark.vision.Response.status', index=0, - number=1, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='inference_result', full_name='spacepark.vision.Response.inference_result', index=1, - number=2, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='camera_state', full_name='spacepark.vision.Response.camera_state', index=2, - number=3, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='firmware_info', full_name='spacepark.vision.Response.firmware_info', index=3, - number=4, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[_RESPONSE_STATUS, ], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - _descriptor.OneofDescriptor( - name='response', full_name='spacepark.vision.Response.response', - index=0, containing_type=None, fields=[]), - ], - serialized_start=2299, - serialized_end=2655, -) - -_BYTETENSOR.fields_by_name['shape'].message_type = _TENSORSHAPE -_FLOATTENSOR.fields_by_name['shape'].message_type = _TENSORSHAPE -_REQUEST_LOADMODEL.fields_by_name['input_shape'].message_type = _TENSORSHAPE -_REQUEST_LOADMODEL.fields_by_name['input_normalizer'].message_type = _TENSORNORMALIZER -_REQUEST_LOADMODEL.containing_type = _REQUEST -_REQUEST_UNLOADMODEL.containing_type = _REQUEST -_REQUEST_IMAGEINFERENCE_PARAMSENTRY.containing_type = _REQUEST_IMAGEINFERENCE -_REQUEST_IMAGEINFERENCE.fields_by_name['tensor'].message_type = _BYTETENSOR -_REQUEST_IMAGEINFERENCE.fields_by_name['params'].message_type = _REQUEST_IMAGEINFERENCE_PARAMSENTRY -_REQUEST_IMAGEINFERENCE.containing_type = _REQUEST -_REQUEST_STARTCAMERAINFERENCE_PARAMSENTRY.containing_type = _REQUEST_STARTCAMERAINFERENCE -_REQUEST_STARTCAMERAINFERENCE.fields_by_name['window'].message_type = _RECTANGLE -_REQUEST_STARTCAMERAINFERENCE.fields_by_name['params'].message_type = _REQUEST_STARTCAMERAINFERENCE_PARAMSENTRY -_REQUEST_STARTCAMERAINFERENCE.containing_type = _REQUEST -_REQUEST_CAMERAINFERENCE.containing_type = _REQUEST -_REQUEST_STOPCAMERAINFERENCE.containing_type = _REQUEST -_REQUEST_GETCAMERASTATE.containing_type = _REQUEST -_REQUEST_IMUSELFTEST.containing_type = _REQUEST -_REQUEST_GETFIRMWAREINFO.containing_type = _REQUEST -_REQUEST.fields_by_name['load_model'].message_type = _REQUEST_LOADMODEL -_REQUEST.fields_by_name['unload_model'].message_type = _REQUEST_UNLOADMODEL -_REQUEST.fields_by_name['image_inference'].message_type = _REQUEST_IMAGEINFERENCE -_REQUEST.fields_by_name['start_camera_inference'].message_type = _REQUEST_STARTCAMERAINFERENCE -_REQUEST.fields_by_name['camera_inference'].message_type = _REQUEST_CAMERAINFERENCE -_REQUEST.fields_by_name['stop_camera_inference'].message_type = _REQUEST_STOPCAMERAINFERENCE -_REQUEST.fields_by_name['get_camera_state'].message_type = _REQUEST_GETCAMERASTATE -_REQUEST.fields_by_name['imu_self_test'].message_type = _REQUEST_IMUSELFTEST -_REQUEST.fields_by_name['get_firmware_info'].message_type = _REQUEST_GETFIRMWAREINFO -_REQUEST.oneofs_by_name['request'].fields.append( - _REQUEST.fields_by_name['load_model']) -_REQUEST.fields_by_name['load_model'].containing_oneof = _REQUEST.oneofs_by_name['request'] -_REQUEST.oneofs_by_name['request'].fields.append( - _REQUEST.fields_by_name['unload_model']) -_REQUEST.fields_by_name['unload_model'].containing_oneof = _REQUEST.oneofs_by_name['request'] -_REQUEST.oneofs_by_name['request'].fields.append( - _REQUEST.fields_by_name['image_inference']) -_REQUEST.fields_by_name['image_inference'].containing_oneof = _REQUEST.oneofs_by_name['request'] -_REQUEST.oneofs_by_name['request'].fields.append( - _REQUEST.fields_by_name['start_camera_inference']) -_REQUEST.fields_by_name['start_camera_inference'].containing_oneof = _REQUEST.oneofs_by_name['request'] -_REQUEST.oneofs_by_name['request'].fields.append( - _REQUEST.fields_by_name['camera_inference']) -_REQUEST.fields_by_name['camera_inference'].containing_oneof = _REQUEST.oneofs_by_name['request'] -_REQUEST.oneofs_by_name['request'].fields.append( - _REQUEST.fields_by_name['stop_camera_inference']) -_REQUEST.fields_by_name['stop_camera_inference'].containing_oneof = _REQUEST.oneofs_by_name['request'] -_REQUEST.oneofs_by_name['request'].fields.append( - _REQUEST.fields_by_name['get_camera_state']) -_REQUEST.fields_by_name['get_camera_state'].containing_oneof = _REQUEST.oneofs_by_name['request'] -_REQUEST.oneofs_by_name['request'].fields.append( - _REQUEST.fields_by_name['imu_self_test']) -_REQUEST.fields_by_name['imu_self_test'].containing_oneof = _REQUEST.oneofs_by_name['request'] -_REQUEST.oneofs_by_name['request'].fields.append( - _REQUEST.fields_by_name['get_firmware_info']) -_REQUEST.fields_by_name['get_firmware_info'].containing_oneof = _REQUEST.oneofs_by_name['request'] -_INFERENCERESULT_TENSORSENTRY.fields_by_name['value'].message_type = _FLOATTENSOR -_INFERENCERESULT_TENSORSENTRY.containing_type = _INFERENCERESULT -_INFERENCERESULT_FRAME.fields_by_name['image'].message_type = _BYTETENSOR -_INFERENCERESULT_FRAME.containing_type = _INFERENCERESULT -_INFERENCERESULT.fields_by_name['window'].message_type = _RECTANGLE -_INFERENCERESULT.fields_by_name['tensors'].message_type = _INFERENCERESULT_TENSORSENTRY -_INFERENCERESULT.fields_by_name['frame'].message_type = _INFERENCERESULT_FRAME -_RESPONSE_STATUS.fields_by_name['code'].enum_type = _RESPONSE_STATUS_CODE -_RESPONSE_STATUS.containing_type = _RESPONSE -_RESPONSE_STATUS_CODE.containing_type = _RESPONSE_STATUS -_RESPONSE.fields_by_name['status'].message_type = _RESPONSE_STATUS -_RESPONSE.fields_by_name['inference_result'].message_type = _INFERENCERESULT -_RESPONSE.fields_by_name['camera_state'].message_type = _CAMERASTATE -_RESPONSE.fields_by_name['firmware_info'].message_type = _FIRMWAREINFO -_RESPONSE.oneofs_by_name['response'].fields.append( - _RESPONSE.fields_by_name['inference_result']) -_RESPONSE.fields_by_name['inference_result'].containing_oneof = _RESPONSE.oneofs_by_name['response'] -_RESPONSE.oneofs_by_name['response'].fields.append( - _RESPONSE.fields_by_name['camera_state']) -_RESPONSE.fields_by_name['camera_state'].containing_oneof = _RESPONSE.oneofs_by_name['response'] -_RESPONSE.oneofs_by_name['response'].fields.append( - _RESPONSE.fields_by_name['firmware_info']) -_RESPONSE.fields_by_name['firmware_info'].containing_oneof = _RESPONSE.oneofs_by_name['response'] -DESCRIPTOR.message_types_by_name['Rectangle'] = _RECTANGLE -DESCRIPTOR.message_types_by_name['TensorShape'] = _TENSORSHAPE -DESCRIPTOR.message_types_by_name['ByteTensor'] = _BYTETENSOR -DESCRIPTOR.message_types_by_name['FloatTensor'] = _FLOATTENSOR -DESCRIPTOR.message_types_by_name['TensorNormalizer'] = _TENSORNORMALIZER -DESCRIPTOR.message_types_by_name['Request'] = _REQUEST -DESCRIPTOR.message_types_by_name['InferenceResult'] = _INFERENCERESULT -DESCRIPTOR.message_types_by_name['CameraState'] = _CAMERASTATE -DESCRIPTOR.message_types_by_name['FirmwareInfo'] = _FIRMWAREINFO -DESCRIPTOR.message_types_by_name['Response'] = _RESPONSE -_sym_db.RegisterFileDescriptor(DESCRIPTOR) - -Rectangle = _reflection.GeneratedProtocolMessageType('Rectangle', (_message.Message,), dict( - DESCRIPTOR = _RECTANGLE, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.Rectangle) - )) -_sym_db.RegisterMessage(Rectangle) - -TensorShape = _reflection.GeneratedProtocolMessageType('TensorShape', (_message.Message,), dict( - DESCRIPTOR = _TENSORSHAPE, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.TensorShape) - )) -_sym_db.RegisterMessage(TensorShape) - -ByteTensor = _reflection.GeneratedProtocolMessageType('ByteTensor', (_message.Message,), dict( - DESCRIPTOR = _BYTETENSOR, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.ByteTensor) - )) -_sym_db.RegisterMessage(ByteTensor) - -FloatTensor = _reflection.GeneratedProtocolMessageType('FloatTensor', (_message.Message,), dict( - DESCRIPTOR = _FLOATTENSOR, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.FloatTensor) - )) -_sym_db.RegisterMessage(FloatTensor) - -TensorNormalizer = _reflection.GeneratedProtocolMessageType('TensorNormalizer', (_message.Message,), dict( - DESCRIPTOR = _TENSORNORMALIZER, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.TensorNormalizer) - )) -_sym_db.RegisterMessage(TensorNormalizer) - -Request = _reflection.GeneratedProtocolMessageType('Request', (_message.Message,), dict( - - LoadModel = _reflection.GeneratedProtocolMessageType('LoadModel', (_message.Message,), dict( - DESCRIPTOR = _REQUEST_LOADMODEL, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.Request.LoadModel) - )) - , - - UnloadModel = _reflection.GeneratedProtocolMessageType('UnloadModel', (_message.Message,), dict( - DESCRIPTOR = _REQUEST_UNLOADMODEL, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.Request.UnloadModel) - )) - , - - ImageInference = _reflection.GeneratedProtocolMessageType('ImageInference', (_message.Message,), dict( - - ParamsEntry = _reflection.GeneratedProtocolMessageType('ParamsEntry', (_message.Message,), dict( - DESCRIPTOR = _REQUEST_IMAGEINFERENCE_PARAMSENTRY, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.Request.ImageInference.ParamsEntry) - )) - , - DESCRIPTOR = _REQUEST_IMAGEINFERENCE, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.Request.ImageInference) - )) - , - - StartCameraInference = _reflection.GeneratedProtocolMessageType('StartCameraInference', (_message.Message,), dict( - - ParamsEntry = _reflection.GeneratedProtocolMessageType('ParamsEntry', (_message.Message,), dict( - DESCRIPTOR = _REQUEST_STARTCAMERAINFERENCE_PARAMSENTRY, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.Request.StartCameraInference.ParamsEntry) - )) - , - DESCRIPTOR = _REQUEST_STARTCAMERAINFERENCE, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.Request.StartCameraInference) - )) - , - - CameraInference = _reflection.GeneratedProtocolMessageType('CameraInference', (_message.Message,), dict( - DESCRIPTOR = _REQUEST_CAMERAINFERENCE, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.Request.CameraInference) - )) - , - - StopCameraInference = _reflection.GeneratedProtocolMessageType('StopCameraInference', (_message.Message,), dict( - DESCRIPTOR = _REQUEST_STOPCAMERAINFERENCE, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.Request.StopCameraInference) - )) - , - - GetCameraState = _reflection.GeneratedProtocolMessageType('GetCameraState', (_message.Message,), dict( - DESCRIPTOR = _REQUEST_GETCAMERASTATE, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.Request.GetCameraState) - )) - , - - ImuSelfTest = _reflection.GeneratedProtocolMessageType('ImuSelfTest', (_message.Message,), dict( - DESCRIPTOR = _REQUEST_IMUSELFTEST, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.Request.ImuSelfTest) - )) - , - - GetFirmwareInfo = _reflection.GeneratedProtocolMessageType('GetFirmwareInfo', (_message.Message,), dict( - DESCRIPTOR = _REQUEST_GETFIRMWAREINFO, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.Request.GetFirmwareInfo) - )) - , - DESCRIPTOR = _REQUEST, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.Request) - )) -_sym_db.RegisterMessage(Request) -_sym_db.RegisterMessage(Request.LoadModel) -_sym_db.RegisterMessage(Request.UnloadModel) -_sym_db.RegisterMessage(Request.ImageInference) -_sym_db.RegisterMessage(Request.ImageInference.ParamsEntry) -_sym_db.RegisterMessage(Request.StartCameraInference) -_sym_db.RegisterMessage(Request.StartCameraInference.ParamsEntry) -_sym_db.RegisterMessage(Request.CameraInference) -_sym_db.RegisterMessage(Request.StopCameraInference) -_sym_db.RegisterMessage(Request.GetCameraState) -_sym_db.RegisterMessage(Request.ImuSelfTest) -_sym_db.RegisterMessage(Request.GetFirmwareInfo) - -InferenceResult = _reflection.GeneratedProtocolMessageType('InferenceResult', (_message.Message,), dict( - - TensorsEntry = _reflection.GeneratedProtocolMessageType('TensorsEntry', (_message.Message,), dict( - DESCRIPTOR = _INFERENCERESULT_TENSORSENTRY, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.InferenceResult.TensorsEntry) - )) - , - - Frame = _reflection.GeneratedProtocolMessageType('Frame', (_message.Message,), dict( - DESCRIPTOR = _INFERENCERESULT_FRAME, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.InferenceResult.Frame) - )) - , - DESCRIPTOR = _INFERENCERESULT, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.InferenceResult) - )) -_sym_db.RegisterMessage(InferenceResult) -_sym_db.RegisterMessage(InferenceResult.TensorsEntry) -_sym_db.RegisterMessage(InferenceResult.Frame) - -CameraState = _reflection.GeneratedProtocolMessageType('CameraState', (_message.Message,), dict( - DESCRIPTOR = _CAMERASTATE, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.CameraState) - )) -_sym_db.RegisterMessage(CameraState) - -FirmwareInfo = _reflection.GeneratedProtocolMessageType('FirmwareInfo', (_message.Message,), dict( - DESCRIPTOR = _FIRMWAREINFO, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.FirmwareInfo) - )) -_sym_db.RegisterMessage(FirmwareInfo) - -Response = _reflection.GeneratedProtocolMessageType('Response', (_message.Message,), dict( - - Status = _reflection.GeneratedProtocolMessageType('Status', (_message.Message,), dict( - DESCRIPTOR = _RESPONSE_STATUS, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.Response.Status) - )) - , - DESCRIPTOR = _RESPONSE, - __module__ = 'protocol_pb2' - # @@protoc_insertion_point(class_scope:spacepark.vision.Response) - )) -_sym_db.RegisterMessage(Response) -_sym_db.RegisterMessage(Response.Status) - - -_REQUEST_IMAGEINFERENCE_PARAMSENTRY.has_options = True -_REQUEST_IMAGEINFERENCE_PARAMSENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) -_REQUEST_STARTCAMERAINFERENCE_PARAMSENTRY.has_options = True -_REQUEST_STARTCAMERAINFERENCE_PARAMSENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) -_INFERENCERESULT_TENSORSENTRY.has_options = True -_INFERENCERESULT_TENSORSENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) -# @@protoc_insertion_point(module_scope) diff --git a/src/aiy/voicehat.py b/src/aiy/voicehat.py deleted file mode 100644 index 57414394..00000000 --- a/src/aiy/voicehat.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Drivers for shared functionality provided by the VoiceHat.""" - -import aiy._drivers._button -import aiy._drivers._led -import aiy._drivers._status_ui - -# GPIO definitions (BCM) -_GPIO_BUTTON = 23 -_GPIO_LED = 25 - -# Import LED class to expose the LED constants. -LED = aiy._drivers._led.LED - -# Global variables. They are lazily initialized. -_voicehat_button = None -_voicehat_led = None -_status_ui = None - - -def get_button(): - """Returns a driver to the VoiceHat button. - - The button driver detects edges on _GPIO_BUTTON. It can be used both - synchronously and asynchrously. - - Synchronous usage: - button = aiy.voicehat.get_button() - button.wait_for_press() - # The above function does not return until the button is pressed. - my_recognizer.recognize() - ... - - Asynchronous usage: - def on_button_press(_): - print('The button is pressed!') - - button = aiy.voicehat.get_button() - button.on_press(on_button_press) - # The console will print 'The button is pressed!' every time the button is - # pressed. - ... - # To cancel the callback, pass None: - button.on_press(None) - # Calling wait_for_press() also cancels any callback. - """ - global _voicehat_button - if not _voicehat_button: - _voicehat_button = aiy._drivers._button.Button(channel=_GPIO_BUTTON) - return _voicehat_button - - -def get_led(): - """Returns a driver to control the VoiceHat LED light with various animations. - - led = aiy.voicehat.get_led() - - # You may set any LED animation: - led.set_state(aiy.voicehat.LED.PULSE_QUICK) - led.set_state(aiy.voicehat.LED.BLINK) - - # Or turn off the light but keep the driver running: - led.set_state(aiy.voicehat.LED.OFF) - """ - global _voicehat_led - if not _voicehat_led: - _voicehat_led = aiy._drivers._led.LED(channel=_GPIO_LED) - _voicehat_led.start() - return _voicehat_led - - -def get_status_ui(): - """Returns a driver to control the LED via statuses. - - The supported statuses are: - - "starting" - - "ready" - - "listening" - - "thinking" - - "stopping" - - "power-off" - - "error" - - Optionally, a sound may be played once when the status changes to - "listening". For example, if you have a wave file at ~/ding.wav, you may set - the trigger sound by: - aiy.voicehat.get_status_ui().set_trigger_sound_wave('~/ding.wav') - - To set the status, use: - aiy.voicehat.get_status_ui().set_state('starting') - aiy.voicehat.get_status_ui().set_state('thinking') - """ - global _status_ui - if not _status_ui: - _status_ui = aiy._drivers._status_ui._StatusUi() - return _status_ui diff --git a/src/examples/vision/annotator.py b/src/examples/vision/annotator.py deleted file mode 100755 index 399a9eec..00000000 --- a/src/examples/vision/annotator.py +++ /dev/null @@ -1,180 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Annotation library for drawing overlays on the raspberry pi's camera preview. - -Annotations include bounding boxes, text overlays, and points. -Annotations support partial opacity, however only with respect to the content in -the preview. A transparent fill value will cover up previously drawn overlay -under it, but not the camera content under it. A color of None can be given, -which will then not cover up overlay content drawn under the region. - -Note: Overlays do not persist through to the storage layer so images saved from -the camera, will not contain overlays. -""" - -import picamera -import time -from PIL import Image -from PIL import ImageDraw - - -def _round_to_bit(value, power): - """Rounds the given value to the next multiple of 2^power. - - Args: - value: int to be rounded. - power: power of two which the value should be rounded up to. - Returns: - the result of value rounded to the next multiple 2^power. - """ - return (((value - 1) >> power) + 1) << power - - -def _round_buffer_dims(dims): - """Appropriately rounds the given dimensions for image overlaying. - - The overlay buffer must be rounded the next multiple of 32 for the hight, and - the next multiple of 16 for the width.""" - return (_round_to_bit(dims[0], 5), _round_to_bit(dims[1], 4)) - - -# TODO(namiller): Add an annotator for images. -class Annotator(object): - """Utility for managing annotations on the camera preview. - - Args: - camera: picamera.PiCamera camera object to overlay on top of. - bg_color: PIL.ImageColor (with alpha) for the background of the overlays. - default_color: PIL.ImageColor (with alpha) default for the drawn content. - """ - - def __init__(self, camera, bg_color=None, default_color=None, - dimensions=None): - self._dims = dimensions if dimensions else camera.resolution - self._buffer_dims = _round_buffer_dims(self._dims) - self._buffer = Image.new('RGBA', self._buffer_dims) - self._overlay = camera.add_overlay( - self._buffer.tobytes(), format='rgba', layer=3, size=self._buffer_dims) - self._draw = ImageDraw.Draw(self._buffer) - self._bg_color = bg_color if bg_color else (0, 0, 0, 0xA0) - self._default_color = default_color if default_color else (0xFF, 0, 0, 0xFF) - - # MMALPort has a bug in enable.wrapper, where it always calls - # self._pool.send_buffer(block=False) regardless of the port direction. - # This is in contrast to setup time when it only calls - # self._pool.send_all_buffers(block=False) - # if self._port[0].type == mmal.MMAL_PORT_TYPE_OUTPUT. - # Because of this bug updating an overlay once will log a MMAL_EAGAIN - # error every update. This is safe to ignore as we the user is driving - # the renderer input port with calls to update() that dequeue buffers - # and sends them to the input port (so queue is empty on when - # send_all_buffers(block=False) is called from wrapper). - # As a workaround, monkey patch MMALPortPool.send_buffer and - # silence the "error" if thrown by our overlay instance. - original_send_buffer = picamera.mmalobj.MMALPortPool.send_buffer - - def silent_send_buffer(zelf, **kwargs): - try: - original_send_buffer(zelf, **kwargs) - except picamera.exc.PiCameraMMALError as error: - # Only silence MMAL_EAGAIN for our target instance. - our_target = self._overlay.renderer.inputs[0].pool == zelf - if not our_target or error.status != 14: - raise error - - picamera.mmalobj.MMALPortPool.send_buffer = silent_send_buffer - - def update(self): - """Updates the contents of the overlay.""" - self._overlay.update(self._buffer.tobytes()) - - def stop(self): - """Removes the overlay from the screen.""" - self._draw.rectangle((0, 0) + self._dims, fill=0) - self.update() - - def clear(self): - """Clears the contents of the overlay - leaving only the plain background. - """ - self._draw.rectangle((0, 0) + self._dims, fill=self._bg_color) - - def bounding_box(self, rect, outline=None, fill=None): - """Draws a bounding box around the specified rectangle. - - Args: - rect: (x1, y1, x2, y2) rectangle to be drawn - where (x1,y1) and (x2, y2) - are opposite corners of the desired rectangle. - outline: PIL.ImageColor with which to draw the outline (defaults to the - configured default_color). - fill: PIL.ImageColor with which to fill the rectangel (defaults to None - which will not cover up drawings under the region. - """ - outline = self._default_color if outline is None else outline - self._draw.rectangle(rect, fill=fill, outline=outline) - - # TODO(namiller): Add a font size parameter and load a truetype font. - def text(self, location, text, color=None): - """Draws the given text at the given location. - - Args: - location: (x,y) point at which to draw the text (upper left corner). - text: string to be drawn. - color: PIL.ImageColor to draw the string in (defaults to default_color). - """ - color = self._default_color if color is None else color - self._draw.text(location, text, fill=color) - - def point(self, location, radius=1, color=None): - """Draws a point of the given size at the given location. - - Args: - location: (x,y) center of the point to be drawn. - radius: the radius of the point to be drawn. - color: The color to draw the point in (defaults to default_color). - """ - color = self._default_color if color is None else color - self._draw.ellipse( - (location[0] - radius, location[1] - radius, location[0] + radius, - location[1] + radius), - fill=color) - - -def _main(): - """Example usage of the annotator utility. - - Demonstrates setting up a camera preview, drawing slowly moving/intersecting - animations over it, and clearing the overlays.""" - with picamera.PiCamera() as camera: - # Resolution can be arbitrary. - camera.resolution = (351, 561) - camera.start_preview() - annotator = Annotator(camera) - for i in range(10): - annotator.clear() - annotator.bounding_box( - (20, 20, 70, 70), outline=(0, 0xFF, 0, 0xFF), fill=0) - annotator.bounding_box((10 * i, 10, 10 * i + 50, 60)) - annotator.bounding_box( - (80, 0, 130, 50), outline=(0, 0, 0xFF, 0xFF), fill=0) - annotator.text((100, 100), 'Hello World') - annotator.point((10, 100), radius=5) - annotator.update() - time.sleep(1) - annotator.stop() - time.sleep(10) - - -if __name__ == '__main__': - _main() diff --git a/src/examples/vision/dish_classifier.py b/src/examples/vision/dish_classifier.py deleted file mode 100755 index 862b48f0..00000000 --- a/src/examples/vision/dish_classifier.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Dish classifier library demo.""" - -import argparse -from PIL import Image - -from aiy.vision.inference import ImageInference -from aiy.vision.models import dish_classifier - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('--input', '-i', dest='input', required=True) - args = parser.parse_args() - - with ImageInference(dish_classifier.model()) as inference: - image = Image.open(args.input) - classes = dish_classifier.get_classes( - inference.run(image), max_num_objects=5, object_prob_threshold=0.1) - for i, (label, score) in enumerate(classes): - print('Result %d: %s (prob=%f)' % (i, label, score)) - - -if __name__ == '__main__': - main() diff --git a/src/examples/vision/face_camera_trigger.py b/src/examples/vision/face_camera_trigger.py deleted file mode 100755 index 9c32ac37..00000000 --- a/src/examples/vision/face_camera_trigger.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Trigger PiCamera when face is detected.""" - -from aiy.vision.inference import CameraInference -from aiy.vision.models import face_detection -from picamera import PiCamera - - -def main(): - with PiCamera() as camera: - # Configure camera - camera.resolution = (1640, 922) # Full Frame, 16:9 (Camera v2) - camera.start_preview() - - # Do inference on VisionBonnet - with CameraInference(face_detection.model()) as inference: - for result in inference.run(): - if len(face_detection.get_faces(result)) >= 1: - camera.capture('faces.jpg') - break - - # Stop preview - camera.stop_preview() - - -if __name__ == '__main__': - main() diff --git a/src/examples/vision/face_detection.py b/src/examples/vision/face_detection.py deleted file mode 100755 index 9c8eb234..00000000 --- a/src/examples/vision/face_detection.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Face detection library demo. - - - Takes an input image and tries to detect faces. - - Draws bounding boxes around detected objects. - - Saves an image with bounding boxes around detected objects. -""" -import argparse -import io -import sys -from PIL import Image -from PIL import ImageDraw - -from aiy.vision.inference import ImageInference -from aiy.vision.models import face_detection - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('--input', '-i', dest='input', required=True) - parser.add_argument('--output', '-o', dest='output') - args = parser.parse_args() - - with ImageInference(face_detection.model()) as inference: - image = Image.open( - io.BytesIO(sys.stdin.buffer.read()) - if args.input == '-' else args.input) - draw = ImageDraw.Draw(image) - for i, face in enumerate(face_detection.get_faces(inference.run(image))): - print('Face #%d: %s' % (i, str(face))) - x, y, width, height = face.bounding_box - draw.rectangle((x, y, x + width, y + height), outline='red') - if args.output: - image.save(args.output) - - -if __name__ == '__main__': - main() diff --git a/src/examples/vision/face_detection_camera.py b/src/examples/vision/face_detection_camera.py deleted file mode 100755 index d7ba3f26..00000000 --- a/src/examples/vision/face_detection_camera.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Camera inference face detection demo code. - -Runs continuous face detection on the VisionBonnet and prints the number of -detected faces. - -Example: -face_detection_camera.py --num_frames 10 -""" -import argparse - -from aiy.vision.inference import CameraInference -from aiy.vision.models import face_detection -from examples.vision.annotator import Annotator -from picamera import PiCamera - - -def main(): - """Face detection camera inference example.""" - parser = argparse.ArgumentParser() - parser.add_argument( - '--num_frames', - '-n', - type=int, - dest='num_frames', - default=-1, - help='Sets the number of frames to run for, otherwise runs forever.') - args = parser.parse_args() - - with PiCamera() as camera: - # Forced sensor mode, 1640x1232, full FoV. See: - # https://picamera.readthedocs.io/en/release-1.13/fov.html#sensor-modes - # This is the resolution inference run on. - camera.sensor_mode = 4 - - # Scaled and cropped resolution. If different from sensor mode implied - # resolution, inference results must be adjusted accordingly. This is - # true in particular when camera.start_recording is used to record an - # encoded h264 video stream as the Pi encoder can't encode all native - # sensor resolutions, or a standard one like 1080p may be desired. - camera.resolution = (1640, 1232) - - # Start the camera stream. - camera.framerate = 30 - camera.start_preview() - - # Annotator renders in software so use a smaller size and scale results - # for increased performace. - annotator = Annotator(camera, dimensions=(320, 240)) - scale_x = 320 / 1640 - scale_y = 240 / 1232 - - # Incoming boxes are of the form (x, y, width, height). Scale and - # transform to the form (x1, y1, x2, y2). - def transform(bounding_box): - x, y, width, height = bounding_box - return (scale_x * x, scale_y * y, scale_x * (x + width), - scale_y * (y + height)) - - with CameraInference(face_detection.model()) as inference: - for i, result in enumerate(inference.run()): - if i == args.num_frames: - break - faces = face_detection.get_faces(result) - annotator.clear() - for face in faces: - annotator.bounding_box(transform(face.bounding_box), fill=0) - annotator.update() - print('Iteration #%d: num_faces=%d' % (i, len(faces))) - - camera.stop_preview() - - -if __name__ == '__main__': - main() diff --git a/src/examples/vision/gpiozero/bonnet_button.py b/src/examples/vision/gpiozero/bonnet_button.py deleted file mode 100755 index 7915548a..00000000 --- a/src/examples/vision/gpiozero/bonnet_button.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python3 -"""Example code that demonstrates using a button connected through the hat. - -The button uses a hat pin through the sysfs driver illustrating the edge -detection polling. - -The demo will light up the on board LED whenever PIN_D is drawn high. -""" -from signal import pause -from gpiozero import Button -from gpiozero import LED -from aiy.vision.pins import LED_1 -from aiy.vision.pins import PIN_D - - -# Set up a gpiozero LED using the first onboard LED on the vision hat. -led = LED(LED_1) -# Set up a gpiozero Button using the 4th pin on the vision hat expansion. -button = Button(PIN_D) - -# When the button is pressed, call the led.on() function (turn the led on) -button.when_pressed = led.on -# When the button is released, call the led.off() function (turn the led off) -button.when_released = led.off - -# Wait for the user to kill the example. -pause() diff --git a/src/examples/vision/gpiozero/button_example.py b/src/examples/vision/gpiozero/button_example.py deleted file mode 100755 index 075c2f8d..00000000 --- a/src/examples/vision/gpiozero/button_example.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python3 -"""Example code that demonstrates using a standard pin along with a hat pin. - -The button uses a standard GPIO pin through the raspberry pi's memory mapped io, -while the led uses the hat's sysfs driver. This implemenation difference is -transparent to the user. - -The demo will light up the on board LED whenever the user presses the button. -""" -from signal import pause -from gpiozero import Button -from gpiozero import LED -from aiy.vision.pins import BUTTON_GPIO_PIN -from aiy.vision.pins import LED_1 - -# Set up a gpiozero LED using the first onboard LED on the vision hat. -led = LED(LED_1) -# Set up a gpiozero Button using the button included with the vision hat. -button = Button(BUTTON_GPIO_PIN) - -# When the button is pressed, call the led.on() function (turn the led on) -button.when_pressed = led.on -# When the button is released, call the led.off() function (turn the led off) -button.when_released = led.off - -# Wait for the user to kill the example. -pause() diff --git a/src/examples/vision/gpiozero/led_example.py b/src/examples/vision/gpiozero/led_example.py deleted file mode 100755 index c5854d1d..00000000 --- a/src/examples/vision/gpiozero/led_example.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python3 -"""Demonstrates on board LED support with correct polarity. - -Demo will turn on, then off the first LED on the hat. -""" - -from time import sleep -from gpiozero import LED -from aiy.vision.pins import LED_1 - -led = LED(LED_1) -# Alternate turning the LED off and on until the user terminates the example. -while True: - led.on() - sleep(1) - led.off() - sleep(1) diff --git a/src/examples/vision/gpiozero/servo_example.py b/src/examples/vision/gpiozero/servo_example.py deleted file mode 100755 index 737bd83e..00000000 --- a/src/examples/vision/gpiozero/servo_example.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python3 -"""Demonstrates simultaneous control of two servos on the hat. - -One servo uses the simple default configuration, the other servo is tuned to -ensure the full range is reachable. -""" - -from time import sleep -from gpiozero import Servo -from aiy.vision.pins import PIN_A -from aiy.vision.pins import PIN_B - -# Create a default servo that will not be able to use quite the full range. -simple_servo = Servo(PIN_A) -# Create a servo with the custom values to give the full dynamic range. -tuned_servo = Servo(PIN_B, min_pulse_width=.0005, max_pulse_width=.0019) - -# Move the Servos back and forth until the user terminates the example. -while True: - simple_servo.min() - tuned_servo.max() - sleep(1) - simple_servo.mid() - tuned_servo.mid() - sleep(1) - simple_servo.max() - tuned_servo.min() - sleep(1) diff --git a/src/examples/vision/gpiozero/simple_button_example.py b/src/examples/vision/gpiozero/simple_button_example.py deleted file mode 100755 index cb5459cb..00000000 --- a/src/examples/vision/gpiozero/simple_button_example.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python3 -"""Example code that demonstrates using a standard pin along with a hat pin. - -The button uses a standard GPIO pin through the raspberry pi's memory mapped io, -while the led uses the hat's sysfs driver. This implemenation difference is -transparent to the user. - -The demo will light up the on board LED whenever the user presses the button. -""" -from gpiozero import Button -from gpiozero import LED -from aiy.vision.pins import BUTTON_GPIO_PIN -from aiy.vision.pins import LED_1 - -# Set up a gpiozero LED using the first onboard LED on the vision hat. -led = LED(LED_1) -# Set up a gpiozero Button using the button included with the vision hat. -button = Button(BUTTON_GPIO_PIN) - -while True: - if button.is_pressed: - led.on() - else: - led.off() diff --git a/src/examples/vision/image_classification.py b/src/examples/vision/image_classification.py deleted file mode 100755 index 07e764d2..00000000 --- a/src/examples/vision/image_classification.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Image classification library demo.""" - -import argparse -import io -import sys -from PIL import Image - -from aiy.vision.inference import ImageInference -from aiy.vision.models import image_classification - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('--input', '-i', dest='input', required=True) - args = parser.parse_args() - - # There are two models available for image classification task: - # 1) MobileNet based (image_classification.MOBILENET), which has 59.9% top-1 - # accuracy on ImageNet; - # 2) SqueezeNet based (image_classification.SQUEEZENET), which has 45.3% top-1 - # accuracy on ImageNet; - model_type = image_classification.MOBILENET - with ImageInference(image_classification.model(model_type)) as inference: - image = Image.open( - io.BytesIO(sys.stdin.buffer.read()) - if args.input == '-' else args.input) - classes = image_classification.get_classes( - inference.run(image), max_num_objects=5, object_prob_threshold=0.1) - for i, (label, score) in enumerate(classes): - print('Result %d: %s (prob=%f)' % (i, label, score)) - - -if __name__ == '__main__': - main() diff --git a/src/examples/vision/image_classification_camera.py b/src/examples/vision/image_classification_camera.py deleted file mode 100755 index ee20f376..00000000 --- a/src/examples/vision/image_classification_camera.py +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Camera image classification demo code. - -Runs continuous image detection on the VisionBonnet and prints the object and -probability for top three objects. - -Example: -image_classification_camera.py --num_frames 10 -""" -import argparse - -from aiy.vision.inference import CameraInference -from aiy.vision.models import image_classification -from picamera import PiCamera - - -def main(): - """Image classification camera inference example.""" - parser = argparse.ArgumentParser() - parser.add_argument( - '--num_frames', - '-n', - type=int, - dest='num_frames', - default=-1, - help='Sets the number of frames to run for, otherwise runs forever.') - - parser.add_argument( - '--num_objects', - '-c', - type=int, - dest='num_objects', - default=3, - help='Sets the number of object interences to print.') - - args = parser.parse_args() - - def print_classes(classes, object_count): - s = '' - for index, (obj, prob) in enumerate(classes): - if index > object_count - 1: - break - s += '%s=%1.2f\t|\t' % (obj, prob) - print('%s\r' % s) - - with PiCamera() as camera: - # Forced sensor mode, 1640x1232, full FoV. See: - # https://picamera.readthedocs.io/en/release-1.13/fov.html#sensor-modes - # This is the resolution inference run on. - camera.sensor_mode = 4 - - # Scaled and cropped resolution. If different from sensor mode implied - # resolution, inference results must be adjusted accordingly. This is - # true in particular when camera.start_recording is used to record an - # encoded h264 video stream as the Pi encoder can't encode all native - # sensor resolutions, or a standard one like 1080p may be desired. - camera.resolution = (1640, 1232) - - # Start the camera stream. - camera.framerate = 30 - camera.start_preview() - - with CameraInference(image_classification.model()) as inference: - for i, result in enumerate(inference.run()): - if i == args.num_frames: - break - classes = image_classification.get_classes(result) - print_classes(classes, args.num_objects) - - camera.stop_preview() - - -if __name__ == '__main__': - main() diff --git a/src/examples/vision/joy/install-services.sh b/src/examples/vision/joy/install-services.sh deleted file mode 100755 index 1a92ae27..00000000 --- a/src/examples/vision/joy/install-services.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -scripts_dir="$(dirname "${BASH_SOURCE[0]}")" -cd "${scripts_dir}" - -sudo cp joy_detection_demo.service /lib/systemd/system -systemctl enable joy_detection_demo.service diff --git a/src/examples/vision/joy/joy_detection_demo.py b/src/examples/vision/joy/joy_detection_demo.py deleted file mode 100755 index 34db62ed..00000000 --- a/src/examples/vision/joy/joy_detection_demo.py +++ /dev/null @@ -1,326 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Joy detection demo.""" -import argparse -import collections -import io -import logging -import math -import os -import queue -import signal -import threading -import time - -from aiy._drivers._hat import get_aiy_device_name -from aiy.toneplayer import TonePlayer -from aiy.vision.inference import CameraInference -from aiy.vision.leds import Leds -from aiy.vision.leds import PrivacyLed -from aiy.vision.models import face_detection - -from contextlib import contextmanager -from gpiozero import Button -from picamera import PiCamera - -from PIL import Image -from PIL import ImageDraw -from PIL import ImageFont - -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) - -JOY_COLOR = (255, 70, 0) -SAD_COLOR = (0, 0, 64) - -JOY_SCORE_PEAK = 0.85 -JOY_SCORE_MIN = 0.10 - -JOY_SOUND = ('C5q', 'E5q', 'C6q') -SAD_SOUND = ('C6q', 'E5q', 'C5q') -MODEL_LOAD_SOUND = ('C6w', 'c6w', 'C6w') -BEEP_SOUND = ('E6q', 'C6q') - - -@contextmanager -def stopwatch(message): - try: - logger.info('%s...', message) - begin = time.time() - yield - finally: - end = time.time() - logger.info('%s done. (%fs)', message, end - begin) - - -def blend(color_a, color_b, alpha): - return tuple([math.ceil(alpha * color_a[i] + (1.0 - alpha) * color_b[i]) for i in range(3)]) - - -def average_joy_score(faces): - if faces: - return sum([face.joy_score for face in faces]) / len(faces) - return 0.0 - - -def draw_rectangle(draw, x0, y0, x1, y1, border, fill=None, outline=None): - assert border % 2 == 1 - for i in range(-border // 2, border // 2 + 1): - draw.rectangle((x0 + i, y0 + i, x1 - i, y1 - i), fill=fill, outline=outline) - - -class AtomicValue(object): - - def __init__(self, value): - self._lock = threading.Lock() - self._value = value - - @property - def value(self): - with self._lock: - return self._value - - @value.setter - def value(self, value): - with self._lock: - self._value = value - - -class MovingAverage(object): - - def __init__(self, size): - self._window = collections.deque(maxlen=size) - - def next(self, value): - self._window.append(value) - return sum(self._window) / len(self._window) - - -class Service(object): - - def __init__(self): - self._requests = queue.Queue() - self._thread = threading.Thread(target=self._run) - self._thread.start() - - def _run(self): - while True: - request = self._requests.get() - if request is None: - break - self.process(request) - self._requests.task_done() - - def join(self): - self._thread.join() - - def stop(self): - self._requests.put(None) - - def process(self, request): - pass - - def submit(self, request): - self._requests.put(request) - - -class Player(Service): - """Controls buzzer.""" - - def __init__(self, gpio, bpm): - super().__init__() - self._toneplayer = TonePlayer(gpio, bpm) - - def process(self, sound): - self._toneplayer.play(*sound) - - def play(self, sound): - self.submit(sound) - - -class Photographer(Service): - """Saves photographs to disk.""" - - def __init__(self, format, folder): - super().__init__() - assert format in ('jpeg', 'bmp', 'png') - - self._font = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSans.ttf', size=25) - self._faces = AtomicValue(()) - self._format = format - self._folder = folder - - def _make_filename(self, timestamp, annotated): - path = '%s/%s_annotated.%s' if annotated else '%s/%s.%s' - return os.path.expanduser(path % (self._folder, timestamp, self._format)) - - def _draw_face(self, draw, face): - x, y, width, height = face.bounding_box - text = 'Joy: %.2f' % face.joy_score - _, text_height = self._font.getsize(text) - margin = 3 - bottom = y + height - text_bottom = bottom + margin + text_height + margin - draw_rectangle(draw, x, y, x + width, bottom, 3, outline='white') - draw_rectangle(draw, x, bottom, x + width, text_bottom, 3, fill='white', outline='white') - draw.text((x + 1 + margin, y + height + 1 + margin), text, font=self._font, fill='black') - - def process(self, camera): - faces = self._faces.value - timestamp = time.strftime('%Y-%m-%d_%H.%M.%S') - - stream = io.BytesIO() - with stopwatch('Taking photo'): - camera.capture(stream, format=self._format, use_video_port=True) - - filename = self._make_filename(timestamp, annotated=False) - with stopwatch('Saving original %s' % filename): - stream.seek(0) - with open(filename, 'wb') as file: - file.write(stream.read()) - - if faces: - filename = self._make_filename(timestamp, annotated=True) - with stopwatch('Saving annotated %s' % filename): - stream.seek(0) - image = Image.open(stream) - draw = ImageDraw.Draw(image) - for face in faces: - self._draw_face(draw, face) - del draw - image.save(filename) - - def update_faces(self, faces): - self._faces.value = faces - - def shoot(self, camera): - self.submit(camera) - - -class Animator(object): - """Controls RGB LEDs.""" - - def __init__(self, leds, done): - self._leds = leds - self._done = done - self._joy_score = AtomicValue(0.0) - self._thread = threading.Thread(target=self._run) - self._thread.start() - - def _run(self): - while not self._done.is_set(): - joy_score = self._joy_score.value - if joy_score > 0: - self._leds.update(Leds.rgb_on(blend(JOY_COLOR, SAD_COLOR, joy_score))) - else: - self._leds.update(Leds.rgb_off()) - - def update_joy_score(self, value): - self._joy_score.value = value - - def join(self): - self._thread.join() - - -class JoyDetector(object): - - def __init__(self): - self._done = threading.Event() - signal.signal(signal.SIGINT, lambda signal, frame: self.stop()) - signal.signal(signal.SIGTERM, lambda signal, frame: self.stop()) - - def stop(self): - logger.info('Stopping...') - self._done.set() - - def run(self, num_frames, preview_alpha, image_format, image_folder): - logger.info('Starting...') - leds = Leds() - player = Player(gpio=22, bpm=10) - photographer = Photographer(image_format, image_folder) - animator = Animator(leds, self._done) - - try: - # Forced sensor mode, 1640x1232, full FoV. See: - # https://picamera.readthedocs.io/en/release-1.13/fov.html#sensor-modes - # This is the resolution inference run on. - with PiCamera(sensor_mode=4, resolution=(1640, 1232)) as camera, PrivacyLed(leds): - def take_photo(): - logger.info('Button pressed.') - player.play(BEEP_SOUND) - photographer.shoot(camera) - - # Blend the preview layer with the alpha value from the flags. - camera.start_preview(alpha=preview_alpha) - - button = Button(23) - button.when_pressed = take_photo - - joy_score_moving_average = MovingAverage(10) - prev_joy_score = 0.0 - with CameraInference(face_detection.model()) as inference: - logger.info('Model loaded.') - player.play(MODEL_LOAD_SOUND) - for i, result in enumerate(inference.run()): - faces = face_detection.get_faces(result) - photographer.update_faces(faces) - - joy_score = joy_score_moving_average.next(average_joy_score(faces)) - animator.update_joy_score(joy_score) - - if joy_score > JOY_SCORE_PEAK > prev_joy_score: - player.play(JOY_SOUND) - elif joy_score < JOY_SCORE_MIN < prev_joy_score: - player.play(SAD_SOUND) - - prev_joy_score = joy_score - - if self._done.is_set() or i == num_frames: - break - finally: - player.stop() - photographer.stop() - - player.join() - photographer.join() - animator.join() - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('--num_frames', '-n', type=int, dest='num_frames', default=-1, - help='Number of frames to run for, -1 to not terminate') - parser.add_argument('--preview_alpha', '-pa', type=int, dest='preview_alpha', default=0, - help='Transparency value of the preview overlay (0-255).') - parser.add_argument('--image_format', type=str, dest='image_format', default='jpeg', - choices=('jpeg', 'bmp', 'png'), help='Format of captured images.') - parser.add_argument('--image_folder', type=str, dest='image_folder', default='~/Pictures', - help='Folder to save captured images.') - args = parser.parse_args() - - if args.preview_alpha < 0 or args.preview_alpha > 255: - parser.error('Invalid preview_alpha value: %d' % args.preview_alpha) - - device = get_aiy_device_name() - if not device or 'Vision' not in device: - logger.error('AIY VisionBonnet is not detected.') - return - - detector = JoyDetector() - detector.run(args.num_frames, args.preview_alpha, args.image_format, args.image_folder) - - -if __name__ == '__main__': - main() diff --git a/src/examples/vision/joy/joy_detection_demo.service b/src/examples/vision/joy/joy_detection_demo.service deleted file mode 100644 index 43577770..00000000 --- a/src/examples/vision/joy/joy_detection_demo.service +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=AIY Joy Detection Demo - -[Service] -Type=simple -Restart=no -User=pi -ExecStart=/usr/bin/python3 /home/pi/AIY-projects-python/src/examples/vision/joy/joy_detection_demo.py - -[Install] -WantedBy=multi-user.target diff --git a/src/examples/vision/leds_example.py b/src/examples/vision/leds_example.py deleted file mode 100755 index 6aaa56b9..00000000 --- a/src/examples/vision/leds_example.py +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import math -import time - -from aiy.vision.leds import Leds -from aiy.vision.leds import Pattern -from aiy.vision.leds import PrivacyLed -from aiy.vision.leds import RgbLeds - -RED = (0xFF, 0x00, 0x00) -GREEN = (0x00, 0xFF, 0x00) -YELLOW = (0xFF, 0xFF, 0x00) -BLUE = (0x00, 0x00, 0xFF) -PURPLE = (0xFF, 0x00, 0xFF) -CYAN = (0x00, 0xFF, 0xFF) -WHITE = (0xFF, 0xFF, 0xFF) - - -def blend(color_a, color_b, alpha): - return tuple([math.ceil(alpha * color_a[i] + (1.0 - alpha) * color_b[i]) for i in range(3)]) - - -leds = Leds() - -print('RGB: Solid RED for 1 second') -leds.update(Leds.rgb_on(RED)) -time.sleep(1) - -print('RGB: Solid GREEN for 1 second') -leds.update(Leds.rgb_on(GREEN)) -time.sleep(1) - -print('RGB: Solid YELLOW for 1 second') -leds.update(Leds.rgb_on(YELLOW)) -time.sleep(1) - -print('RGB: Solid BLUE for 1 second') -leds.update(Leds.rgb_on(BLUE)) -time.sleep(1) - -print('RGB: Solid PURPLE for 1 second') -leds.update(Leds.rgb_on(PURPLE)) -time.sleep(1) - -print('RGB: Solid CYAN for 1 second') -leds.update(Leds.rgb_on(CYAN)) -time.sleep(1) - -print('RGB: Solid WHITE for 1 second') -leds.update(Leds.rgb_on(WHITE)) -time.sleep(1) - -print('RGB: Off for 1 second') -leds.update(Leds.rgb_off()) -time.sleep(1) - -for _ in range(3): - print('Privacy: On (brightness=default)') - leds.update(Leds.privacy_on()) - time.sleep(1) - print('Privacy: Off') - leds.update(Leds.privacy_off()) - time.sleep(1) - -for _ in range(3): - print('Privacy: On (brightness=5)') - leds.update(Leds.privacy_on(5)) - time.sleep(1) - print('Privacy: Off') - leds.update(Leds.privacy_off()) - time.sleep(1) - -print('Set blink pattern: period=500ms (2Hz)') -leds.pattern = Pattern.blink(500) - -print('RGB: Blink RED for 5 seconds') -leds.update(Leds.rgb_pattern(RED)) -time.sleep(5) - -print('RGB: Blink GREEN for 5 seconds') -leds.update(Leds.rgb_pattern(GREEN)) -time.sleep(5) - -print('RGB: Blink BLUE for 5 seconds') -leds.update(Leds.rgb_pattern(BLUE)) -time.sleep(5) - -print('Set breathe pattern: period=1000ms (1Hz)') -leds.pattern = Pattern.breathe(1000) - -print('RGB: Breathe RED for 5 seconds') -leds.update(Leds.rgb_pattern(RED)) -time.sleep(5) - -print('RGB: Breathe GREEN for 5 seconds') -leds.update(Leds.rgb_pattern(GREEN)) -time.sleep(5) - -print('RGB: Breathe BLUE for 5 seconds') -leds.update(Leds.rgb_pattern(BLUE)) -time.sleep(5) - -print('RGB: Increase RED brightness for 3.2 seconds') -for i in range(32): - leds.update(Leds.rgb_on((8 * i, 0, 0))) - time.sleep(0.1) - -print('RGB: Decrease RED brightness for 3.2 seconds') -for i in reversed(range(32)): - leds.update(Leds.rgb_on((8 * i, 0, 0))) - time.sleep(0.1) - -print('RGB: Blend between GREEN and BLUE for 3.2 seconds') -for i in range(32): - leds.update(Leds.rgb_on(blend(BLUE, GREEN, i / 32))) - time.sleep(0.1) - -print('RGB: Off for 1 second') -leds.update(Leds.rgb_off()) -time.sleep(1) - -print('Privacy: On for 2 seconds') -with PrivacyLed(leds): - time.sleep(2) - -print('RGB: Solid GREEN for 2 seconds') -with RgbLeds(leds, Leds.rgb_on(GREEN)): - time.sleep(2) - -print('Custom configuration for 5 seconds') -leds.update({ - 1: Leds.Channel(Leds.Channel.PATTERN, 128), # Red channel - 2: Leds.Channel(Leds.Channel.OFF, 0), # Green channel - 3: Leds.Channel(Leds.Channel.ON, 128), # Blue channel - 4: Leds.Channel(Leds.Channel.PATTERN, 64), # Privacy channel -}) -time.sleep(5) - -print('Done') -leds.reset() diff --git a/src/examples/vision/object_detection.py b/src/examples/vision/object_detection.py deleted file mode 100755 index a5f3896a..00000000 --- a/src/examples/vision/object_detection.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Object detection library demo. - - - Takes an input image and tries to detect person, dog, or cat. - - Draws bounding boxes around detected objects. - - Saves an image with bounding boxes around detected objects. -""" -import argparse -import io -import sys -from PIL import Image -from PIL import ImageDraw - -from aiy.vision.inference import ImageInference -from aiy.vision.models import object_detection - - -def _crop_center(image): - width, height = image.size - size = min(width, height) - x, y = (width - size) / 2, (height - size) / 2 - return image.crop((x, y, x + size, y + size)), (x, y) - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('--input', '-i', dest='input', required=True) - parser.add_argument('--output', '-o', dest='output') - args = parser.parse_args() - - with ImageInference(object_detection.model()) as inference: - image = Image.open( - io.BytesIO(sys.stdin.buffer.read()) - if args.input == '-' else args.input) - image_center, offset = _crop_center(image) - draw = ImageDraw.Draw(image) - result = inference.run(image_center) - for i, obj in enumerate(object_detection.get_objects(result, 0.3, offset)): - print('Object #%d: %s' % (i, str(obj))) - x, y, width, height = obj.bounding_box - draw.rectangle((x, y, x + width, y + height), outline='red') - if args.output: - image.save(args.output) - - -if __name__ == '__main__': - main() diff --git a/src/examples/vision/object_meter/README.md b/src/examples/vision/object_meter/README.md deleted file mode 100644 index 18a4062f..00000000 --- a/src/examples/vision/object_meter/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Image classification demo - -## Physical Setup - -- VisionHat installed on a Raspberry Pi Zero -- Servo connected to vision hat (signal - PIN_A, Vcc - POWER, Ground - GND) - - Servo mounted in label display -- (optional) Monitor connected to raspberry pi. diff --git a/src/examples/vision/object_meter/install_services.sh b/src/examples/vision/object_meter/install_services.sh deleted file mode 100755 index 0c643036..00000000 --- a/src/examples/vision/object_meter/install_services.sh +++ /dev/null @@ -1,18 +0,0 @@ - #!/bin/bash -# Copyright 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -scripts_dir="$(dirname "${BASH_SOURCE[0]}")" -cd "${scripts_dir}" -sudo cp object_meter_demo.service /lib/systemd/system -systemctl enable object_meter_demo.service diff --git a/src/examples/vision/object_meter/object_meter.py b/src/examples/vision/object_meter/object_meter.py deleted file mode 100755 index e0d1d47b..00000000 --- a/src/examples/vision/object_meter/object_meter.py +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Object detection with servo output demo.""" -import argparse -import time -import picamera - -from aiy.vision.pins import PIN_A -from aiy.vision.pins import BUTTON_GPIO_PIN -from aiy.vision.inference import CameraInference -from aiy.vision.models import image_classification -from examples.vision.annotator import Annotator -from gpiozero import Button -from gpiozero import AngularServo -from wordnet_grouping import category_mapper - - -class AutoButton(object): - """Button utility that handles the io and state tracking.""" - - def __init__(self, start_enabled=False, use_hardware=True): - self._use_hardware = use_hardware - if use_hardware: - self._button = Button(BUTTON_GPIO_PIN) - self._enabled = start_enabled - if not start_enabled: - self._button.when_pressed = self._enable - - def _enable(self): - self._enabled = True - - def on(self): - if not self._use_hardware or not self._enabled: - return True - # Button is currently pressed - return self._button.is_pressed - - -class OverlayManager(object): - """Overlay utility for managing state and drawing of overlay.""" - LINE_HEIGHT = 12 - ROW_HEIGHT = 50 - - def __init__(self, camera): - self._clear_needed = False - self._annotator = Annotator(camera, default_color=(0xFF, 0xFF, 0xFF, 0xFF), - dimensions=(320, 240)) - - def _draw_annotation(self, result, category, index): - self._annotator.text((5, - index * self.ROW_HEIGHT + 5 + 0 * self.LINE_HEIGHT), - '{:.2%}'.format(result[1])) - self._annotator.text((5, - index * self.ROW_HEIGHT + 5 + 1 * self.LINE_HEIGHT), - '{:25.25}'.format(result[0])) - self._annotator.text((5, - index * self.ROW_HEIGHT + 5 + 2 * self.LINE_HEIGHT), - 'category: {:20.20}'.format(category)) - - def clear(self): - if self._clear_needed: - self._annotator.stop() - self._clear_needed = False - - def update(self, classes, categories): - self._annotator.clear() - self._clear_needed = True - for i, result in enumerate(classes): - self._draw_annotation(result, categories[i], i) - self._annotator.update() - - -class DummyOverlayManager(object): - """Dummy implementation of overlay manager used when overlay is disabled.""" - - def clear(self): - pass - - def update(self, classes, categories): - del classes, categories # Unused - - -def main(): - parser = argparse.ArgumentParser( - description='Example application for displaying a dial indicator for ' - 'what object is seen') - parser.add_argument( - '--output_overlay', - default=True, - type=bool, - help='Should the visual overlay be generated') - parser.add_argument( - '--button_enabled', - default=True, - type=bool, - help='Should the button be monitored') - parser.add_argument( - '--button_active', - default=False, - type=bool, - help='Should the button start out active (true) or only be active once ' - 'pressed (false)') - flags = parser.parse_args() - load_model = time.time() - category_count = len(category_mapper.get_categories()) - button = AutoButton(flags.button_active, flags.button_enabled) - - for category in category_mapper.get_categories(): - print('Category[%d]: %s' % (category_mapper.get_category_index(category), - category)) - with picamera.PiCamera() as camera: - camera.resolution = (1640, 1232) - camera.start_preview() - overlay = OverlayManager( - camera) if flags.output_overlay else DummyOverlayManager() - servo = AngularServo(PIN_A, min_pulse_width=.0005, max_pulse_width=.0019) - with CameraInference(image_classification.model()) as classifier: - print('Load Model %f' % (time.time() - load_model)) - for result in classifier.run(): - if not button.on(): - overlay.clear() - servo.angle = -90 - continue - - classes = image_classification.get_classes(result) - - probs = [0] * (category_count + 1) - result_categories = [] - for label, score in classes: - category = category_mapper.get_category(label) or 'Other' - probs[category_mapper.get_category_index(category) + 1] += score - result_categories.append(category) - overlay.update(classes, result_categories) - max_prob = max(probs) - best_category = probs.index(max_prob) - if best_category == 0 and max_prob > .5: - servo.angle = -90 - elif best_category != 0: - servo.angle = -90 + (180 * best_category) / category_count - print('category: %d - %s' % - (best_category, - category_mapper.get_categories()[best_category - 1])) - - -if __name__ == '__main__': - main() diff --git a/src/examples/vision/object_meter/object_meter_demo.service b/src/examples/vision/object_meter/object_meter_demo.service deleted file mode 100644 index e021b625..00000000 --- a/src/examples/vision/object_meter/object_meter_demo.service +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description=AIY Object Meter Demo - -[Service] -Type=simple -Restart=no -ExecStart=/home/pi/AIY-projects-python/env/bin/python /home/pi/AIY-projects-python/src/examples/vision/object_meter/object_meter.py - -[Install] -WantedBy=multi-user.target diff --git a/src/examples/vision/object_meter/wordnet_grouping/category_mapper.py b/src/examples/vision/object_meter/wordnet_grouping/category_mapper.py deleted file mode 100755 index 7fe36509..00000000 --- a/src/examples/vision/object_meter/wordnet_grouping/category_mapper.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Utility for grouping ImageNet classifications under super-categories. - -Super categories are defined by the mapping_data.py file which uses labels from -nodes above the grouped leaves in the wordnet for defining super-categories. -""" - -from __future__ import print_function -from .mapping_data import CATEGORIES -from .mapping_data import MAPPINGS - - -def get_category(word): - return MAPPINGS.get(word) - - -def get_categories(): - return CATEGORIES - - -def get_word_index(word): - category = get_category(word) - if category is None: - return -1 - return get_categories().index(category) - - -def get_category_index(category): - try: - return get_categories().index(category) - except ValueError: - return -1 - - -def _example_usage(): - """Example usage for the category mapper utility.""" - print('~'.join(get_categories())) - print(get_category('hay')) - print(get_category('ballpoint/ballpoint pen/ballpen/Biro')) - print(get_category('beer bottle')) - print(get_category('NASDFOIAAS')) - print(get_word_index('beer bottle')) - print(get_word_index('NASDFLJ')) - for cat in get_categories(): - print('%d : %s' % (get_category_index(cat), cat)) - - cat = 'Other' - print('%d : %s' % (get_category_index(cat), cat)) - - -if __name__ == '__main__': - _example_usage() diff --git a/src/examples/vision/object_meter/wordnet_grouping/mapping_data.py b/src/examples/vision/object_meter/wordnet_grouping/mapping_data.py deleted file mode 100644 index da230c23..00000000 --- a/src/examples/vision/object_meter/wordnet_grouping/mapping_data.py +++ /dev/null @@ -1,1240 +0,0 @@ -# Copyright 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Auto generated wordnet mappings for imagenet values to categories.""" - -MAPPINGS = { - "black stork/Ciconia nigra": - "animal, animate being, beast, brute, creature, fauna", - "drake": - "animal, animate being, beast, brute, creature, fauna", - "guinea pig/Cavia cobaya": - "animal, animate being, beast, brute, creature, fauna", - "golden retriever": - "dog, domestic dog, Canis familiaris", - "echidna/spiny anteater/anteater": - "animal, animate being, beast, brute, creature, fauna", - "printer": - "electronic equipment", - "ruffed grouse/partridge/Bonasa umbellus": - "animal, animate being, beast, brute, creature, fauna", - "beer glass": - "bottle", - "Airedale/Airedale terrier": - "dog, domestic dog, Canis familiaris", - "hot pot/hotpot": - "food, nutrient", - "barrow/garden cart/lawn cart/wheelbarrow": - "wheeled vehicle", - "sweatshirt": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "admiral": - "animal, animate being, beast, brute, creature, fauna", - "boa constrictor/Constrictor constrictor": - "animal, animate being, beast, brute, creature, fauna", - "pizza/pizza pie": - "food, nutrient", - "Border terrier": - "dog, domestic dog, Canis familiaris", - "chiton/coat-of-mail shell/sea cradle/polyplacophore": - "animal, animate being, beast, brute, creature, fauna", - "puffer/pufferfish/blowfish/globefish": - "animal, animate being, beast, brute, creature, fauna", - "toy poodle": - "dog, domestic dog, Canis familiaris", - "American chameleon/anole/Anolis carolinensis": - "animal, animate being, beast, brute, creature, fauna", - "thunder snake/worm snake/Carphophis amoenus": - "animal, animate being, beast, brute, creature, fauna", - "fur coat": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "Tibetan terrier/chrysanthemum dog": - "dog, domestic dog, Canis familiaris", - "ibex/Capra ibex": - "animal, animate being, beast, brute, creature, fauna", - "cricket": - "animal, animate being, beast, brute, creature, fauna", - "trench coat": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "ptarmigan": - "animal, animate being, beast, brute, creature, fauna", - "abaya": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "European fire salamander/Salamandra salamandra": - "animal, animate being, beast, brute, creature, fauna", - "hand-held computer/hand-held microcomputer": - "computer, computing machine, computing device, data processor, " - "electronic computer, information processing system", - "stole": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "mongoose": - "animal, animate being, beast, brute, creature, fauna", - "bull mastiff": - "dog, domestic dog, Canis familiaris", - "lynx/catamount": - "animal, animate being, beast, brute, creature, fauna", - "cab/hack/taxi/taxicab": - "wheeled vehicle", - "basset/basset hound": - "dog, domestic dog, Canis familiaris", - "sea anemone/anemone": - "animal, animate being, beast, brute, creature, fauna", - "fiddler crab": - "animal, animate being, beast, brute, creature, fauna", - "Indian cobra/Naja naja": - "animal, animate being, beast, brute, creature, fauna", - "black-footed ferret/ferret/Mustela nigripes": - "animal, animate being, beast, brute, creature, fauna", - "leaf beetle/chrysomelid": - "animal, animate being, beast, brute, creature, fauna", - "bald eagle/American eagle/Haliaeetus leucocephalus": - "animal, animate being, beast, brute, creature, fauna", - "Irish terrier": - "dog, domestic dog, Canis familiaris", - "beer bottle": - "bottle", - "Dungeness crab/Cancer magister": - "animal, animate being, beast, brute, creature, fauna", - "basenji": - "dog, domestic dog, Canis familiaris", - "grand piano/grand": - "musical instrument, instrument", - "black-and-tan coonhound": - "dog, domestic dog, Canis familiaris", - "giant panda/panda/panda bear/coon bear/Ailuropoda melanoleuca": - "animal, animate being, beast, brute, creature, fauna", - "capuchin/ringtail/Cebus capucinus": - "animal, animate being, beast, brute, creature, fauna", - "lycaenid/lycaenid butterfly": - "animal, animate being, beast, brute, creature, fauna", - "ladybug/ladybeetle/lady beetle/ladybird/ladybird beetle": - "animal, animate being, beast, brute, creature, fauna", - "tarantula": - "animal, animate being, beast, brute, creature, fauna", - "American Staffordshire terrier/Staffordshire terrier/American pit bull " - "terrier/pit bull terrier": - "dog, domestic dog, Canis familiaris", - "kite": - "animal, animate being, beast, brute, creature, fauna", - "red wine": - "food, nutrient", - "black grouse": - "animal, animate being, beast, brute, creature, fauna", - "porcupine/hedgehog": - "animal, animate being, beast, brute, creature, fauna", - "water jug": - "bottle", - "French loaf": - "food, nutrient", - "titi/titi monkey": - "animal, animate being, beast, brute, creature, fauna", - "Italian greyhound": - "animal, animate being, beast, brute, creature, fauna", - "police van/police wagon/paddy wagon/patrol wagon/wagon/black Maria": - "wheeled vehicle", - "pill bottle": - "bottle", - "iPod": - "electronic equipment", - "borzoi/Russian wolfhound": - "dog, domestic dog, Canis familiaris", - "tree frog/tree-frog": - "animal, animate being, beast, brute, creature, fauna", - "grey whale/gray whale/devilfish/Eschrichtius gibbosus/" - "Eschrichtius robustus": - "animal, animate being, beast, brute, creature, fauna", - "spotted salamander/Ambystoma maculatum": - "animal, animate being, beast, brute, creature, fauna", - "wine bottle": - "bottle", - "sulphur-crested cockatoo/Kakatoe galerita/Cacatua galerita": - "animal, animate being, beast, brute, creature, fauna", - "modem": - "electronic equipment", - "red-backed sandpiper/dunlin/Erolia alpina": - "animal, animate being, beast, brute, creature, fauna", - "gazelle": - "animal, animate being, beast, brute, creature, fauna", - "Eskimo dog/husky": - "dog, domestic dog, Canis familiaris", - "digital watch": - "timepiece, timekeeper, horologe", - "cheetah/chetah/Acinonyx jubatus": - "animal, animate being, beast, brute, creature, fauna", - "sombrero": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "seat belt/seatbelt": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "burrito": - "food, nutrient", - "slide rule/slipstick": - "computer, computing machine, computing device, data processor, " - "electronic computer, information processing system", - "Bouvier des Flandres/Bouviers des Flandres": - "dog, domestic dog, Canis familiaris", - "mask": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "Doberman/Doberman pinscher": - "dog, domestic dog, Canis familiaris", - "rhinoceros beetle": - "animal, animate being, beast, brute, creature, fauna", - "daisy": - "plant, flora, plant life", - "monitor": - "electronic equipment", - "Komodo dragon/Komodo lizard/dragon lizard/giant lizard/" - "Varanus komodoensis": - "animal, animate being, beast, brute, creature, fauna", - "garbage truck/dustcart": - "wheeled vehicle", - "Rhodesian ridgeback": - "dog, domestic dog, Canis familiaris", - "half track": - "wheeled vehicle", - "starfish/sea star": - "animal, animate being, beast, brute, creature, fauna", - "brambling/Fringilla montifringilla": - "animal, animate being, beast, brute, creature, fauna", - "convertible": - "wheeled vehicle", - "long-horned beetle/longicorn/longicorn beetle": - "animal, animate being, beast, brute, creature, fauna", - "academic gown/academic robe/judge's robe": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "computer keyboard/keypad": - "electronic equipment", - "Norwich terrier": - "dog, domestic dog, Canis familiaris", - "meerkat/mierkat": - "animal, animate being, beast, brute, creature, fauna", - "overskirt": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "toucan": - "animal, animate being, beast, brute, creature, fauna", - "apron": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "stopwatch/stop watch": - "timepiece, timekeeper, horologe", - "lab coat/laboratory coat": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "screen/CRT screen": - "electronic equipment", - "golfcart/golf cart": - "wheeled vehicle", - "digital clock": - "timepiece, timekeeper, horologe", - "Leonberg": - "dog, domestic dog, Canis familiaris", - "African crocodile/Nile crocodile/Crocodylus niloticus": - "animal, animate being, beast, brute, creature, fauna", - "lemon": - "edible fruit", - "Siberian husky": - "dog, domestic dog, Canis familiaris", - "bagel/beigel": - "food, nutrient", - "badger": - "animal, animate being, beast, brute, creature, fauna", - "scorpion": - "animal, animate being, beast, brute, creature, fauna", - "chow/chow chow": - "dog, domestic dog, Canis familiaris", - "Labrador retriever": - "dog, domestic dog, Canis familiaris", - "guenon/guenon monkey": - "animal, animate being, beast, brute, creature, fauna", - "military uniform": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "wood rabbit/cottontail/cottontail rabbit": - "animal, animate being, beast, brute, creature, fauna", - "jackfruit/jak/jack": - "edible fruit", - "oscilloscope/scope/cathode-ray oscilloscope/CRO": - "electronic equipment", - "jellyfish": - "animal, animate being, beast, brute, creature, fauna", - "Arctic fox/white fox/Alopex lagopus": - "animal, animate being, beast, brute, creature, fauna", - "feather boa/boa": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "bathing cap/swimming cap": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "cairn/cairn terrier": - "dog, domestic dog, Canis familiaris", - "German short-haired pointer": - "dog, domestic dog, Canis familiaris", - "hammerhead/hammerhead shark": - "animal, animate being, beast, brute, creature, fauna", - "violin/fiddle": - "musical instrument, instrument", - "green mamba": - "animal, animate being, beast, brute, creature, fauna", - "vizsla/Hungarian pointer": - "dog, domestic dog, Canis familiaris", - "moving van": - "wheeled vehicle", - "monarch/monarch butterfly/milkweed butterfly/Danaus plexippus": - "animal, animate being, beast, brute, creature, fauna", - "standard schnauzer": - "dog, domestic dog, Canis familiaris", - "tick": - "animal, animate being, beast, brute, creature, fauna", - "Gila monster/Heloderma suspectum": - "animal, animate being, beast, brute, creature, fauna", - "stingray": - "animal, animate being, beast, brute, creature, fauna", - "trilobite": - "animal, animate being, beast, brute, creature, fauna", - "knee pad": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "Boston bull/Boston terrier": - "dog, domestic dog, Canis familiaris", - "plate": - "food, nutrient", - "football helmet": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "electric ray/crampfish/numbfish/torpedo": - "animal, animate being, beast, brute, creature, fauna", - "sea urchin": - "animal, animate being, beast, brute, creature, fauna", - "ice cream/icecream": - "food, nutrient", - "red-breasted merganser/Mergus serrator": - "animal, animate being, beast, brute, creature, fauna", - "lesser panda/red panda/panda/bear cat/cat bear/Ailurus fulgens": - "animal, animate being, beast, brute, creature, fauna", - "barn spider/Araneus cavaticus": - "animal, animate being, beast, brute, creature, fauna", - "sea cucumber/holothurian": - "animal, animate being, beast, brute, creature, fauna", - "bulbul": - "animal, animate being, beast, brute, creature, fauna", - "quail": - "animal, animate being, beast, brute, creature, fauna", - "lacewing/lacewing fly": - "animal, animate being, beast, brute, creature, fauna", - "sulphur butterfly/sulfur butterfly": - "animal, animate being, beast, brute, creature, fauna", - "bicycle-built-for-two/tandem bicycle/tandem": - "wheeled vehicle", - "cheeseburger": - "food, nutrient", - "dial telephone/dial phone": - "electronic equipment", - "Australian terrier": - "dog, domestic dog, Canis familiaris", - "laptop/laptop computer": - "computer, computing machine, computing device, data processor, " - "electronic computer, information processing system", - "lorikeet": - "animal, animate being, beast, brute, creature, fauna", - "Bedlington terrier": - "dog, domestic dog, Canis familiaris", - "black widow/Latrodectus mactans": - "animal, animate being, beast, brute, creature, fauna", - "baboon": - "animal, animate being, beast, brute, creature, fauna", - "agama": - "animal, animate being, beast, brute, creature, fauna", - "Saluki/gazelle hound": - "dog, domestic dog, Canis familiaris", - "curly-coated retriever": - "dog, domestic dog, Canis familiaris", - "mobile home/manufactured home": - "wheeled vehicle", - "brassiere/bra/bandeau": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "sarong": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "Siamese cat/Siamese": - "animal, animate being, beast, brute, creature, fauna", - "accordion/piano accordion/squeeze box": - "musical instrument, instrument", - "malamute/malemute/Alaskan malamute": - "dog, domestic dog, Canis familiaris", - "Welsh springer spaniel": - "dog, domestic dog, Canis familiaris", - "robin/American robin/Turdus migratorius": - "animal, animate being, beast, brute, creature, fauna", - "Persian cat": - "animal, animate being, beast, brute, creature, fauna", - "sock": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "skunk/polecat/wood pussy": - "animal, animate being, beast, brute, creature, fauna", - "collie": - "dog, domestic dog, Canis familiaris", - "warthog": - "animal, animate being, beast, brute, creature, fauna", - "king penguin/Aptenodytes patagonica": - "animal, animate being, beast, brute, creature, fauna", - "Saint Bernard/St Bernard": - "dog, domestic dog, Canis familiaris", - "black swan/Cygnus atratus": - "animal, animate being, beast, brute, creature, fauna", - "axolotl/mud puppy/Ambystoma mexicanum": - "animal, animate being, beast, brute, creature, fauna", - "chocolate sauce/chocolate syrup": - "food, nutrient", - "Arabian camel/dromedary/Camelus dromedarius": - "animal, animate being, beast, brute, creature, fauna", - "frilled lizard/Chlamydosaurus kingi": - "animal, animate being, beast, brute, creature, fauna", - "shopping cart": - "wheeled vehicle", - "Brabancon griffon": - "dog, domestic dog, Canis familiaris", - "Sealyham terrier/Sealyham": - "dog, domestic dog, Canis familiaris", - "forklift": - "wheeled vehicle", - "ant/emmet/pismire": - "animal, animate being, beast, brute, creature, fauna", - "pop bottle/soda bottle": - "bottle", - "electric guitar": - "musical instrument, instrument", - "tape player": - "electronic equipment", - "hummingbird": - "animal, animate being, beast, brute, creature, fauna", - "Model T": - "wheeled vehicle", - "gown": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "fox squirrel/eastern fox squirrel/Sciurus niger": - "animal, animate being, beast, brute, creature, fauna", - "bikini/two-piece": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "redbone": - "dog, domestic dog, Canis familiaris", - "house finch/linnet/Carpodacus mexicanus": - "animal, animate being, beast, brute, creature, fauna", - "bighorn/bighorn sheep/cimarron/Rocky Mountain bighorn/Rocky Mountain " - "sheep/Ovis canadensis": - "animal, animate being, beast, brute, creature, fauna", - "carbonara": - "food, nutrient", - "English foxhound": - "dog, domestic dog, Canis familiaris", - "banjo": - "musical instrument, instrument", - "organ/pipe organ": - "musical instrument, instrument", - "American black bear/black bear/Ursus americanus/Euarctos americanus": - "animal, animate being, beast, brute, creature, fauna", - "impala/Aepyceros melampus": - "animal, animate being, beast, brute, creature, fauna", - "sea snake": - "animal, animate being, beast, brute, creature, fauna", - "coyote/prairie wolf/brush wolf/Canis latrans": - "animal, animate being, beast, brute, creature, fauna", - "silky terrier/Sydney silky": - "dog, domestic dog, Canis familiaris", - "Samoyed/Samoyede": - "dog, domestic dog, Canis familiaris", - "cello/violoncello": - "musical instrument, instrument", - "pineapple/ananas": - "edible fruit", - "damselfly": - "animal, animate being, beast, brute, creature, fauna", - "sax/saxophone": - "musical instrument, instrument", - "Chihuahua": - "dog, domestic dog, Canis familiaris", - "beagle": - "dog, domestic dog, Canis familiaris", - "harp": - "musical instrument, instrument", - "African elephant/Loxodonta africana": - "animal, animate being, beast, brute, creature, fauna", - "miniskirt/mini": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "dalmatian/coach dog/carriage dog": - "dog, domestic dog, Canis familiaris", - "strawberry": - "edible fruit", - "komondor": - "dog, domestic dog, Canis familiaris", - "hare": - "animal, animate being, beast, brute, creature, fauna", - "trailer truck/tractor trailer/trucking rig/rig/articulated lorry/semi": - "wheeled vehicle", - "goldfinch/Carduelis carduelis": - "animal, animate being, beast, brute, creature, fauna", - "prairie chicken/prairie grouse/prairie fowl": - "animal, animate being, beast, brute, creature, fauna", - "bearskin/busby/shako": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "sidewinder/horned rattlesnake/Crotalus cerastes": - "animal, animate being, beast, brute, creature, fauna", - "pug/pug-dog": - "dog, domestic dog, Canis familiaris", - "moped": - "wheeled vehicle", - "English springer/English springer spaniel": - "dog, domestic dog, Canis familiaris", - "malinois": - "dog, domestic dog, Canis familiaris", - "American coot/marsh hen/mud hen/water hen/Fulica americana": - "animal, animate being, beast, brute, creature, fauna", - "sea slug/nudibranch": - "animal, animate being, beast, brute, creature, fauna", - "steam locomotive": - "wheeled vehicle", - "cocker spaniel/English cocker spaniel/cocker": - "dog, domestic dog, Canis familiaris", - "upright/upright piano": - "musical instrument, instrument", - "goblet": - "bottle", - "grey fox/gray fox/Urocyon cinereoargenteus": - "animal, animate being, beast, brute, creature, fauna", - "Norwegian elkhound/elkhound": - "dog, domestic dog, Canis familiaris", - "Great Pyrenees": - "dog, domestic dog, Canis familiaris", - "rock crab/Cancer irroratus": - "animal, animate being, beast, brute, creature, fauna", - "Kerry blue terrier": - "dog, domestic dog, Canis familiaris", - "quill/quill pen": - "writing implement", - "terrapin": - "animal, animate being, beast, brute, creature, fauna", - "crane": - "animal, animate being, beast, brute, creature, fauna", - "gong/tam-tam": - "musical instrument, instrument", - "pajama/pyjama/pj's/jammies": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "bolo tie/bolo/bola tie/bola": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "Weimaraner": - "dog, domestic dog, Canis familiaris", - "water buffalo/water ox/Asiatic buffalo/Bubalus bubalis": - "animal, animate being, beast, brute, creature, fauna", - "Shetland sheepdog/Shetland sheep dog/Shetland": - "dog, domestic dog, Canis familiaris", - "tench/Tinca tinca": - "animal, animate being, beast, brute, creature, fauna", - "siamang/Hylobates syndactylus/Symphalangus syndactylus": - "animal, animate being, beast, brute, creature, fauna", - "loggerhead/loggerhead turtle/Caretta caretta": - "animal, animate being, beast, brute, creature, fauna", - "dung beetle": - "animal, animate being, beast, brute, creature, fauna", - "Granny Smith": - "edible fruit", - "Angora/Angora rabbit": - "animal, animate being, beast, brute, creature, fauna", - "dough": - "food, nutrient", - "hen": - "animal, animate being, beast, brute, creature, fauna", - "CD player": - "electronic equipment", - "howler monkey/howler": - "animal, animate being, beast, brute, creature, fauna", - "English setter": - "dog, domestic dog, Canis familiaris", - "West Highland white terrier": - "dog, domestic dog, Canis familiaris", - "pomegranate": - "edible fruit", - "timber wolf/grey wolf/gray wolf/Canis lupus": - "animal, animate being, beast, brute, creature, fauna", - "go-kart": - "wheeled vehicle", - "hornbill": - "animal, animate being, beast, brute, creature, fauna", - "Christmas stocking": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "alligator lizard": - "animal, animate being, beast, brute, creature, fauna", - "tabby/tabby cat": - "animal, animate being, beast, brute, creature, fauna", - "crash helmet": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "parking meter": - "timepiece, timekeeper, horologe", - "mantis/mantid": - "animal, animate being, beast, brute, creature, fauna", - "marmoset": - "animal, animate being, beast, brute, creature, fauna", - "Rottweiler": - "dog, domestic dog, Canis familiaris", - "whiskey jug": - "bottle", - "leopard/Panthera pardus": - "animal, animate being, beast, brute, creature, fauna", - "ram/tup": - "animal, animate being, beast, brute, creature, fauna", - "bison": - "animal, animate being, beast, brute, creature, fauna", - "horned viper/cerastes/sand viper/horned asp/Cerastes cornutus": - "animal, animate being, beast, brute, creature, fauna", - "anemone fish": - "animal, animate being, beast, brute, creature, fauna", - "sports car/sport car": - "wheeled vehicle", - "red fox/Vulpes vulpes": - "animal, animate being, beast, brute, creature, fauna", - "hog/pig/grunter/squealer/Sus scrofa": - "animal, animate being, beast, brute, creature, fauna", - "unicycle/monocycle": - "wheeled vehicle", - "macaque": - "animal, animate being, beast, brute, creature, fauna", - "drum/membranophone/tympan": - "musical instrument, instrument", - "king snake/kingsnake": - "animal, animate being, beast, brute, creature, fauna", - "affenpinscher/monkey pinscher/monkey dog": - "dog, domestic dog, Canis familiaris", - "custard apple": - "edible fruit", - "meat loaf/meatloaf": - "food, nutrient", - "American egret/great white heron/Egretta albus": - "animal, animate being, beast, brute, creature, fauna", - "whiptail/whiptail lizard": - "animal, animate being, beast, brute, creature, fauna", - "joystick": - "electronic equipment", - "spoonbill": - "animal, animate being, beast, brute, creature, fauna", - "espresso": - "food, nutrient", - "mortarboard": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "jersey/T-shirt/tee shirt": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "kimono": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "squirrel monkey/Saimiri sciureus": - "animal, animate being, beast, brute, creature, fauna", - "hartebeest": - "animal, animate being, beast, brute, creature, fauna", - "marimba/xylophone": - "musical instrument, instrument", - "ice lolly/lolly/lollipop/popsicle": - "food, nutrient", - "marmot": - "animal, animate being, beast, brute, creature, fauna", - "beaver": - "animal, animate being, beast, brute, creature, fauna", - "Afghan hound/Afghan": - "dog, domestic dog, Canis familiaris", - "keeshond": - "dog, domestic dog, Canis familiaris", - "eggnog": - "food, nutrient", - "cougar/puma/catamount/mountain lion/painter/panther/Felis concolor": - "animal, animate being, beast, brute, creature, fauna", - "bonnet/poke bonnet": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "koala/koala bear/kangaroo bear/native bear/Phascolarctos cinereus": - "animal, animate being, beast, brute, creature, fauna", - "trombone": - "musical instrument, instrument", - "fig": - "edible fruit", - "gorilla/Gorilla gorilla": - "animal, animate being, beast, brute, creature, fauna", - "Japanese spaniel": - "dog, domestic dog, Canis familiaris", - "Lakeland terrier": - "dog, domestic dog, Canis familiaris", - "tiger cat": - "animal, animate being, beast, brute, creature, fauna", - "streetcar/tram/tramcar/trolley/trolley car": - "wheeled vehicle", - "tiger beetle": - "animal, animate being, beast, brute, creature, fauna", - "Pembroke/Pembroke Welsh corgi": - "dog, domestic dog, Canis familiaris", - "tank/army tank/armored combat vehicle/armoured combat vehicle": - "wheeled vehicle", - "ringneck snake/ring-necked snake/ring snake": - "animal, animate being, beast, brute, creature, fauna", - "Mexican hairless": - "dog, domestic dog, Canis familiaris", - "great grey owl/great gray owl/Strix nebulosa": - "animal, animate being, beast, brute, creature, fauna", - "bloodhound/sleuthhound": - "dog, domestic dog, Canis familiaris", - "racer/race car/racing car": - "wheeled vehicle", - "armadillo": - "animal, animate being, beast, brute, creature, fauna", - "bulletproof vest": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "triceratops": - "animal, animate being, beast, brute, creature, fauna", - "hyena/hyaena": - "animal, animate being, beast, brute, creature, fauna", - "ox": - "animal, animate being, beast, brute, creature, fauna", - "beach wagon/station wagon/wagon/estate car/beach waggon/station " - "waggon/waggon": - "wheeled vehicle", - "wall clock": - "timepiece, timekeeper, horologe", - "mink": - "animal, animate being, beast, brute, creature, fauna", - "EntleBucher": - "dog, domestic dog, Canis familiaris", - "magpie": - "animal, animate being, beast, brute, creature, fauna", - "cockroach/roach": - "animal, animate being, beast, brute, creature, fauna", - "slug": - "animal, animate being, beast, brute, creature, fauna", - "albatross/mollymawk": - "animal, animate being, beast, brute, creature, fauna", - "Irish setter/red setter": - "dog, domestic dog, Canis familiaris", - "maraca": - "musical instrument, instrument", - "acoustic guitar": - "musical instrument, instrument", - "green snake/grass snake": - "animal, animate being, beast, brute, creature, fauna", - "yellow lady's slipper/yellow lady-slipper/Cypripedium " - "calceolus/Cypripedium parviflorum": - "plant, flora, plant life", - "jaguar/panther/Panthera onca/Felis onca": - "animal, animate being, beast, brute, creature, fauna", - "dugong/Dugong dugon": - "animal, animate being, beast, brute, creature, fauna", - "potpie": - "food, nutrient", - "Madagascar cat/ring-tailed lemur/Lemur catta": - "animal, animate being, beast, brute, creature, fauna", - "hay": - "food, nutrient", - "fire engine/fire truck": - "wheeled vehicle", - "water bottle": - "bottle", - "tiger/Panthera tigris": - "animal, animate being, beast, brute, creature, fauna", - "redshank/Tringa totanus": - "animal, animate being, beast, brute, creature, fauna", - "tailed frog/bell toad/ribbed toad/tailed toad/Ascaphus trui": - "animal, animate being, beast, brute, creature, fauna", - "Yorkshire terrier": - "dog, domestic dog, Canis familiaris", - "freight car": - "wheeled vehicle", - "patas/hussar monkey/Erythrocebus patas": - "animal, animate being, beast, brute, creature, fauna", - "Norfolk terrier": - "dog, domestic dog, Canis familiaris", - "ringlet/ringlet butterfly": - "animal, animate being, beast, brute, creature, fauna", - "leafhopper": - "animal, animate being, beast, brute, creature, fauna", - "polecat/fitch/foulmart/foumart/Mustela putorius": - "animal, animate being, beast, brute, creature, fauna", - "zebra": - "animal, animate being, beast, brute, creature, fauna", - "ground beetle/carabid beetle": - "animal, animate being, beast, brute, creature, fauna", - "hermit crab": - "animal, animate being, beast, brute, creature, fauna", - "spider monkey/Ateles geoffroyi": - "animal, animate being, beast, brute, creature, fauna", - "analog clock": - "timepiece, timekeeper, horologe", - "limpkin/Aramus pictus": - "animal, animate being, beast, brute, creature, fauna", - "Irish water spaniel": - "dog, domestic dog, Canis familiaris", - "ballpoint/ballpoint pen/ballpen/Biro": - "writing implement", - "papillon": - "dog, domestic dog, Canis familiaris", - "banded gecko": - "animal, animate being, beast, brute, creature, fauna", - "Greater Swiss Mountain dog": - "dog, domestic dog, Canis familiaris", - "Staffordshire bullterrier/Staffordshire bull terrier": - "dog, domestic dog, Canis familiaris", - "bustard": - "animal, animate being, beast, brute, creature, fauna", - "night snake/Hypsiglena torquata": - "animal, animate being, beast, brute, creature, fauna", - "lion/king of beasts/Panthera leo": - "animal, animate being, beast, brute, creature, fauna", - "wig": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "flamingo": - "animal, animate being, beast, brute, creature, fauna", - "isopod": - "animal, animate being, beast, brute, creature, fauna", - "barracouta/snoek": - "animal, animate being, beast, brute, creature, fauna", - "swimming trunks/bathing trunks": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "Ibizan hound/Ibizan Podenco": - "dog, domestic dog, Canis familiaris", - "sundial": - "timepiece, timekeeper, horologe", - "fly": - "animal, animate being, beast, brute, creature, fauna", - "otter": - "animal, animate being, beast, brute, creature, fauna", - "banana": - "edible fruit", - "nematode/nematode worm/roundworm": - "animal, animate being, beast, brute, creature, fauna", - "green lizard/Lacerta viridis": - "animal, animate being, beast, brute, creature, fauna", - "bassoon": - "musical instrument, instrument", - "cellular telephone/cellular phone/cellphone/cell/mobile phone": - "electronic equipment", - "vestment": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "ruddy turnstone/Arenaria interpres": - "animal, animate being, beast, brute, creature, fauna", - "white wolf/Arctic wolf/Canis lupus tundrarum": - "animal, animate being, beast, brute, creature, fauna", - "vine snake": - "animal, animate being, beast, brute, creature, fauna", - "pelican": - "animal, animate being, beast, brute, creature, fauna", - "Windsor tie": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "tow truck/tow car/wrecker": - "wheeled vehicle", - "dingo/warrigal/warragal/Canis dingo": - "animal, animate being, beast, brute, creature, fauna", - "Appenzeller": - "dog, domestic dog, Canis familiaris", - "kit fox/Vulpes macrotis": - "animal, animate being, beast, brute, creature, fauna", - "ostrich/Struthio camelus": - "animal, animate being, beast, brute, creature, fauna", - "gar/garfish/garpike/billfish/Lepisosteus osseus": - "animal, animate being, beast, brute, creature, fauna", - "little blue heron/Egretta caerulea": - "animal, animate being, beast, brute, creature, fauna", - "French horn/horn": - "musical instrument, instrument", - "red wolf/maned wolf/Canis rufus/Canis niger": - "animal, animate being, beast, brute, creature, fauna", - "Great Dane": - "dog, domestic dog, Canis familiaris", - "pretzel": - "food, nutrient", - "Dandie Dinmont/Dandie Dinmont terrier": - "dog, domestic dog, Canis familiaris", - "macaw": - "animal, animate being, beast, brute, creature, fauna", - "Chesapeake Bay retriever": - "dog, domestic dog, Canis familiaris", - "diaper/nappy/napkin": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "French bulldog": - "dog, domestic dog, Canis familiaris", - "indri/indris/Indri indri/Indri brevicaudatus": - "animal, animate being, beast, brute, creature, fauna", - "flute/transverse flute": - "musical instrument, instrument", - "ocarina/sweet potato": - "musical instrument, instrument", - "tractor": - "wheeled vehicle", - "goldfish/Carassius auratus": - "animal, animate being, beast, brute, creature, fauna", - "toy terrier": - "dog, domestic dog, Canis familiaris", - "Blenheim spaniel": - "dog, domestic dog, Canis familiaris", - "orange": - "edible fruit", - "motor scooter/scooter": - "wheeled vehicle", - "snowmobile": - "wheeled vehicle", - "mitten": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "brown bear/bruin/Ursus arctos": - "animal, animate being, beast, brute, creature, fauna", - "shower cap": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "Border collie": - "dog, domestic dog, Canis familiaris", - "hourglass": - "timepiece, timekeeper, horologe", - "briard": - "dog, domestic dog, Canis familiaris", - "European gallinule/Porphyrio porphyrio": - "animal, animate being, beast, brute, creature, fauna", - "leatherback turtle/leatherback/leathery turtle/Dermochelys coriacea": - "animal, animate being, beast, brute, creature, fauna", - "tusker": - "animal, animate being, beast, brute, creature, fauna", - "Shih-Tzu": - "dog, domestic dog, Canis familiaris", - "proboscis monkey/Nasalis larvatus": - "animal, animate being, beast, brute, creature, fauna", - "otterhound/otter hound": - "dog, domestic dog, Canis familiaris", - "African chameleon/Chamaeleo chamaeleon": - "animal, animate being, beast, brute, creature, fauna", - "lionfish": - "animal, animate being, beast, brute, creature, fauna", - "water snake": - "animal, animate being, beast, brute, creature, fauna", - "recreational vehicle/RV/R.V.": - "wheeled vehicle", - "Brittany spaniel": - "dog, domestic dog, Canis familiaris", - "rock python/rock snake/Python sebae": - "animal, animate being, beast, brute, creature, fauna", - "menu": - "food, nutrient", - "eel": - "animal, animate being, beast, brute, creature, fauna", - "peacock": - "animal, animate being, beast, brute, creature, fauna", - "Bernese mountain dog": - "dog, domestic dog, Canis familiaris", - "desktop computer": - "computer, computing machine, computing device, data processor, " - "electronic computer, information processing system", - "crayfish/crawfish/crawdad/crawdaddy": - "animal, animate being, beast, brute, creature, fauna", - "brain coral": - "animal, animate being, beast, brute, creature, fauna", - "oystercatcher/oyster catcher": - "animal, animate being, beast, brute, creature, fauna", - "killer whale/killer/orca/grampus/sea wolf/Orcinus orca": - "animal, animate being, beast, brute, creature, fauna", - "cup": - "bottle", - "giant schnauzer": - "dog, domestic dog, Canis familiaris", - "jean/blue jean/denim": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "wild boar/boar/Sus scrofa": - "animal, animate being, beast, brute, creature, fauna", - "steel drum": - "musical instrument, instrument", - "chime/bell/gong": - "musical instrument, instrument", - "snail": - "animal, animate being, beast, brute, creature, fauna", - "bluetick": - "dog, domestic dog, Canis familiaris", - "wire-haired fox terrier": - "dog, domestic dog, Canis familiaris", - "limousine/limo": - "wheeled vehicle", - "conch": - "animal, animate being, beast, brute, creature, fauna", - "Sussex spaniel": - "dog, domestic dog, Canis familiaris", - "Tibetan mastiff": - "dog, domestic dog, Canis familiaris", - "German shepherd/German shepherd dog/German police dog/alsatian": - "dog, domestic dog, Canis familiaris", - "schipperke": - "dog, domestic dog, Canis familiaris", - "goose": - "animal, animate being, beast, brute, creature, fauna", - "dhole/Cuon alpinus": - "animal, animate being, beast, brute, creature, fauna", - "soft-coated wheaten terrier": - "dog, domestic dog, Canis familiaris", - "oxcart": - "wheeled vehicle", - "flatworm/platyhelminth": - "animal, animate being, beast, brute, creature, fauna", - "clumber/clumber spaniel": - "dog, domestic dog, Canis familiaris", - "suit/suit of clothes": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "colobus/colobus monkey": - "animal, animate being, beast, brute, creature, fauna", - "Pomeranian": - "dog, domestic dog, Canis familiaris", - "mud turtle": - "animal, animate being, beast, brute, creature, fauna", - "cicada/cicala": - "animal, animate being, beast, brute, creature, fauna", - "orangutan/orang/orangutang/Pongo pygmaeus": - "animal, animate being, beast, brute, creature, fauna", - "Gordon setter": - "dog, domestic dog, Canis familiaris", - "panpipe/pandean pipe/syrinx": - "musical instrument, instrument", - "chambered nautilus/pearly nautilus/nautilus": - "animal, animate being, beast, brute, creature, fauna", - "harmonica/mouth organ/harp/mouth harp": - "musical instrument, instrument", - "snow leopard/ounce/Panthera uncia": - "animal, animate being, beast, brute, creature, fauna", - "cock": - "animal, animate being, beast, brute, creature, fauna", - "sloth bear/Melursus ursinus/Ursus ursinus": - "animal, animate being, beast, brute, creature, fauna", - "rock beauty/Holocanthus tricolor": - "animal, animate being, beast, brute, creature, fauna", - "hamster": - "animal, animate being, beast, brute, creature, fauna", - "miniature schnauzer": - "dog, domestic dog, Canis familiaris", - "horse cart/horse-cart": - "wheeled vehicle", - "African hunting dog/hyena dog/Cape hunting dog/Lycaon pictus": - "animal, animate being, beast, brute, creature, fauna", - "cabbage butterfly": - "animal, animate being, beast, brute, creature, fauna", - "great white shark/white shark/man-eater/man-eating shark/Carcharodon " - "carcharias": - "animal, animate being, beast, brute, creature, fauna", - "flat-coated retriever": - "dog, domestic dog, Canis familiaris", - "llama": - "animal, animate being, beast, brute, creature, fauna", - "mashed potato": - "food, nutrient", - "groenendael": - "dog, domestic dog, Canis familiaris", - "centipede": - "animal, animate being, beast, brute, creature, fauna", - "whippet": - "animal, animate being, beast, brute, creature, fauna", - "jacamar": - "animal, animate being, beast, brute, creature, fauna", - "standard poodle": - "dog, domestic dog, Canis familiaris", - "Pekinese/Pekingese/Peke": - "dog, domestic dog, Canis familiaris", - "poncho": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "tricycle/trike/velocipede": - "wheeled vehicle", - "wolf spider/hunting spider": - "animal, animate being, beast, brute, creature, fauna", - "Walker hound/Walker foxhound": - "dog, domestic dog, Canis familiaris", - "hognose snake/puff adder/sand viper": - "animal, animate being, beast, brute, creature, fauna", - "miniature pinscher": - "dog, domestic dog, Canis familiaris", - "kuvasz": - "dog, domestic dog, Canis familiaris", - "dowitcher": - "animal, animate being, beast, brute, creature, fauna", - "notebook/notebook computer": - "computer, computing machine, computing device, data processor, " - "electronic computer, information processing system", - "sorrel": - "animal, animate being, beast, brute, creature, fauna", - "chickadee": - "animal, animate being, beast, brute, creature, fauna", - "common iguana/iguana/Iguana iguana": - "animal, animate being, beast, brute, creature, fauna", - "snowplow/snowplough": - "wheeled vehicle", - "boxer": - "dog, domestic dog, Canis familiaris", - "diamondback/diamondback rattlesnake/Crotalus adamanteus": - "animal, animate being, beast, brute, creature, fauna", - "cornet/horn/trumpet/trump": - "musical instrument, instrument", - "Indian elephant/Elephas maximus": - "animal, animate being, beast, brute, creature, fauna", - "hippopotamus/hippo/river horse/Hippopotamus amphibius": - "animal, animate being, beast, brute, creature, fauna", - "ambulance": - "wheeled vehicle", - "weasel": - "animal, animate being, beast, brute, creature, fauna", - "cowboy hat/ten-gallon hat": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "American lobster/Northern lobster/Maine lobster/Homarus americanus": - "animal, animate being, beast, brute, creature, fauna", - "weevil": - "animal, animate being, beast, brute, creature, fauna", - "oboe/hautboy/hautbois": - "musical instrument, instrument", - "maillot": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "three-toed sloth/ai/Bradypus tridactylus": - "animal, animate being, beast, brute, creature, fauna", - "platypus/duckbill/duckbilled platypus/duck-billed " - "platypus/Ornithorhynchus anatinus": - "animal, animate being, beast, brute, creature, fauna", - "white stork/Ciconia ciconia": - "animal, animate being, beast, brute, creature, fauna", - "bee eater": - "animal, animate being, beast, brute, creature, fauna", - "Newfoundland/Newfoundland dog": - "dog, domestic dog, Canis familiaris", - "dragonfly/darning needle/devil's darning needle/sewing needle/snake " - "feeder/snake doctor/mosquito hawk/skeeter hawk": - "animal, animate being, beast, brute, creature, fauna", - "spiny lobster/langouste/rock lobster/crawfish/crayfish/sea crawfish": - "animal, animate being, beast, brute, creature, fauna", - "Old English sheepdog/bobtail": - "dog, domestic dog, Canis familiaris", - "partridge": - "animal, animate being, beast, brute, creature, fauna", - "Lhasa/Lhasa apso": - "dog, domestic dog, Canis familiaris", - "bee": - "animal, animate being, beast, brute, creature, fauna", - "American alligator/Alligator mississipiensis": - "animal, animate being, beast, brute, creature, fauna", - "harvestman/daddy longlegs/Phalangium opilio": - "animal, animate being, beast, brute, creature, fauna", - "common newt/Triturus vulgaris": - "animal, animate being, beast, brute, creature, fauna", - "water ouzel/dipper": - "animal, animate being, beast, brute, creature, fauna", - "jeep/landrover": - "wheeled vehicle", - "walking stick/walkingstick/stick insect": - "animal, animate being, beast, brute, creature, fauna", - "guacamole": - "food, nutrient", - "mountain bike/all-terrain bike/off-roader": - "wheeled vehicle", - "grasshopper/hopper": - "animal, animate being, beast, brute, creature, fauna", - "bullfrog/Rana catesbeiana": - "animal, animate being, beast, brute, creature, fauna", - "garden spider/Aranea diademata": - "animal, animate being, beast, brute, creature, fauna", - "amphibian/amphibious vehicle": - "wheeled vehicle", - "langur": - "animal, animate being, beast, brute, creature, fauna", - "vulture": - "animal, animate being, beast, brute, creature, fauna", - "wallaby/brush kangaroo": - "animal, animate being, beast, brute, creature, fauna", - "gibbon/Hylobates lar": - "animal, animate being, beast, brute, creature, fauna", - "bittern": - "animal, animate being, beast, brute, creature, fauna", - "ice bear/polar bear/Ursus Maritimus/Thalarctos maritimus": - "animal, animate being, beast, brute, creature, fauna", - "pickup/pickup truck": - "wheeled vehicle", - "fountain pen": - "writing implement", - "trifle": - "food, nutrient", - "pay-phone/pay-station": - "electronic equipment", - "Scotch terrier/Scottish terrier/Scottie": - "dog, domestic dog, Canis familiaris", - "web site/website/internet site/site": - "computer, computing machine, computing device, data processor, " - "electronic computer, information processing system", - "coho/cohoe/coho salmon/blue jack/silver salmon/Oncorhynchus kisutch": - "animal, animate being, beast, brute, creature, fauna", - "Maltese dog/Maltese terrier/Maltese": - "dog, domestic dog, Canis familiaris", - "coucal": - "animal, animate being, beast, brute, creature, fauna", - "tiger shark/Galeocerdo cuvieri": - "animal, animate being, beast, brute, creature, fauna", - "indigo bunting/indigo finch/indigo bird/Passerina cyanea": - "animal, animate being, beast, brute, creature, fauna", - "hotdog/hot dog/red hot": - "food, nutrient", - "minivan": - "wheeled vehicle", - "passenger car/coach/carriage": - "wheeled vehicle", - "sea lion": - "animal, animate being, beast, brute, creature, fauna", - "cardigan": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "jinrikisha/ricksha/rickshaw": - "wheeled vehicle", - "chimpanzee/chimp/Pan troglodytes": - "animal, animate being, beast, brute, creature, fauna", - "African grey/African gray/Psittacus erithacus": - "animal, animate being, beast, brute, creature, fauna", - "black and gold garden spider/Argiope aurantia": - "animal, animate being, beast, brute, creature, fauna", - "miniature poodle": - "dog, domestic dog, Canis familiaris", - "electric locomotive": - "wheeled vehicle", - "Cardigan/Cardigan Welsh corgi": - "dog, domestic dog, Canis familiaris", - "box turtle/box tortoise": - "animal, animate being, beast, brute, creature, fauna", - "sturgeon": - "animal, animate being, beast, brute, creature, fauna", - "Irish wolfhound": - "dog, domestic dog, Canis familiaris", - "maillot/tank suit": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "kelpie": - "dog, domestic dog, Canis familiaris", - "cassette player": - "electronic equipment", - "hoopskirt/crinoline": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "bow tie/bow-tie/bowtie": - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "junco/snowbird": - "animal, animate being, beast, brute, creature, fauna", - "Scottish deerhound/deerhound": - "dog, domestic dog, Canis familiaris", - "king crab/Alaska crab/Alaskan king crab/Alaska king crab/Paralithodes " - "camtschatica": - "animal, animate being, beast, brute, creature, fauna", - "Egyptian cat": - "animal, animate being, beast, brute, creature, fauna", - "jay": - "animal, animate being, beast, brute, creature, fauna", - "eft": - "animal, animate being, beast, brute, creature, fauna", - "garter snake/grass snake": - "animal, animate being, beast, brute, creature, fauna", - "wombat": - "animal, animate being, beast, brute, creature, fauna", - "consomme": - "food, nutrient", -} - -CATEGORIES = ( - "food, nutrient", - "edible fruit", - "electronic equipment", - "wheeled vehicle", - "dog, domestic dog, Canis familiaris", - "animal, animate being, beast, brute, creature, fauna", - "plant, flora, plant life", - "clothing, article of clothing, vesture, wear, wearable, habiliment", - "writing implement", - "computer, computing machine, computing device, data processor, electronic" - " computer, information processing system", - "timepiece, timekeeper, horologe", - "bottle", - "musical instrument, instrument", -) diff --git a/src/examples/voice/assistant_grpc_demo.py b/src/examples/voice/assistant_grpc_demo.py deleted file mode 100755 index 23456e19..00000000 --- a/src/examples/voice/assistant_grpc_demo.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""A demo of the Google Assistant GRPC recognizer.""" - -import logging - -import aiy.assistant.grpc -import aiy.audio -import aiy.voicehat - -logging.basicConfig( - level=logging.INFO, - format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s" -) - - -def main(): - status_ui = aiy.voicehat.get_status_ui() - status_ui.status('starting') - assistant = aiy.assistant.grpc.get_assistant() - button = aiy.voicehat.get_button() - with aiy.audio.get_recorder(): - while True: - status_ui.status('ready') - print('Press the button and speak') - button.wait_for_press() - status_ui.status('listening') - print('Listening...') - text, audio = assistant.recognize() - if text: - if text == 'goodbye': - status_ui.status('stopping') - print('Bye!') - break - print('You said "', text, '"') - if audio: - aiy.audio.play_audio(audio) - - -if __name__ == '__main__': - main() diff --git a/src/examples/voice/assistant_library_with_button_demo.py b/src/examples/voice/assistant_library_with_button_demo.py deleted file mode 100755 index e7ac93e8..00000000 --- a/src/examples/voice/assistant_library_with_button_demo.py +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Run a recognizer using the Google Assistant Library with button support. - -The Google Assistant Library has direct access to the audio API, so this Python -code doesn't need to record audio. Hot word detection "OK, Google" is supported. - -It is available for Raspberry Pi 2/3 only; Pi Zero is not supported. -""" - -import logging -import platform -import sys -import threading - -import aiy.assistant.auth_helpers -from aiy.assistant.library import Assistant -import aiy.voicehat -from google.assistant.library.event import EventType - -logging.basicConfig( - level=logging.INFO, - format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s" -) - - -class MyAssistant(object): - """An assistant that runs in the background. - - The Google Assistant Library event loop blocks the running thread entirely. - To support the button trigger, we need to run the event loop in a separate - thread. Otherwise, the on_button_pressed() method will never get a chance to - be invoked. - """ - - def __init__(self): - self._task = threading.Thread(target=self._run_task) - self._can_start_conversation = False - self._assistant = None - - def start(self): - """Starts the assistant. - - Starts the assistant event loop and begin processing events. - """ - self._task.start() - - def _run_task(self): - credentials = aiy.assistant.auth_helpers.get_assistant_credentials() - with Assistant(credentials) as assistant: - self._assistant = assistant - for event in assistant.start(): - self._process_event(event) - - def _process_event(self, event): - status_ui = aiy.voicehat.get_status_ui() - if event.type == EventType.ON_START_FINISHED: - status_ui.status('ready') - self._can_start_conversation = True - # Start the voicehat button trigger. - aiy.voicehat.get_button().on_press(self._on_button_pressed) - if sys.stdout.isatty(): - print('Say "OK, Google" or press the button, then speak. ' - 'Press Ctrl+C to quit...') - - elif event.type == EventType.ON_CONVERSATION_TURN_STARTED: - self._can_start_conversation = False - status_ui.status('listening') - - elif event.type == EventType.ON_END_OF_UTTERANCE: - status_ui.status('thinking') - - elif (event.type == EventType.ON_CONVERSATION_TURN_FINISHED - or event.type == EventType.ON_CONVERSATION_TURN_TIMEOUT - or event.type == EventType.ON_NO_RESPONSE): - status_ui.status('ready') - self._can_start_conversation = True - - elif event.type == EventType.ON_ASSISTANT_ERROR and event.args and event.args['is_fatal']: - sys.exit(1) - - def _on_button_pressed(self): - # Check if we can start a conversation. 'self._can_start_conversation' - # is False when either: - # 1. The assistant library is not yet ready; OR - # 2. The assistant library is already in a conversation. - if self._can_start_conversation: - self._assistant.start_conversation() - - -def main(): - if platform.machine() == 'armv6l': - print('Cannot run hotword demo on Pi Zero!') - exit(-1) - MyAssistant().start() - - -if __name__ == '__main__': - main() diff --git a/src/examples/voice/cloudspeech_demo.py b/src/examples/voice/cloudspeech_demo.py deleted file mode 100755 index 13eedfbf..00000000 --- a/src/examples/voice/cloudspeech_demo.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""A demo of the Google CloudSpeech recognizer.""" - -import aiy.audio -import aiy.cloudspeech -import aiy.voicehat - - -def main(): - recognizer = aiy.cloudspeech.get_recognizer() - recognizer.expect_phrase('turn off the light') - recognizer.expect_phrase('turn on the light') - recognizer.expect_phrase('blink') - - button = aiy.voicehat.get_button() - led = aiy.voicehat.get_led() - aiy.audio.get_recorder().start() - - while True: - print('Press the button and speak') - button.wait_for_press() - print('Listening...') - text = recognizer.recognize() - if not text: - print('Sorry, I did not hear you.') - else: - print('You said "', text, '"') - if 'turn on the light' in text: - led.set_state(aiy.voicehat.LED.ON) - elif 'turn off the light' in text: - led.set_state(aiy.voicehat.LED.OFF) - elif 'blink' in text: - led.set_state(aiy.voicehat.LED.BLINK) - elif 'goodbye' in text: - break - - -if __name__ == '__main__': - main() diff --git a/src/setup.py b/src/setup.py deleted file mode 100644 index d51fb433..00000000 --- a/src/setup.py +++ /dev/null @@ -1,56 +0,0 @@ -from setuptools import setup, find_packages - -setup( - name='aiy-projects-python', - version='1.0', - author='Peter Malkin', - author_email='petermalkin@google.com', - packages=find_packages(), - url="https://aiyprojects.withgoogle.com/", - license='LICENSE.txt', - description="AIY Python API", - data_files=[ - ('share/doc/aiy', ['README.md']), - ('share/doc/aiy/examples', [ - "examples/vision/buzzer/congratulations.track", - "examples/vision/buzzer/dramatic.track", - "examples/vision/buzzer/laughing.track", - "examples/vision/buzzer/sadtrombone.track", - "examples/vision/buzzer/tetris.track", - ]), - ], - install_requires=[ - 'google-assistant-grpc>=0.1.0', - 'google-cloud-speech>=0.30.0', - 'google-auth-oauthlib>=0.2.0', - 'pyasn1>=0.4.2', - 'grpcio>=1.7.0', - ], - python_requires='~=3.5', - scripts=[ - "examples/vision/annotator.py", - "examples/vision/buzzer/buzzer_demo.py", - "examples/vision/buzzer/buzzer_tracker_demo.py", - "examples/vision/dish_classifier.py", - "examples/vision/face_camera_trigger.py", - "examples/vision/face_detection.py", - "examples/vision/face_detection_camera.py", - "examples/vision/gpiozero/bonnet_button.py", - "examples/vision/gpiozero/button_example.py", - "examples/vision/gpiozero/led_example.py", - "examples/vision/gpiozero/servo_example.py", - "examples/vision/gpiozero/simple_button_example.py", - "examples/vision/image_classification.py", - "examples/vision/image_classification_camera.py", - "examples/vision/joy/joy_detection_demo.py", - "examples/vision/leds_example.py", - "examples/vision/object_detection.py", - "examples/vision/object_meter/object_meter.py", - "examples/vision/object_meter/wordnet_grouping/category_mapper.py", - "examples/vision/object_meter/wordnet_grouping/mapping_data.py", - "examples/voice/assistant_grpc_demo.py", - "examples/voice/assistant_library_demo.py", - "examples/voice/assistant_library_with_button_demo.py", - "examples/voice/assistant_library_with_local_commands_demo.py", - "examples/voice/cloudspeech_demo.py", - ]) diff --git a/systemd/alsa-init.service b/systemd/alsa-init.service deleted file mode 100644 index 0841d7c3..00000000 --- a/systemd/alsa-init.service +++ /dev/null @@ -1,16 +0,0 @@ -# Play 1 s of silence if asound.state does not exists so lxpanel's volumealsa -# can initialize properly. - -[Unit] -Description=alsa init service -ConditionPathExists=!/etc/alsa/state-daemon.conf -ConditionPathExists=!/var/lib/alsa/asound.state -DefaultDependencies=no -After=local-fs.target sysinit.target - -[Service] -Type=oneshot -ExecStart=-/usr/bin/aplay -q -d 1 -c 1 -t raw -f S32_LE /dev/zero - -[Install] -WantedBy=basic.target diff --git a/systemd/ntpdate.service b/systemd/ntpdate.service deleted file mode 100644 index 7db6d822..00000000 --- a/systemd/ntpdate.service +++ /dev/null @@ -1,14 +0,0 @@ -[Unit] -Description=Set time with ntpdate -After=network.target - -[Service] -# use -u to avoid conflict with ntpd -ExecStart=/usr/sbin/ntpdate -u pool.ntp.org - -# we may not have network yet, so retry until success -Restart=on-failure -RestartSec=60s - -[Install] -WantedBy=multi-user.target diff --git a/systemd/voice-recognizer.service b/systemd/voice-recognizer.service deleted file mode 100644 index db0191ba..00000000 --- a/systemd/voice-recognizer.service +++ /dev/null @@ -1,19 +0,0 @@ -# This service can be used to run your code automatically on startup. Look in -# HACKING.md for instructions on creating main.py and enabling it. - -[Unit] -Description=voice recognizer -After=network.target ntpdate.service - -[Service] -Environment=VIRTUAL_ENV=/home/pi/AIY-projects-python/env -Environment=PATH=/home/pi/AIY-projects-python/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -ExecStart=/home/pi/AIY-projects-python/env/bin/python3 -u src/main.py -WorkingDirectory=/home/pi/AIY-projects-python -StandardOutput=inherit -StandardError=inherit -Restart=always -User=pi - -[Install] -WantedBy=multi-user.target