

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

# 示範範本：使用 `crowd-bounding-box` 註釋影像
<a name="sms-custom-templates-step2-demo1"></a>

當您在 Amazon SageMaker Ground Truth 主控台選擇使用自訂範本作為任務類型時，您會進入 **Custom labeling task panel** (自訂標籤任務面板)。那裡有多個基礎範本供您選擇。範本代表一些最常見的任務，並提供範例讓您開始建立自訂標籤任務的範本。如果您不使用主控台，或只是要當作額外的資源，請參閱 [Amazon SageMaker AI Ground Truth 範例任務使用者介面](https://github.com/aws-samples/amazon-sagemaker-ground-truth-task-uis)，以取得各種標籤任務類型的示範範本儲存庫。

此示範搭配 **BoundingBox** 範本。此示範也可使用任務前後處理資料所需的 AWS Lambda 函數。在上述 Github 儲存庫中，若要尋找使用 AWS Lambda 函數的範本，請在範本`{{ task.input.{{<property name>}} }}`中尋找 。

**Topics**
+ [入門邊界框自訂範本](#sms-custom-templates-step2-demo1-base-template)
+ [您自己的邊界框自訂範本](#sms-custom-templates-step2-demo1-your-own-template)
+ [您的資訊清單檔案](#sms-custom-templates-step2-demo1-manifest)
+ [您的註釋前 Lambda 函式](#sms-custom-templates-step2-demo1-pre-annotation)
+ [您的註釋後 Lambda 函式](#sms-custom-templates-step2-demo1-post-annotation)
+ [標籤工作的輸出](#sms-custom-templates-step2-demo1-job-output)

## 入門邊界框自訂範本
<a name="sms-custom-templates-step2-demo1-base-template"></a>

這是提供給您的入門邊界框範本。

```
<script src="https://assets.crowd.aws/crowd-html-elements.js"></script>

<crowd-form>
  <crowd-bounding-box
    name="boundingBox"
    src="{{ task.input.taskObject | grant_read_access }}"
    header="{{ task.input.header }}"
    labels="{{ task.input.labels | to_json | escape }}"
  >

    <!-- The <full-instructions> tag is where you will define the full instructions of your task. -->
    <full-instructions header="Bounding Box Instructions" >
      <p>Use the bounding box tool to draw boxes around the requested target of interest:</p>
      <ol>
        <li>Draw a rectangle using your mouse over each instance of the target.</li>
        <li>Make sure the box does not cut into the target, leave a 2 - 3 pixel margin</li>
        <li>
          When targets are overlapping, draw a box around each object,
          include all contiguous parts of the target in the box.
          Do not include parts that are completely overlapped by another object.
        </li>
        <li>
          Do not include parts of the target that cannot be seen,
          even though you think you can interpolate the whole shape of the target.
        </li>
        <li>Avoid shadows, they're not considered as a part of the target.</li>
        <li>If the target goes off the screen, label up to the edge of the image.</li>
      </ol>
    </full-instructions>

    <!-- The <short-instructions> tag allows you to specify instructions that are displayed in the left hand side of the task interface.
    It is a best practice to provide good and bad examples in this section for quick reference. -->
    <short-instructions>
      Use the bounding box tool to draw boxes around the requested target of interest.
    </short-instructions>
  </crowd-bounding-box>
</crowd-form>
```

自訂範本使用 [Liquid 範本語言](https://shopify.github.io/liquid/)，雙大括號括住的每個項目都是變數。註釋前 AWS Lambda 函數應該提供名為 的物件，`taskInput`該物件的屬性可以像 範本`{{ task.input.<property name> }}`一樣存取。

## 您自己的邊界框自訂範本
<a name="sms-custom-templates-step2-demo1-your-own-template"></a>

例如，假設您有一大堆動物照片，而根據先前影像分類任務，您知道影像中的動物種類。現在，您想要在周圍繪製邊界框。

在入門範例中，有三個變數：`taskObject`、`header` 和 `labels`。

每一個變數都在邊界框的不同部分中表示。
+ `taskObject` 是要註釋之照片的 HTTP(S) URL 或 S3 URI。新增的 `| grant_read_access` 是篩選條件，會將 S3 URI 轉換為可短期存取該資源的 HTTPS URL。如果您使用的是 HTTP(S) URL，則不需要。
+ `header` 是要標籤之照片上方的文字，例如“在照片中的鳥周圍繪製方塊”。
+ `labels` 是陣列，表示為 `['item1', 'item2', ...]`。這些標籤可以由工作者指派給他們所繪製的不同方塊。您可以有一或多個。

每個變數名稱都來自註釋前 Lambda 回應中的 JSON 物件。上述名稱僅為建議，請使用任何對您有意義的變數名稱，並提升您團隊中的程式碼可讀性。

**僅在需要時使用變數**  
如果欄位不會變更，您可以從範本中移除該變數，將其取代為該文字，否則您必須將該文字重複為資訊清單中每個物件的值，或寫在註釋前 Lambda 函式中。

**Example ：最終自訂邊界框範本**  
為求簡化，此範本將具有一個變數、一個標籤和非常基本的說明。假設資訊清單中每個資料物件都有 “animal” 屬性，該值可以在範本的兩個部分中重複使用。  

```
<script src="https://assets.crowd.aws/crowd-html-elements.js"></script>
<crowd-form>
  <crowd-bounding-box
    name="boundingBox"
    labels="[ '{{ task.input.animal }}' ]"
    src="{{ task.input.source-ref | grant_read_access }}"
    header="Draw a box around the {{ task.input.animal }}."
  >
    <full-instructions header="Bounding Box Instructions" >
      <p>Draw a bounding box around the {{ task.input.animal }} in the image. If 
      there is more than one {{ task.input.animal }} per image, draw a bounding 
      box around the largest one.</p>
      <p>The box should be tight around the {{ task.input.animal }} with 
      no more than a couple of pixels of buffer around the 
      edges.</p>
      <p>If the image does not contain a {{ task.input.animal }}, check the <strong>
      Nothing to label</strong> box.
    </full-instructions>
    <short-instructions>
      <p>Draw a bounding box around the {{ task.input.animal }} in each image. If 
      there is more than one {{ task.input.animal }} per image, draw a bounding 
      box around the largest one.</p>
    </short-instructions>
  </crowd-bounding-box>
</crowd-form>
```
請注意，整個範本都重複使用 `{{ task.input.animal }}`。如果資訊清單中的所有動物名稱都以大寫字母開頭，您可以使用 `{{ task.input.animal | downcase }}`，在句子中需要以小寫表示的地方，納入 Liquid 的其中一個內建篩選條件。

## 您的資訊清單檔案
<a name="sms-custom-templates-step2-demo1-manifest"></a>

您的資訊清單檔案應該提供您在範本中使用的變數值。您可以在註釋前 Lambda 中對資訊清單資料進行某些轉換，但如果您不需要，則可以降低錯誤風險，並使 Lambda 執行更快速。下列是範本的範例資訊清單檔案。

```
{"source-ref": "<S3 image URI>", "animal": "horse"}
{"source-ref": "<S3 image URI>", "animal" : "bird"}
{"source-ref": "<S3 image URI>", "animal" : "dog"}
{"source-ref": "<S3 image URI>", "animal" : "cat"}
```

## 您的註釋前 Lambda 函式
<a name="sms-custom-templates-step2-demo1-pre-annotation"></a>

作為任務設定的一部分，提供 函數的 ARN，該 AWS Lambda 函數可以呼叫 來處理資訊清單項目並將其傳遞至範本引擎。

**指定 Lambda 函式名稱**  
函式的命名最佳實務是在函式名稱中使用以下四個字串之一：`SageMaker`、`Sagemaker`、`sagemaker` 或 `LabelingFunction`。這適用於註釋前函式和註釋後函式。

當您使用 主控台時，如果您的帳戶擁有 AWS Lambda 函數，則會提供符合命名需求的函數下拉式清單來選擇。

在這個非常基本的範例中，您只是從資訊清單傳遞資訊，而沒有做任何額外的處理。此範例註釋前函式是針對 Python 3.7 而撰寫。

```
import json

def lambda_handler(event, context):
    return {
        "taskInput": event['dataObject']
    }
```

資訊清單中的 JSON 物件，將做為 `event` 物件的子系提供。`taskInput` 物件內的屬性可當作範本的變數使用，因此只要將 `taskInput` 的值設為 `event['dataObject']`，就會將資訊清單物件的所有值傳遞到您的範本，而無需個別地複製它們。如果您希望將更多值傳送到範本，您可以將它們新增至 `taskInput` 物件。

## 您的註釋後 Lambda 函式
<a name="sms-custom-templates-step2-demo1-post-annotation"></a>

作為任務設定的一部分，提供 AWS Lambda 函數的 ARN，可在工作者完成任務時呼叫該函數來處理表單資料。根據您的需要，此部分可以簡單也可以複雜。如果您希望進行回答整合與評分，您可以套用您選擇的評分和 (或) 整合演算法。如果您希望存放原始資料以進行離線處理，則可以選擇此選項。

**提供許可給您的註釋後 Lambda**  
註釋資料會位於由 `payload` 物件中之 `s3Uri` 字串所指定的檔案中。若要處理註釋 (即使是簡單的傳遞函式)，您也需要為 Lambda 指派 `S3ReadOnly` 存取權以便其讀取註釋檔案。  
在建立 Lambda 的主控台頁面中，捲動至 **Execution role** (執行角色) 面板。選取 **Create a new role from one or more templates** (從一或多個範本建立新角色)。為角色命名。從 **Policy templates** (政策範本) 下拉式清單，選擇 **Amazon S3 object read-only permissions** (Amazon S3 物件唯讀許可)。儲存 Lambda，即會儲存並選取角色。

下列範例採用 Python 2.7。

```
import json
import boto3
from urlparse import urlparse

def lambda_handler(event, context):
    consolidated_labels = []

    parsed_url = urlparse(event['payload']['s3Uri']);
    s3 = boto3.client('s3')
    textFile = s3.get_object(Bucket = parsed_url.netloc, Key = parsed_url.path[1:])
    filecont = textFile['Body'].read()
    annotations = json.loads(filecont);
    
    for dataset in annotations:
        for annotation in dataset['annotations']:
            new_annotation = json.loads(annotation['annotationData']['content'])
            label = {
                'datasetObjectId': dataset['datasetObjectId'],
                'consolidatedAnnotation' : {
                'content': {
                    event['labelAttributeName']: {
                        'workerId': annotation['workerId'],
                        'boxesInfo': new_annotation,
                        'imageSource': dataset['dataObject']
                        }
                    }
                }
            }
            consolidated_labels.append(label)
    
    return consolidated_labels
```

註釋後 Lambda 通常會在事件物件中接收任務結果批次。該批次將是 Lambda 應重複執行的 `payload` 物件。您傳回的內容會是符合 [ API 合約](sms-custom-templates-step3.md)的物件。

## 標籤工作的輸出
<a name="sms-custom-templates-step2-demo1-job-output"></a>

您將在指定之目標 S3 儲存貯體中以標籤工作命名的資料夾中找到工作輸出。該輸出位於名為 `manifests` 的子資料夾。

針對邊界框任務，您將在輸出資訊清單中找到的輸出看起來會如下列示範。已對範例進行清除以便於列印。每項記錄的實際輸出為單一行。

**Example ：您輸出資訊清單中的 JSON**  

```
{
  "source-ref":"<URL>",
  "<{{label attribute name}}>":
    {
       "workerId":"<URL>",
       "imageSource":"<image URL>",
       "boxesInfo":"{\"boundingBox\":{\"boundingBoxes\":[{\"height\":878, \"label\":\"bird\", \"left\":208, \"top\":6, \"width\":809}], \"inputImageProperties\":{\"height\":924, \"width\":1280}}}"},
  "<{{label attribute name}}>-metadata":
    {
      "type":"groundTruth/custom",
      "job_name":"<Labeling job name>",
      "human-annotated":"yes"
    },
  "animal" : "bird"
}
```
請注意其他 `animal` 屬性如何從原始資訊清單，傳遞到與 `source-ref` 和標籤資料位於相同層級的輸出資訊清單。輸入資訊清單中的任何屬性 (無論是否用於您的範本中) 都將傳遞到輸出資訊清單。