From cd171d4c2fc592878c48a264828eaa951fee020d Mon Sep 17 00:00:00 2001 From: Shahnawaz Alam Date: Tue, 12 Apr 2022 14:14:38 -0400 Subject: [PATCH] EasyOCR example Added --- samples/PT37_opengpu_easyocr/README.md | 74 +++ .../easyocr_37_2_app/assets/.keep | 0 .../deployment_overrides/override_camera.json | 1 + .../graphs/easyocr_37_2_app/graph.json | 53 ++ .../easyocr_37_2_app/packages/.keep | 0 .../Dockerfile | 14 + .../descriptor.json | 11 + .../package.json | 30 + .../src/app.py | 76 +++ .../easyocr_example.ipynb | 549 ++++++++++++++++++ 10 files changed, 808 insertions(+) create mode 100644 samples/PT37_opengpu_easyocr/README.md create mode 100644 samples/PT37_opengpu_easyocr/easyocr_37_2_app/assets/.keep create mode 100644 samples/PT37_opengpu_easyocr/easyocr_37_2_app/deployment_overrides/override_camera.json create mode 100644 samples/PT37_opengpu_easyocr/easyocr_37_2_app/graphs/easyocr_37_2_app/graph.json create mode 100644 samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/.keep create mode 100644 samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/028663699634-easyocr_37_2_app-1.0/Dockerfile create mode 100644 samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/028663699634-easyocr_37_2_app-1.0/descriptor.json create mode 100644 samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/028663699634-easyocr_37_2_app-1.0/package.json create mode 100644 samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/028663699634-easyocr_37_2_app-1.0/src/app.py create mode 100644 samples/PT37_opengpu_easyocr/easyocr_example.ipynb diff --git a/samples/PT37_opengpu_easyocr/README.md b/samples/PT37_opengpu_easyocr/README.md new file mode 100644 index 0000000..f9f8209 --- /dev/null +++ b/samples/PT37_opengpu_easyocr/README.md @@ -0,0 +1,74 @@ +# Run EasyOCR library on AWS Panorama + +## Brief +In this guide, we show how to use easyocr library on the Panorama device. + +## Setup the application + +The dependencies folder included with this application has + +* The Dockerfile +* TensorRT 7.1 +* Cuda Enabled PyTorch for Jetson Xavier + +## Steps for setting this up + +* Step 1: Navigate to ./dependencies +* Step 2 : ``` sudo docker build -t pt:37 . ``` +* Step 3 : Open pytorch_example.ipynb and make sure you configure the following + * The Device ID + * The Camera node information +* Step 4 : Follow the steps outlined in the notebook + +## Special flags in package.json + +* Step 1 : Before you deploy the application, open PT37_opengpu_easyocr/easyocr_37_app/packages/(account-id)-easyocr_37_app-1.0/package.json +* Step 2 : Add the following flags to the package.json + +``` +"requirements": + [{ + "type" : "hardware_access", + "inferenceAccelerators": [ + { + "deviceType": "nvhost_gpu", + "sharedResourcePolicy": { + "policy" : "allow_all" + } + } + ] + }] +``` + +The assets should look something like this + +``` +"assets": [ + { + "name": "easyocr_37_2_app", + "implementations": [ + { + "type": "container", + "assetUri": "9a49a98784f4571adacc417f00942dac7ef2e34686eef21dca9fcb7f4b7ffd70.tar.gz", + "descriptorUri": "4bab130ec48eea84e072d9fe813b947e9d9610b2924099036b0165026a91d306.json", + "requirements": + [{ + "type" : "hardware_access", + "inferenceAccelerators": [ + { + "deviceType": "nvhost_gpu", + "sharedResourcePolicy": { + "policy" : "allow_all" + } + } + ] + }] + } + ] + } +], +``` + +# Debugging + +If you encounter issues with deploying from this, once the application is uploaded to the cloud, you can use the graph.json and deploy using the Panorama console as well \ No newline at end of file diff --git a/samples/PT37_opengpu_easyocr/easyocr_37_2_app/assets/.keep b/samples/PT37_opengpu_easyocr/easyocr_37_2_app/assets/.keep new file mode 100644 index 0000000..e69de29 diff --git a/samples/PT37_opengpu_easyocr/easyocr_37_2_app/deployment_overrides/override_camera.json b/samples/PT37_opengpu_easyocr/easyocr_37_2_app/deployment_overrides/override_camera.json new file mode 100644 index 0000000..4409f95 --- /dev/null +++ b/samples/PT37_opengpu_easyocr/easyocr_37_2_app/deployment_overrides/override_camera.json @@ -0,0 +1 @@ +{"nodeGraphOverrides": {"envelopeVersion": "2021-01-01", "packages": [{"name": "028663699634::test_rtsp_camera_lab3", "version": "2.0"}], "nodes": [{"name": "test_rtsp_camera_lab3", "interface": "028663699634::test_rtsp_camera_lab3.test_rtsp_camera_lab3", "overridable": true, "overrideMandatory": false, "launch": "onAppStart"}], "nodeOverrides": [{"replace": "front_door_camera", "with": [{"name": "test_rtsp_camera_lab3"}]}]}} \ No newline at end of file diff --git a/samples/PT37_opengpu_easyocr/easyocr_37_2_app/graphs/easyocr_37_2_app/graph.json b/samples/PT37_opengpu_easyocr/easyocr_37_2_app/graphs/easyocr_37_2_app/graph.json new file mode 100644 index 0000000..6860e55 --- /dev/null +++ b/samples/PT37_opengpu_easyocr/easyocr_37_2_app/graphs/easyocr_37_2_app/graph.json @@ -0,0 +1,53 @@ +{ + "nodeGraph": { + "envelopeVersion": "2021-01-01", + "packages": [ + { + "name": "028663699634::easyocr_37_2_app", + "version": "1.0" + }, + { + "name": "panorama::hdmi_data_sink", + "version": "1.0" + }, + { + "name": "panorama::abstract_rtsp_media_source", + "version": "1.0" + } + ], + "nodes": [ + { + "name": "front_door_camera", + "interface": "panorama::abstract_rtsp_media_source.rtsp_v1_interface", + "overridable": true, + "launch": "onAppStart", + "decorator": { + "title": "Camera front_door_camera", + "description": "Default description for camera front_door_camera" + } + }, + { + "name": "easyocr_37_2_app_node", + "interface": "028663699634::easyocr_37_2_app.easyocr_37_2_app_interface", + "overridable": false, + "launch": "onAppStart" + }, + { + "name": "output_node", + "interface": "panorama::hdmi_data_sink.hdmi0", + "overridable": true, + "launch": "onAppStart" + } + ], + "edges": [ + { + "producer": "front_door_camera.video_out", + "consumer": "easyocr_37_2_app_node.video_in" + }, + { + "producer": "easyocr_37_2_app_node.video_out", + "consumer": "output_node.video_in" + } + ] + } +} \ No newline at end of file diff --git a/samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/.keep b/samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/.keep new file mode 100644 index 0000000..e69de29 diff --git a/samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/028663699634-easyocr_37_2_app-1.0/Dockerfile b/samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/028663699634-easyocr_37_2_app-1.0/Dockerfile new file mode 100644 index 0000000..e6a83f9 --- /dev/null +++ b/samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/028663699634-easyocr_37_2_app-1.0/Dockerfile @@ -0,0 +1,14 @@ +# Use the pre-built docker image attached in this example by doing ```docker load --input panoramasdk_gpu_access_base_image.tar.gz``` or build the base image yourself using the dockerfile provided under /docker/Dockerfile +FROM pt:37 +RUN apt-get update && apt-get install -y libglib2.0-0 +RUN python3.7 -m pip install boto3 +COPY src /panorama +# COPY saved_model_trt_fp16 /panorama/saved_model_trt_fp16 + +# For easyOCR +RUN pip install opencv-python-headless==4.5.4.60 +RUN pip install easyocr +RUN pip install -U scikit-image==0.17.2 +RUN python3 -c 'import easyocr; easyocr.Reader(["en"], gpu=False);' +RUN chmod -R 777 /root/ +RUN ls /root/.EasyOCR/model/ -lrt diff --git a/samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/028663699634-easyocr_37_2_app-1.0/descriptor.json b/samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/028663699634-easyocr_37_2_app-1.0/descriptor.json new file mode 100644 index 0000000..26503dd --- /dev/null +++ b/samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/028663699634-easyocr_37_2_app-1.0/descriptor.json @@ -0,0 +1,11 @@ +{ + "runtimeDescriptor": + { + "envelopeVersion": "2021-01-01", + "entry": + { + "path": "python3.7", + "name": "/panorama/src/app.py" + } + } +} diff --git a/samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/028663699634-easyocr_37_2_app-1.0/package.json b/samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/028663699634-easyocr_37_2_app-1.0/package.json new file mode 100644 index 0000000..e0e5035 --- /dev/null +++ b/samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/028663699634-easyocr_37_2_app-1.0/package.json @@ -0,0 +1,30 @@ +{ + "nodePackage": { + "envelopeVersion": "2021-01-01", + "name": "easyocr_37_2_app", + "version": "1.0", + "description": "Default description for package easyocr_37_app", + "assets": [ + + ], + "interfaces": [ + { + "name": "easyocr_37_2_app_interface", + "category": "business_logic", + "asset": "easyocr_37_2_app", + "inputs": [ + { + "name": "video_in", + "type": "media" + } + ], + "outputs": [ + { + "name": "video_out", + "type": "media" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/028663699634-easyocr_37_2_app-1.0/src/app.py b/samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/028663699634-easyocr_37_2_app-1.0/src/app.py new file mode 100644 index 0000000..22b797e --- /dev/null +++ b/samples/PT37_opengpu_easyocr/easyocr_37_2_app/packages/028663699634-easyocr_37_2_app-1.0/src/app.py @@ -0,0 +1,76 @@ +import logging +from logging.handlers import RotatingFileHandler + +import easyocr +import numpy as np +import panoramasdk + + +class Application(panoramasdk.node): + def __init__(self): + """Initializes the application's attributes with parameters from the interface, and default values.""" + self.ocr_detector = easyocr.Reader(["en"], gpu=True) + + logger.info('Initialiation complete.') + + + def process_streams(self): + """Processes one frame of video from one or more video streams.""" + self.frame_num += 1 + logger.debug(self.frame_num) + + # Loop through attached video streams + streams = self.inputs.video_in.get() + for stream in streams: + self.process_media(stream) + + self.outputs.video_out.put(streams) + + def process_media(self, stream): + """Runs inference on a frame of video.""" + image_data = stream.image + logger.debug(image_data.shape) + + # Cropping image to focus on region to read OCR (top left region with 100*100 pixels) + cropped_image = image_data[:100, :100, :] + + # Process results (object deteciton) + self.process_results(cropped_image, stream) + + def process_results(self, cropped_image, stream): + """Processes output tensors from a computer vision model and annotates a video frame.""" + if any(dim_size==0 for dim_size in cropped_image.shape): + logger.warning("Image size too small") + return + + list_of_words_detected = self.ocr_detector.readtext(cropped_image, detail=0) + + drift = 0.05 + + # Logging and printing first 5 words + for idx, word in enumerate(list_of_words_detected[:5]): + logger.info('word #{} = {}'.format(str(idx), word)) + stream.add_label('word #{} = {}'.format(str(idx), word), 0.1, 0.1*(drift*idx)) + +def get_logger(name=__name__,level=logging.INFO): + logger = logging.getLogger(name) + logger.setLevel(level) + handler = RotatingFileHandler("/opt/aws/panorama/logs/app.log", maxBytes=100000000, backupCount=2) + formatter = logging.Formatter(fmt='%(asctime)s %(levelname)-8s %(message)s', + datefmt='%Y-%m-%d %H:%M:%S') + handler.setFormatter(formatter) + logger.addHandler(handler) + return logger + +def main(): + try: + logger.info("INITIALIZING APPLICATION") + app = Application() + logger.info("PROCESSING STREAMS") + while True: + app.process_streams() + except: + logger.exception('Exception during processing loop.') + +logger = get_logger(level=logging.INFO) +main() diff --git a/samples/PT37_opengpu_easyocr/easyocr_example.ipynb b/samples/PT37_opengpu_easyocr/easyocr_example.ipynb new file mode 100644 index 0000000..1ec7f2b --- /dev/null +++ b/samples/PT37_opengpu_easyocr/easyocr_example.ipynb @@ -0,0 +1,549 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "cffd59b9", + "metadata": {}, + "source": [ + "# EasyOCR Sample Application\n" + ] + }, + { + "cell_type": "markdown", + "id": "8a2a3ae2", + "metadata": {}, + "source": [ + "# Prerequisites (DO NOT SKIP)" + ] + }, + { + "cell_type": "markdown", + "id": "9aaddd01", + "metadata": {}, + "source": [ + "1. In a terminal session on this Jupyter notebook server, run `aws configure`. This allows this notebook server to access Panorama resources and deploy applications on your behalf.\n", + "\n", + "2. This notebook works best in the Test Utility. Please see [here](https://github.com/aws-samples/aws-panorama-samples/blob/main/docs/EnvironmentSetup.md) to set it up \n", + "\n", + "3. **PLEASE READ THE [README](README.md) INCLUDE WITH THIS BEFORE YOU START USING THIS NOTEBOOK**" + ] + }, + { + "cell_type": "markdown", + "id": "b1c2f6f8", + "metadata": {}, + "source": [ + "# Set up" + ] + }, + { + "cell_type": "markdown", + "id": "352b4749", + "metadata": {}, + "source": [ + "Import libraries for use with this notebook environment, you do not need these libraries when you write your application code." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1183276e", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "import os\n", + "import time\n", + "import json\n", + "\n", + "import boto3\n", + "import sagemaker\n", + "\n", + "import matplotlib.pyplot as plt\n", + "from IPython.core.magic import register_cell_magic\n", + "\n", + "sys.path.insert( 0, os.path.abspath( \"../common/test_utility\" ) )\n", + "import panorama_test_utility\n", + "\n", + "# instantiate boto3 clients\n", + "s3_client = boto3.client('s3')\n", + "panorama_client = boto3.client('panorama', region_name = 'us-west-2')\n", + "\n", + "# configure matplotlib\n", + "%matplotlib inline\n", + "plt.rcParams[\"figure.figsize\"] = (20,20)\n", + "\n", + "# register custom magic command\n", + "@register_cell_magic\n", + "def save_cell(line, cell):\n", + " 'Save python code block to a file'\n", + " with open(line, 'wt') as fd:\n", + " fd.write(cell)" + ] + }, + { + "cell_type": "markdown", + "id": "00f12da5", + "metadata": { + "tags": [] + }, + "source": [ + "## Notebook parameters\n", + "Global constants that help the notebook create Panorama resources on your behalf." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1a73ca51", + "metadata": {}, + "outputs": [], + "source": [ + "# Device ID, should look like: device-oc66nax4cgzwhyuaeyifrqowue\n", + "DEVICE_ID = input( 'DEVICE_ID (format: device-*)' ).strip()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82721929", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# application name\n", + "app_name = 'easyocr_37_2_app'\n", + "\n", + "## package names and node names\n", + "code_package_name = 'easyocr_37_2_app'\n", + "camera_node_name = 'abstract_rtsp_media_source'\n", + "\n", + "# AWS account ID\n", + "account_id = boto3.client(\"sts\").get_caller_identity()[\"Account\"]\n" + ] + }, + { + "cell_type": "markdown", + "id": "d1034c1e", + "metadata": {}, + "source": [ + "## Set up application\n", + "\n", + "Every application uses the creator's AWS Account ID as the prefix to uniquely identifies the application resources. Running `panorama-cli import-application` replaces the generic account Id with your account Id." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96ef4328", + "metadata": {}, + "outputs": [], + "source": [ + "!cd ./easyocr_37_2_app && panorama-cli import-application" + ] + }, + { + "cell_type": "markdown", + "id": "36dd2241-a253-4651-af60-b3f8fbe2a92d", + "metadata": {}, + "source": [ + "## Download Depedencies and Artifacts (One Time Download)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23c125d8-9cc2-48d8-a1bc-b947c1725eba", + "metadata": {}, + "outputs": [], + "source": [ + "panorama_test_utility.download_artifacts_gpu_sample('pytorch', account_id)" + ] + }, + { + "cell_type": "markdown", + "id": "4c78dda7-4135-4b43-9880-8a4ea03663b8", + "metadata": {}, + "source": [ + "### Build Docker image from Dockerfile" + ] + }, + { + "cell_type": "markdown", + "id": "01a4b4d1-baaa-4cf0-9075-a5d9963e787f", + "metadata": {}, + "source": [ + "Open a terminal, go to ./yolov5s_37_2_opengpu/dependencies/docker and run\n", + "\n", + "```sudo docker build -t pt:37 . ```" + ] + }, + { + "cell_type": "markdown", + "id": "4df1a26a-e84b-48f3-a2c6-b289a5a0b4d1", + "metadata": { + "tags": [] + }, + "source": [ + "## Update camera streams\n", + "\n", + "In the AWS Panorama console, you can select the camera streams, but programmatically, you need to define the camera stream info for the cameras you are using with the app.\n", + "\n", + "We used an ```abstract data source``` here, usually this lets you select the pre-created camera source from the console. But programatically, we have to do the following steps\n", + "\n", + "\n", + "- Create Camera\n", + "- Create Override json file\n", + "- Include the Override json file while are deploying the application" + ] + }, + { + "cell_type": "markdown", + "id": "c217bb6c-a15f-4ec8-b00b-b91fca369180", + "metadata": {}, + "source": [ + "### Create New Camera\n", + "\n", + "Because we are using an ```abstract_rtsp_media_source```, we have to create a camera before we can use the ```abstract_rtsp_media_source```\n", + "\n", + "**NOTE** : Update your RTSP Info in the next cell, Username, Password and RTSP Stream URL" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e808c80f-6778-4e7c-a906-e02f2a3a4909", + "metadata": {}, + "outputs": [], + "source": [ + "CAMERA_NAME = \"test_rtsp_camera_lab3\"\n", + "\n", + "CAMERA_CREDS = '{\"Username\":\"root\",\"Password\":\"Aws2017!\",\"StreamUrl\": \"rtsp://10.92.202.65/onvif-media/media.amp?profile=profile_1_h264&sessiontimeout=60&streamtype=unicast\"}'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53af9488-5e7c-4bb9-ba65-feaf06be8a4e", + "metadata": {}, + "outputs": [], + "source": [ + "res = !aws panorama create-node-from-template-job --template-type RTSP_CAMERA_STREAM \\\n", + " --output-package-name {CAMERA_NAME} \\\n", + " --output-package-version '3.0' \\\n", + " --node-name {CAMERA_NAME} \\\n", + " --template-parameters '{CAMERA_CREDS}'\n", + "\n", + "# FIXME : camera node creation fails if it already exists.\n", + "# Should either ignore the already-exist error, or delete the node at the end of this notebook\n", + "\n", + "res = ''.join(res)\n", + "print(res)\n", + "res_json = json.loads(res)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b94dc937-f62a-49a1-ae86-315b9a0c3266", + "metadata": {}, + "outputs": [], + "source": [ + "!aws panorama describe-node-from-template-job --job-id {res_json['JobId']}" + ] + }, + { + "cell_type": "markdown", + "id": "62921b7b-0669-45cb-b0b3-18087fc9be82", + "metadata": {}, + "source": [ + "## Overriding camera node" + ] + }, + { + "cell_type": "markdown", + "id": "672873ea", + "metadata": {}, + "source": [ + "If you want to override the camera configuration at deployment (for ex. deploy to another site) you can provide a deployment time override. Go to `people_counter_app/deployment_overrides/override_camera.json` file and replace YOUR_AWS_ACCOUNT_ID with your ACCOUNT_ID and YOUR_CAMERA_NAME with your camera name." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36e9c66f-3f32-4984-b5d8-be69251f022b", + "metadata": {}, + "outputs": [], + "source": [ + "# Update Account ID\n", + "with open( f\"./{app_name}/deployment_overrides/override_camera.json\", \"r\" ) as fd:\n", + " override_json = json.load(fd)\n", + "\n", + "override_json['nodeGraphOverrides']['packages'][0]['name'] = '{}::{}'.format(account_id, CAMERA_NAME)\n", + "override_json['nodeGraphOverrides']['nodes'][0]['name'] = CAMERA_NAME\n", + "override_json['nodeGraphOverrides']['nodes'][0]['interface'] = '{}::{}.{}'.format(account_id, CAMERA_NAME, CAMERA_NAME) \n", + "override_json['nodeGraphOverrides']['nodeOverrides'][0]['with'][0]['name'] = CAMERA_NAME \n", + "\n", + "with open( f\"./{app_name}/deployment_overrides/override_camera.json\", \"w\") as fd:\n", + " json.dump(override_json, fd)" + ] + }, + { + "cell_type": "markdown", + "id": "337238ff", + "metadata": {}, + "source": [ + "### Build app with container" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "afc63216", + "metadata": {}, + "outputs": [], + "source": [ + "container_asset_name = 'easyocr_37_2_app'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25f5b4b1", + "metadata": {}, + "outputs": [], + "source": [ + "%%capture captured_output\n", + "\n", + "# Building container image.This process takes time (5min ~ 10min)\n", + "# FIXME : without %%capture, browser tab crashes because of too much output from the command.\n", + "\n", + "!cd ./easyocr_37_2_app && panorama-cli build \\\n", + " --container-asset-name {container_asset_name} \\\n", + " --package-path packages/{account_id}-{code_package_name}-1.0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81c66f7d-70b6-411c-b86f-5256a47d8516", + "metadata": {}, + "outputs": [], + "source": [ + "stdout_lines = captured_output.stdout.splitlines()\n", + "stderr_lines = captured_output.stderr.splitlines()\n", + "print(\" :\")\n", + "print(\" :\")\n", + "for line in stdout_lines[-30:] + stderr_lines[-30:]:\n", + " print(line)" + ] + }, + { + "cell_type": "markdown", + "id": "6e7837df-f283-4f8a-b338-4757473b951b", + "metadata": {}, + "source": [ + "### Special flags in package.json\n", + "\n", + "* Step 1 : Before you deploy the application, open PT37_opengpu/easyocr_37_2_app/packages/(account-id)-easyocr_37_2_app-1.0/package.json\n", + "* Step 2 : Add the following flags to the package.json\n", + "\n", + "```\n", + "\"requirements\": \n", + " [{\n", + " \"type\" : \"hardware_access\",\n", + " \"inferenceAccelerators\": [ \n", + " {\n", + " \"deviceType\": \"nvhost_gpu\",\n", + " \"sharedResourcePolicy\": {\n", + " \"policy\" : \"allow_all\"\n", + " }\n", + " }\n", + " ]\n", + " }]\n", + "```\n", + "\n", + "The assets should look something like this\n", + "\n", + "```\n", + "\"assets\": [\n", + " {\n", + " \"name\": \"easyocr_37_2_app\",\n", + " \"implementations\": [\n", + " {\n", + " \"type\": \"container\",\n", + " \"assetUri\": \"9a49a98784f4571adacc417f00942dac7ef2e34686eef21dca9fcb7f4b7ffd70.tar.gz\",\n", + " \"descriptorUri\": \"4bab130ec48eea84e072d9fe813b947e9d9610b2924099036b0165026a91d306.json\",\n", + " \"requirements\": \n", + " [{\n", + " \"type\" : \"hardware_access\",\n", + " \"inferenceAccelerators\": [ \n", + " {\n", + " \"deviceType\": \"nvhost_gpu\",\n", + " \"sharedResourcePolicy\": {\n", + " \"policy\" : \"allow_all\"\n", + " }\n", + " }\n", + " ]\n", + " }]\n", + " }\n", + " ]\n", + " }\n", + "],\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "f017081e", + "metadata": {}, + "source": [ + "### Upload application to Panorama for deploying to devices" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e8bc1f3b", + "metadata": {}, + "outputs": [], + "source": [ + "# This step takes some time, depending on your network environment.\n", + "!cd ./easyocr_37_2_app && pwd && panorama-cli package-application" + ] + }, + { + "cell_type": "markdown", + "id": "4a6794d7", + "metadata": {}, + "source": [ + "### Ready for deploying to a device\n", + "\n", + "Congrats! Your app is now ready to deploy to a device. Next, you can continue in this notebook to deploy the app programmatically or you can go to the Panorama console and deploying using the AWS Console. The console makes it easier to select camera streams and select the devices you want to deploy to. Programmatic deployment is faster to complete and easier to automate." + ] + }, + { + "cell_type": "markdown", + "id": "e8e572a8", + "metadata": {}, + "source": [ + "# Deploy app to device" + ] + }, + { + "cell_type": "markdown", + "id": "b59f04c5", + "metadata": {}, + "source": [ + "Let's make sure the device we are deploying to is available." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4cd42dc", + "metadata": {}, + "outputs": [], + "source": [ + "response = panorama_client.describe_device(\n", + " DeviceId= DEVICE_ID\n", + ")\n", + "\n", + "print('You are deploying to Device: {}'.format(response['Name']))" + ] + }, + { + "cell_type": "markdown", + "id": "a09b151f", + "metadata": {}, + "source": [ + "## Deploy app\n", + "\n", + "You are ready to deploy your app. Below, you can see an example of how to use the AWS CLI to deploy the app. Alternatively, you can use the boto3 SDK as you did above for getting the device information." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "db49ffc1-55fc-4fe9-8866-5888ea479f0c", + "metadata": {}, + "outputs": [], + "source": [ + "with open(f\"./{app_name}/graphs/{app_name}/graph.json\") as fd:\n", + " manifest_payload = \"'%s'\" % json.dumps({\"PayloadData\":json.dumps(json.load(fd))})\n", + " \n", + "with open(f\"./{app_name}/deployment_overrides/override_camera.json\") as fd:\n", + " override_payload = \"'%s'\" % json.dumps({\"PayloadData\":json.dumps(json.load(fd))})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27710523-c8b2-471d-97c4-5405e4a7fa7e", + "metadata": {}, + "outputs": [], + "source": [ + "role_arn = panorama_test_utility.resolve_sm_role()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d41609c9-1612-4da7-b1d5-4c6e5512f895", + "metadata": {}, + "outputs": [], + "source": [ + "res = !aws panorama create-application-instance \\\n", + " --name {app_name} \\\n", + " --default-runtime-context-device {DEVICE_ID} \\\n", + " --manifest-payload {manifest_payload} \\\n", + " --manifest-overrides-payload {override_payload}\n", + " --runtime-role-arn {role_arn}\n", + "\n", + "res = ''.join(res)\n", + "print(res)\n", + "res_json = json.loads(res)" + ] + }, + { + "cell_type": "markdown", + "id": "ad70b33a", + "metadata": {}, + "source": [ + "# Clean up" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "43b45a9b", + "metadata": {}, + "outputs": [], + "source": [ + "panorama_test_utility.remove_application( DEVICE_ID, app_id )" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}