

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# 데모 템플릿: `crowd-bounding-box`를 사용한 이미지 주석
<a name="sms-custom-templates-step2-demo1"></a>

Amazon SageMaker Ground Truth 콘솔의 작업 유형으로 사용자 지정 템플릿을 선택하면 **사용자 지정 라벨링 작업 패널**이 열립니다. 여기에서 여러 기본 템플릿을 선택할 수 있습니다. 템플릿은 가장 일반적인 작업 몇 가지를 제시하며 사용자 지정 라벨링 작업의 템플릿을 생성할 때 작업할 샘플을 제공합니다. 콘솔을 사용하지 않거나 추가 리소스가 필요한 경우 [Amazon SageMaker AI Ground Truth 샘플 작업 UI](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` 등 3가지 변수가 있습니다.

이러한 각 변수는 경계 상자의 여러 부분을 나타냅니다.
+ `taskObject`는 주석을 달 사진의 HTTP(S) URL 또는 S3 URI입니다. 추가된 `| grant_read_access`는 S3 URI를 리소스에 대한 단기 액세스가 가능한 HTTPS URL로 변환하는 필터입니다. HTTP(S) URL을 사용하는 경우에는 필요하지 않습니다.
+ `header`는 라벨링할 사진 위에 표시되는 텍스트입니다(예: "사진 속 새 주위에 상자를 그려보세요").
+ `labels`은 `['item1', 'item2', ...]`로 표시되는 어레이입니다. 이러한 항목은 작업자가 자신이 그린 여러 상자에 할당할 수 있는 레이블로, 하나 이상일 수 있습니다.

각 변수 이름은 주석 전 Lambda의 응답에 있는 JSON 객체에서 가져오고, 위의 이름은 단순히 제안 항목에 불과하며, 변수 이름은 합리적이고 팀 내에서 코드 가독성을 향상시킬 수 있는 것이면 뭐든 사용할 수 있습니다.

**필요한 경우 변수 사용**  
필드가 변경되지 않으면 템플릿에서 변수를 제거한 다음 텍스트로 바꿀 수 있습니다. 그렇지 않으면 매니페스트의 각 객체에서 텍스트를 값으로 반복하거나 주석 전 Lambda 함수로 코딩해야 합니다.

**Example : 최종 사용자 지정 경계 상자 템플릿**  
간단한 설명을 위해 이 템플릿에는 변수, 라벨링이 하나씩 있고 매우 기본적인 지침이 있습니다. 매니페스트의 각 데이터 객체에 "동물" 속성이 있다고 가정하면, 값을 템플릿의 두 부분에서 재사용할 수 있습니다.  

```
<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>

작업 설정의 일부로 매니페스트 항목을 처리하고 템플릿 엔진에 전달하기 위해 호출할 수 있는 AWS Lambda 함수의 ARN을 제공합니다.

**Lambda 함수 이름 지정**  
함수 이름 지정에서 모범 사례는 `SageMaker`, `Sagemaker`, `sagemaker`, `LabelingFunction` 등 4개 문자열 중 하나를 함수 이름의 일부로 사용하는 것입니다. 이는 주석 전 및 주석 후 함수에 모두 적용됩니다.

콘솔을 사용할 때 계정이 소유한 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를 생성하기 위한 콘솔 페이지에서 **실행 역할** 패널로 스크롤합니다. **1개 이상의 템플릿에서 새로운 역할을 생성하세요**를 선택합니다. 역할 이름을 지정합니다. **정책 템플릿** 드롭다운에서 **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` 및 라벨링 데이터와 동일한 수준에서 출력 매니페스트로 전달되었는지 보세요. 템플릿에서 사용되었는지 여부와 상관없이 입력 매니페스트의 모든 속성이 출력 매니페스트로 전달됩니다.