

終止支援通知：2026 年 5 月 31 日， AWS 將終止對 的支援 AWS Panorama。2026 年 5 月 31 日之後，您將無法再存取 AWS Panorama 主控台或 AWS Panorama 資源。如需詳細資訊，請參閱[AWS Panorama 終止支援](https://docs.aws.amazon.com/panorama/latest/dev/panorama-end-of-support.html)。

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 開發 AWS Panorama 應用程式
<a name="gettingstarted-sample"></a>

您可以使用範例應用程式來了解 AWS Panorama 應用程式結構，以及做為您自己應用程式的起點。

下圖顯示在 AWS Panorama 設備上執行之應用程式的主要元件。應用程式程式碼使用 AWS Panorama 應用程式 SDK 來取得映像，並與模型互動，而模型無法直接存取。應用程式會將視訊輸出至已連線的顯示器，但不會將影像資料傳送到本機網路外部。

![\[\]](http://docs.aws.amazon.com/zh_tw/panorama/latest/dev/images/sample-app.png)


在此範例中，應用程式使用 AWS Panorama 應用程式開發套件從攝影機取得影片影格、預先處理影片資料，並將資料傳送至偵測物件的電腦視覺模型。應用程式會在連接至設備的 HDMI 顯示器上顯示結果。

**Topics**
+ [應用程式資訊清單](#gettingstarted-sample-manifest)
+ [使用範例應用程式建置](#gettingstarted-sample-adapting)
+ [變更電腦視覺模型](#gettingstarted-sample-model)
+ [預先處理映像](#gettingstarted-sample-preprocessing)
+ [使用適用於 Python 的 SDK 上傳指標](#gettingstarted-sample-metrics)
+ [後續步驟](#gettingstarted-sample-nextsteps)

## 應用程式資訊清單
<a name="gettingstarted-sample-manifest"></a>

應用程式資訊清單是在 `graph.json` `graphs` 資料夾中名為 的檔案。資訊清單會定義應用程式的元件，即套件、節點和邊緣。

套件是應用程式程式碼、模型、攝影機和顯示器的程式碼、組態和二進位檔案。範例應用程式使用 4 個套件：

**Example `graphs/aws-panorama-sample/graph.json` – 套件**  

```
        "packages": [
            {
                "name": "123456789012::SAMPLE_CODE",
                "version": "1.0"
            },
            {
                "name": "123456789012::SQUEEZENET_PYTORCH_V1",
                "version": "1.0"
            },
            {
                "name": "panorama::abstract_rtsp_media_source",
                "version": "1.0"
            },
            {
                "name": "panorama::hdmi_data_sink",
                "version": "1.0"
            }
        ],
```

前兩個套件是在 `packages`目錄中的應用程式內定義。它們包含此應用程式特定的程式碼和模型。第二個套件是 AWS Panorama 服務提供的一般攝影機和顯示套件。`abstract_rtsp_media_source` 套件是您在部署期間覆寫之攝影機的預留位置。`hdmi_data_sink` 套件代表裝置上的 HDMI 輸出連接器。

節點是套件的界面，以及具有您在部署時間覆寫之預設值的非套件參數。程式碼和模型套件在檔案中定義指定輸入和輸出`package.json`的界面，可以是影片串流或基本資料類型，例如浮點數、布林值或字串。

例如，`code_node`節點是指來自 `SAMPLE_CODE`套件的 界面。

```
        "nodes": [
            {
                "name": "code_node",
                "interface": "123456789012::SAMPLE_CODE.interface",
                "overridable": false,
                "launch": "onAppStart"
            },
```

此界面在套件組態檔案 中定義`package.json`。界面指定套件是商業邏輯，並且需要名為 的影片串流`video_in`和名為 `threshold` 的浮點數做為輸入。介面也指定程式碼需要名為 的影片串流緩衝，`video_out`才能將影片輸出至顯示器

**Example `packages/123456789012-SAMPLE_CODE-1.0/package.json`**  

```
{
    "nodePackage": {
        "envelopeVersion": "2021-01-01",
        "name": "SAMPLE_CODE",
        "version": "1.0",
        "description": "Computer vision application code.",
        "assets": [],
        "interfaces": [
            {
                "name": "interface",
                "category": "business_logic",
                "asset": "code_asset",
                "inputs": [
                    {
                        "name": "video_in",
                        "type": "media"
                    },
                    {
                        "name": "threshold",
                        "type": "float32"
                    }
                ],
                "outputs": [
                    {
                        "description": "Video stream output",
                        "name": "video_out",
                        "type": "media"
                    }
                ]
            }
        ]
    }
}
```

回到應用程式資訊清單，`camera_node`節點代表來自攝影機的視訊串流。它包含裝飾項目，在您部署應用程式時會顯示在主控台中，提示您選擇攝影機串流。

**Example `graphs/aws-panorama-sample/graph.json` – 攝影機節點**  

```
            {
                "name": "camera_node",
                "interface": "panorama::abstract_rtsp_media_source.rtsp_v1_interface",
                "overridable": true,
                "launch": "onAppStart",
                "decorator": {
                    "title": "Camera",
                    "description": "Choose a camera stream."
                }
            },
```

參數節點 `threshold_param`定義應用程式程式碼使用的可信度閾值參數。其預設值為 60，可在部署期間覆寫。

**Example `graphs/aws-panorama-sample/graph.json` – 參數節點**  

```
            {
                "name": "threshold_param",
                "interface": "float32",
                "value": 60.0,
                "overridable": true,
                "decorator": {
                    "title": "Confidence threshold",
                    "description": "The minimum confidence for a classification to be recorded."
                }
            }
```

應用程式資訊清單的最後一個區段 `edges`會在節點之間進行連線。攝影機的視訊串流和閾值參數會連接到程式碼節點的輸入，而來自程式碼節點的視訊輸出則會連接到顯示器。

**Example `graphs/aws-panorama-sample/graph.json` – 邊緣**  

```
        "edges": [
            {
                "producer": "camera_node.video_out",
                "consumer": "code_node.video_in"
            },
            {
                "producer": "code_node.video_out",
                "consumer": "output_node.video_in"
            },
            {
                "producer": "threshold_param",
                "consumer": "code_node.threshold"
            }
        ]
```

## 使用範例應用程式建置
<a name="gettingstarted-sample-adapting"></a>

您可以使用範例應用程式做為您自己的應用程式的起點。

每個套件的名稱在您的帳戶中必須是唯一的。如果您和帳戶中的另一個使用者都使用通用套件名稱，例如 `code`或 `model`，則部署時可能會收到錯誤的套件版本。將程式碼套件的名稱變更為代表您應用程式的名稱。

**重新命名程式碼套件**

1. 重新命名套件資料夾：`packages/123456789012-SAMPLE_CODE-1.0/`。

1. 在下列位置更新套件名稱。

****
   + **應用程式資訊清單** – `graphs/aws-panorama-sample/graph.json`
   + **套件組態** – `packages/123456789012-SAMPLE_CODE-1.0/package.json`
   + **組建指令碼** – `3-build-container.sh`

**更新應用程式的程式碼**

1. 在 中修改應用程式碼`packages/123456789012-SAMPLE_CODE-1.0/src/application.py`。

1. 若要建置容器，請執行 `3-build-container.sh`。

   ```
   aws-panorama-sample$ ./3-build-container.sh
   TMPDIR=$(pwd) docker build -t code_asset packages/123456789012-SAMPLE_CODE-1.0
   Sending build context to Docker daemon  61.44kB
   Step 1/2 : FROM public.ecr.aws/panorama/panorama-application
    ---> 9b197f256b48
   Step 2/2 : COPY src /panorama
    ---> 55c35755e9d2
   Successfully built 55c35755e9d2
   Successfully tagged code_asset:latest
   docker export --output=code_asset.tar $(docker create code_asset:latest)
   gzip -9 code_asset.tar
   Updating an existing asset with the same name
   {
       "name": "code_asset",
       "implementations": [
           {
               "type": "container",
               "assetUri": "98aaxmpl1c1ef64cde5ac13bd3be5394e5d17064beccee963b4095d83083c343.tar.gz",
               "descriptorUri": "1872xmpl129481ed053c52e66d6af8b030f9eb69b1168a29012f01c7034d7a8f.json"
           }
       ]
   }
   Container asset for the package has been succesfully built at  ~/aws-panorama-sample-dev/assets/98aaxmpl1c1ef64cde5ac13bd3be5394e5d17064beccee963b4095d83083c343.tar.gz
   ```

   CLI 會自動從 `assets` 資料夾刪除舊容器資產，並更新套件組態。

1. 若要上傳套件，請執行 `4-package-application.py`。

1. 開啟 AWS Panorama 主控台[部署的應用程式頁面](https://console.aws.amazon.com/panorama/home#deployed-applications)。

1. 選擇應用程式。

1. 選擇 **Replace** (取代)。

1. 完成部署應用程式的步驟。如有需要，您可以變更應用程式資訊清單、攝影機串流或參數。

## 變更電腦視覺模型
<a name="gettingstarted-sample-model"></a>

範例應用程式包含電腦視覺模型。若要使用您自己的模型，請修改模型節點的組態，並使用 AWS Panorama 應用程式 CLI 將其匯入為資產。

下列範例使用 MXNet SSD ResNet50 模型，您可以從本指南的 GitHub 儲存庫下載：[ssd\$1512\$1resnet50\$1v1\$1voc.tar.gz](https://github.com/awsdocs/aws-panorama-developer-guide/releases/download/v0.1-preview/ssd_512_resnet50_v1_voc.tar.gz)

**變更範例應用程式的模型**

1. 重新命名套件資料夾以符合您的模型。例如， 到 `packages/123456789012-SSD_512_RESNET50_V1_VOC-1.0/`。

1. 在下列位置更新套件名稱。

****
   + **應用程式資訊清單** – `graphs/aws-panorama-sample/graph.json`
   + **套件組態** – `packages/123456789012-SSD_512_RESNET50_V1_VOC-1.0/package.json`

1. 在套件組態檔案中 (`package.json`)。將`assets`值變更為空白陣列。

   ```
   {
       "nodePackage": {
           "envelopeVersion": "2021-01-01",
           "name": "SSD_512_RESNET50_V1_VOC",
           "version": "1.0",
           "description": "Compact classification model",
           "assets": [],
   ```

1. 開啟套件描述項檔案 (`descriptor.json`)。更新 `framework`和 `shape`值以符合您的模型。

   ```
   {
       "mlModelDescriptor": {
           "envelopeVersion": "2021-01-01",
           "framework": "MXNET",
           "inputs": [
               {
                   "name": "data",
                   "shape": [ 1, 3, 512, 512 ]
               }
           ]
       }
   }
   ```

   **形狀**的值 表示模型作為輸入 (1) 拍攝的影像數量`1,3,512,512`、每個影像中的通道數量 (3-紅色、綠色和藍色），以及影像的維度 (512 x 512)。陣列的值和順序因模型而異。

1. 使用 AWS Panorama 應用程式 CLI 匯入模型。AWS Panorama Application CLI 會將模型和描述項檔案複製到具有唯一名稱的`assets`資料夾中，並更新套件組態。

   ```
   aws-panorama-sample$ panorama-cli add-raw-model --model-asset-name model-asset \
   --model-local-path ssd_512_resnet50_v1_voc.tar.gz \
   --descriptor-path packages/123456789012-SSD_512_RESNET50_V1_VOC-1.0/descriptor.json \
   --packages-path packages/123456789012-SSD_512_RESNET50_V1_VOC-1.0
   {
       "name": "model-asset",
       "implementations": [
           {
               "type": "model",
               "assetUri": "b1a1589afe449b346ff47375c284a1998c3e1522b418a7be8910414911784ce1.tar.gz",
               "descriptorUri": "a6a9508953f393f182f05f8beaa86b83325f4a535a5928580273e7fe26f79e78.json"
           }
       ]
   }
   ```

1. 若要上傳模型，請執行 `panorama-cli package-application`。

   ```
   $ panorama-cli package-application
   Uploading package SAMPLE_CODE
   Patch Version 1844d5a59150d33f6054b04bac527a1771fd2365e05f990ccd8444a5ab775809 already registered, ignoring upload
   Uploading package SSD_512_RESNET50_V1_VOC
   Patch version for the package 244a63c74d01e082ad012ebf21e67eef5d81ce0de4d6ad1ae2b69d0bc498c8fd
   upload: assets/b1a1589afe449b346ff47375c284a1998c3e1522b418a7be8910414911784ce1.tar.gz to s3://arn:aws:s3:us-west-2:454554846382:accesspoint/panorama-123456789012-wc66m5eishf4si4sz5jefhx
   63a/123456789012/nodePackages/SSD_512_RESNET50_V1_VOC/binaries/b1a1589afe449b346ff47375c284a1998c3e1522b418a7be8910414911784ce1.tar.gz
   upload: assets/a6a9508953f393f182f05f8beaa86b83325f4a535a5928580273e7fe26f79e78.json to s3://arn:aws:s3:us-west-2:454554846382:accesspoint/panorama-123456789012-wc66m5eishf4si4sz5jefhx63
   a/123456789012/nodePackages/SSD_512_RESNET50_V1_VOC/binaries/a6a9508953f393f182f05f8beaa86b83325f4a535a5928580273e7fe26f79e78.json
   {
       "ETag": "\"2381dabba34f4bc0100c478e67e9ab5e\"",
       "ServerSideEncryption": "AES256",
       "VersionId": "KbY5fpESdpYamjWZ0YyGqHo3.LQQWUC2"
   }
   Registered SSD_512_RESNET50_V1_VOC with patch version 244a63c74d01e082ad012ebf21e67eef5d81ce0de4d6ad1ae2b69d0bc498c8fd
   Uploading package SQUEEZENET_PYTORCH_V1
   Patch Version 568138c430e0345061bb36f05a04a1458ac834cd6f93bf18fdacdffb62685530 already registered, ignoring upload
   ```

1. 更新應用程式程式碼。大多數程式碼都可以重複使用。模型回應的特定程式碼位於 `process_results`方法中。

   ```
       def process_results(self, inference_results, stream):
           """Processes output tensors from a computer vision model and annotates a video frame."""
           for class_tuple in inference_results:
               indexes = self.topk(class_tuple[0])
           for j in range(2):
               label = 'Class [%s], with probability %.3f.'% (self.classes[indexes[j]], class_tuple[0][indexes[j]])
               stream.add_label(label, 0.1, 0.25 + 0.1*j)
   ```

   根據您的模型，您可能還需要更新 `preprocess`方法。

## 預先處理映像
<a name="gettingstarted-sample-preprocessing"></a>

在應用程式將映像傳送至模型之前，它會調整其大小並正規化顏色資料，以準備進行推論。應用程式使用的模型需要具有三個顏色通道的 224 x 224 像素影像，以符合其第一層中的輸入數目。應用程式透過將其轉換為介於 0 到 1 之間的數字、減去該顏色的平均值，然後除以標準差來調整每個顏色值。最後，它會結合顏色通道，並將其轉換為模型可以處理的 NumPy 陣列。

**Example https：//[application.py](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/sample-apps/aws-panorama-sample/packages/123456789012-SAMPLE_CODE-1.0/application.py) – 預先處理**  

```
    def preprocess(self, img, width):
        resized = cv2.resize(img, (width, width))
        mean = [0.485, 0.456, 0.406]
        std = [0.229, 0.224, 0.225]
        img = resized.astype(np.float32) / 255.
        img_a = img[:, :, 0]
        img_b = img[:, :, 1]
        img_c = img[:, :, 2]
        # Normalize data in each channel
        img_a = (img_a - mean[0]) / std[0]
        img_b = (img_b - mean[1]) / std[1]
        img_c = (img_c - mean[2]) / std[2]
        # Put the channels back together
        x1 = [[[], [], []]]
        x1[0][0] = img_a
        x1[0][1] = img_b
        x1[0][2] = img_c
        return np.asarray(x1)
```

此程序提供以 0 為中心的可預測範圍內的模型值。它符合訓練資料集中套用至影像的預先處理，這是標準方法，但可能因模型而異。

## 使用適用於 Python 的 SDK 上傳指標
<a name="gettingstarted-sample-metrics"></a>

範例應用程式使用適用於 Python 的 SDK 將指標上傳至 Amazon CloudWatch。

**Example https：//[application.py](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/sample-apps/aws-panorama-sample/packages/123456789012-SAMPLE_CODE-1.0/application.py) – 適用於 Python 的 SDK**  

```
    def process_streams(self):
        """Processes one frame of video from one or more video streams."""
        ...
            logger.info('epoch length: {:.3f} s ({:.3f} FPS)'.format(epoch_time, epoch_fps))
            logger.info('avg inference time: {:.3f} ms'.format(avg_inference_time))
            logger.info('max inference time: {:.3f} ms'.format(max_inference_time))
            logger.info('avg frame processing time: {:.3f} ms'.format(avg_frame_processing_time))
            logger.info('max frame processing time: {:.3f} ms'.format(max_frame_processing_time))
            self.inference_time_ms = 0
            self.inference_time_max = 0
            self.frame_time_ms = 0
            self.frame_time_max = 0
            self.epoch_start = time.time()
            self.put_metric_data('AverageInferenceTime', avg_inference_time)
            self.put_metric_data('AverageFrameProcessingTime', avg_frame_processing_time)
 
    def put_metric_data(self, metric_name, metric_value):
        """Sends a performance metric to CloudWatch."""
        namespace = 'AWSPanoramaApplication'
        dimension_name = 'Application Name'
        dimension_value = 'aws-panorama-sample'
        try:
            metric = self.cloudwatch.Metric(namespace, metric_name)
            metric.put_data(
                Namespace=namespace,
                MetricData=[{
                    'MetricName': metric_name,
                    'Value': metric_value,
                    'Unit': 'Milliseconds',
                    'Dimensions': [
                        {
                            'Name': dimension_name,
                            'Value': dimension_value
                        },
                        {
                            'Name': 'Device ID',
                            'Value': self.device_id
                        }
                    ]
                }]
            )
            logger.info("Put data for metric %s.%s", namespace, metric_name)
        except ClientError:
            logger.warning("Couldn't put data for metric %s.%s", namespace, metric_name)
        except AttributeError:
            logger.warning("CloudWatch client is not available.")
```

它從您在部署期間指派的執行期角色取得許可。角色在 `aws-panorama-sample.yml` CloudFormation 範本中定義。

**Example [aws-panorama-sample.yml](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/sample-apps/aws-panorama-sample/aws-panorama-sample.yml)**  

```
Resources:
  runtimeRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"		 	 	 
        Statement:
          -
            Effect: Allow
            Principal:
              Service:
                - panorama.amazonaws.com
            Action:
              - sts:AssumeRole
      Policies:
        - PolicyName: cloudwatch-putmetrics
          PolicyDocument:
            Version: 2012-10-17		 	 	 
            Statement:
              - Effect: Allow
                Action: 'cloudwatch:PutMetricData'
                Resource: '*'
      Path: /service-role/
```

範例應用程式會使用 pip 安裝適用於 Python 的 SDK 和其他相依性。當您建置應用程式容器時， 會`Dockerfile`執行命令，在基礎映像隨附的內容上安裝程式庫。

**Example [Dockerfile](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/sample-apps/aws-panorama-sample/packages/123456789012-SAMPLE_CODE-1.0/Dockerfile)**  

```
FROM public.ecr.aws/panorama/panorama-application
WORKDIR /panorama
COPY . .
RUN pip install --no-cache-dir --upgrade pip && \
    pip install --no-cache-dir -r requirements.txt
```

若要在應用程式程式碼中使用 AWS SDK，請先修改範本，以新增應用程式使用之所有 API 動作的許可。`1-create-role.sh` 每次進行變更時，請執行 來更新 CloudFormation 堆疊。然後，將變更部署到您的應用程式程式碼。

對於修改或使用現有資源的動作，最佳實務是透過在個別陳述式`Resource`中指定目標的名稱或模式，將此政策的範圍降至最低。如需每個服務支援的動作和資源的詳細資訊，請參閱服務授權參考中的[動作、資源和條件索引鍵](https://docs.aws.amazon.com/service-authorization/latest/reference/reference_policies_actions-resources-contextkeys.html) 

## 後續步驟
<a name="gettingstarted-sample-nextsteps"></a>

如需使用 AWS Panorama 應用程式 CLI 從頭建置應用程式和建立套件的說明，請參閱 CLI 的 README。

****
+ [github.com/aws/aws-panorama-cli](https://github.com/aws/aws-panorama-cli)

如需更多範例程式碼和測試公用程式，您可以在部署之前用來驗證應用程式程式碼，請造訪 AWS Panorama 範例儲存庫。

****
+ [github.com/aws-samples/aws-panorama-samples](https://github.com/aws-samples/aws-panorama-samples)