자습서: Azure AI Vision을 사용하여 Azure Storage에서 이미지 메타데이터 생성

이 자습서에서는 Azure AI Vision 서비스를 웹앱에 통합하여 업로드된 이미지에 대한 메타데이터를 생성하는 방법을 알아봅니다. 이는 회사가 모든 이미지에 대해 설명이 포함된 캡션 또는 검색 가능한 키워드(keyword) 신속하게 생성하려는 경우와 같은 DAM(디지털 자산 관리) 시나리오에 유용합니다.

Visual Studio를 사용하여 사용자가 업로드한 이미지를 허용하고 Azure Blob Storage에 이미지를 저장하는 MVC 웹앱을 작성합니다. C#에서 Blob을 읽고 쓰고 Blob 메타데이터를 사용하여 만든 Blob에 추가 정보를 연결하는 방법을 알아봅니다. 그런 다음 사용자가 업로드한 각 이미지를 Azure AI Vision API에 제출하여 이미지에 대한 캡션 및 검색 메타데이터를 생성합니다. 마지막으로 Visual Studio를 사용하여 클라우드에 앱을 배포할 수 있습니다.

이 자습서에서는 다음을 수행하는 방법을 보여 줍니다.

  • Azure Portal을 사용하여 스토리지 계정 및 스토리지 컨테이너 만들기
  • Visual Studio에서 웹앱을 만들고 Azure에 배포
  • Azure AI Vision API를 사용하여 이미지에서 정보 추출
  • Azure Storage 이미지에 메타데이터 연결
  • Azure Storage Explorer를 사용하여 이미지 메타데이터 확인

Azure AI Vision을 사용하여 메타데이터 생성 섹션은 이미지 분석과 가장 관련이 있습니다. 이미지 분석이 설정된 애플리케이션에 통합되는 방법을 확인하려면 건너뜁니다.

Azure 구독이 아직 없는 경우 시작하기 전에 체험 계정을 만듭니다.

필수 조건

저장소 계정 만들기

이 섹션에서는 Azure Portal을 사용하여 스토리지 계정을 만듭니다. 그런 다음 사용자가 업로드한 이미지를 저장하는 컨테이너와 업로드된 이미지에서 생성된 이미지 썸네일을 저장하는 컨테이너 쌍을 만듭니다.

  1. 브라우저에서 Azure Portal에 로그인합니다. 로그인하라는 메시지가 표시되면 Microsoft 계정을 사용하여 로그인합니다.

  2. 스토리지 계정을 만들려면 왼쪽 리본에서 + 리소스 만들기를 선택합니다. 그런 다음 스토리지를 선택한 다음 스토리지 계정을 선택합니다.

    Creating a storage account

  3. 이름 필드에 스토리지 계정의 고유한 이름을 입력하고 그 옆에 녹색 확인 표시가 나타나는지 확인합니다. 이름은 이 계정에서 만든 Blob에 액세스하는 URL의 한 부분을 형성하기 때문에 중요합니다. 스토리지 계정을 "IntellipixResources"라는 새 리소스 그룹에 배치하고 가장 가까운 지역을 선택합니다. 화면 하단의 검토 + 만들기 버튼을 선택하여 새 스토리지 계정을 생성하여 완료합니다.

    참고 항목

    스토리지 계정 이름의 길이는 3~24자이며 숫자와 소문자만 포함할 수 있습니다. 또한 입력한 이름은 Azure 내에서 고유해야 합니다. 다른 사람이 같은 이름을 선택한 경우 이름 입력란에 빨간색 느낌표와 함께 해당 이름을 사용할 수 없다는 알림이 표시됩니다.

    Specifying parameters for a new storage account

  4. 왼쪽 리본에서 리소스 그룹을 선택합니다. 그런 다음 "IntellipixResources" 리소스 그룹을 선택합니다.

    Opening the resource group

  5. 리소스 그룹에 대해 열리는 탭에서 생성한 스토리지 계정을 선택합니다. 스토리지 계정이 아직 없으면 표시될 때까지 탭 상단에서 새로 고침을 선택할 수 있습니다.

    Opening the new storage account

  6. 스토리지 계정 탭에서 Blob을 선택하면 이 계정과 연결된 컨테이너 목록을 볼 수 있습니다.

    Viewing blobs button

  7. 스토리지 계정에는 현재 컨테이너가 없습니다. Blob을 만들려면 먼저 컨테이너를 만들어 저장해야 합니다. + 컨테이너를 선택하여 새 컨테이너를 만듭니다. 이름 필드에 입력 photos 하고 Blob공용 액세스 수준으로 선택합니다. 그런 다음 확인을 선택하여 'photos'라는 컨테이너를 만듭니다.

    기본적으로 컨테이너와 해당 콘텐츠는 비공개입니다. 액세스 수준으로 Blob을 선택하면 "photos" 컨테이너의 Blob에 공개적으로 액세스할 수 있지만 컨테이너 자체는 공개되지 않습니다. 이는 "사진" 컨테이너에 저장된 이미지가 웹앱에서 연결되기 때문에 원하는 것입니다.

    Creating a

  8. 이전 단계를 반복하여 컨테이너의 공용 액세스 수준이 Blob으로 설정되도록 한 번 더 "미리 보기"라는 컨테이너를 만듭니다.

  9. 두 컨테이너가 이 스토리지 계정의 컨테이너 목록에 표시되고 이름이 올바르게 철자되었는지 확인합니다.

    The new containers

  10. "Blob 서비스" 화면을 닫습니다. 스토리지 계정 화면 왼쪽 메뉴에서 액세스 키를 선택한 다음 key1KEY 옆에 있는 복사 버튼을 선택합니다. 나중에 사용할 수 있도록 이 액세스 키를 즐겨찾는 텍스트 편집기에 붙여넣습니다.

    Copying the access key

이제 빌드하려는 앱에 업로드된 이미지와 이미지를 저장할 컨테이너를 보관하는 스토리지 계정을 만들었습니다.

Azure Storage Explorer 실행

Azure Storage Explorer 는 Windows, macOS 및 Linux를 실행하는 PC에서 Azure Storage를 사용하기 위한 그래픽 인터페이스를 제공하는 무료 도구입니다. Azure Portal과 동일한 대부분의 기능을 제공하고 Blob 메타데이터를 보는 기능과 같은 다른 기능을 제공합니다. 이 섹션에서는 Microsoft Azure Storage Explorer를 사용하여 이전 섹션에서 만든 컨테이너를 봅니다.

  1. Storage Explorer를 설치하지 않았거나 최신 버전을 실행하고 있는지 확인하려면 이동하여 http://storageexplorer.com/ 다운로드하여 설치합니다.

  2. Storage Explorer를 시작합니다. 로그인하라는 메시지가 표시되면 Azure Portal에 로그인할 때 사용한 것과—동일한 Microsoft 계정을 사용하여 로그인합니다. Storage Explorer의 왼쪽 창에 스토리지 계정이 표시되지 않으면 아래에 강조 표시된 계정 관리 버튼을 선택하고 Microsoft 계정과 스토리지 계정을 만드는 데 사용된 구독이 모두 Storage Explorer에 추가되었는지 확인하세요.

    Managing accounts in Storage Explorer

  3. 스토리지 계정 옆에 있는 작은 화살표를 선택하여 내용을 표시한 다음 Blob 컨테이너 옆에 있는 화살표를 선택합니다. 만든 컨테이너가 목록에 표시되는지 확인합니다.

    Viewing blob containers

컨테이너는 현재 비어 있지만 앱이 배포되고 사진 업로드를 시작하면 변경됩니다. Storage Explorer를 설치하면 앱이 Blob Storage에 쓰는 내용을 쉽게 확인할 수 있습니다.

Visual Studio에서 새 웹앱 만들기

이 섹션에서는 Visual Studio에서 새 웹앱을 만들고, 이미지를 업로드하고, Blob Storage에 쓰고, 웹 페이지에 표시하는 데 필요한 기본 기능을 구현하는 코드를 추가합니다.

  1. Visual Studio를 시작하고 파일 -> 새로 만들기 -> 프로젝트 명령을 사용하여 "Intellipix"("Intelligent Pictures"의 약자)라는 새 Visual C# ASP.NET 웹 애플리케이션 프로젝트를 만듭니다.

    Creating a new Web Application project

  2. "새 ASP.NET 웹 애플리케이션" 대화 상자에서 MVC가 선택되어 있는지 확인합니다. 그런 다음 확인을 선택합니다.

    Creating a new ASP.NET MVC project

  3. 잠시 시간을 내어 솔루션 탐색기 프로젝트 구조를 검토합니다. 무엇보다도 프로젝트의 MVC 컨트롤러를 보유하는 Controllers라는 폴더와 프로젝트의 뷰를 보유하는 Views라는 폴더가 있습니다. 애플리케이션을 구현할 때 이러한 폴더 및 다른 폴더의 자산으로 작업합니다.

    The project shown in Solution Explorer

  4. Visual Studio의 디버그 -> 디버깅 없이 시작 명령(또는 Ctrl+F5 누름)을 사용하여 브라우저에서 애플리케이션을 시작합니다. 애플리케이션이 현재 상태에서 어떻게 보이는지 보여 줍니다.

    The initial application

  5. 브라우저를 닫고 Visual Studio로 돌아갑니다. 솔루션 탐색기에서 Intellipix 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 NuGet 패키지 관리...를 선택합니다. 찾아보기를 선택합니다. 그런 다음 검색 상자에 입력 imageresizer 하고 ImageResizer라는 NuGet 패키지를 선택합니다. 마지막으로 설치를 선택하여 패키지의 최신 안정 버전을 설치합니다. ImageResizer에는 앱에 업로드된 이미지에서 이미지 썸네일을 만드는 데 사용할 API가 포함되어 있습니다. 변경 내용을 확인하고 제공된 라이선스를 수락합니다.

    Installing ImageResizer

  6. 이 프로세스를 반복하여 프로젝트에 WindowsAzure.Storage라는 NuGet 패키지를 추가합니다. 이 패키지에는 .NET 애플리케이션에서 Azure Storage에 액세스하기 위한 API가 포함되어 있습니다. 변경 내용을 확인하고 제공된 라이선스를 수락합니다.

    Installing WindowsAzure.Storage

  7. Web.config를 열고 다음 문을 <appSettings> 섹션에 추가합니다. 여기서 ACCOUNT_NAME은 첫 번째 섹션에서 만든 스토리지 계정 이름으로, ACCOUNT_KEY는 저장한 액세스 키로 바꿉니다.

    <add key="StorageConnectionString" value="DefaultEndpointsProtocol=https;AccountName=ACCOUNT_NAME;AccountKey=ACCOUNT_KEY" />
    

    Important

    Web.config 파일은 구독 키와 같은 중요한 정보를 보관하기 위한 것이며, .config 확장자를 사용하는 파일에 대한 HTTP 요청은 ASP.NET 엔진에서 처리되며, 이 메시지는 "이 유형의 페이지는 제공되지 않습니다" 메시지를 반환합니다. 그러나 공격자가 Web.config 콘텐츠를 볼 수 있는 다른 악용을 찾을 수 있는 경우 해당 정보를 노출할 수 있습니다. Web.config 데이터를 더욱 안전하게 보호하기 위해 수행할 수 있는 추가 단계는 커넥트ion 문자열 및 기타 구성 정보 보호를 참조하세요.

  8. 프로젝트의 Views/Shared 폴더에서 _Layout.cshtml이라는 파일을 엽니다. 19번 줄에서 "애플리케이션 이름"을 "Intellipix"로 변경합니다. 줄은 다음과 같아야 합니다.

    @Html.ActionLink("Intellipix", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
    

    참고 항목

    ASP.NET MVC 프로젝트에서 _Layout.cshtml 은 다른 보기에 대한 템플릿 역할을 하는 특수 뷰입니다. 일반적으로 이 파일의 모든 보기에 공통적인 머리글 및 바닥글 콘텐츠를 정의합니다.

  9. 프로젝트의 Models 폴더를 마우스 오른쪽 단추로 클릭하고 추가 -> 클래스... 명령을 사용하여 BlobInfo.cs라는 클래스 파일을 폴더에 추가합니다. 그런 다음 빈 BlobInfo 클래스를 다음 클래스 정의로 바꿉다.

    public class BlobInfo
    {
        public string ImageUri { get; set; }
        public string ThumbnailUri { get; set; }
        public string Caption { get; set; }
    }
    
  10. 프로젝트의 Controllers 폴더에서 HomeController.cs 열고 파일 맨 위에 다음 using 문을 추가합니다.

    using ImageResizer;
    using Intellipix.Models;
    using Microsoft.WindowsAzure.Storage;
    using Microsoft.WindowsAzure.Storage.Blob;
    using System.Configuration;
    using System.Threading.Tasks;
    using System.IO;
    
  11. HomeController.cs Index 메서드를 다음 구현으로 바꿉다.

    public ActionResult Index()
    {
        // Pass a list of blob URIs in ViewBag
        CloudStorageAccount account = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["StorageConnectionString"]);
        CloudBlobClient client = account.CreateCloudBlobClient();
        CloudBlobContainer container = client.GetContainerReference("photos");
        List<BlobInfo> blobs = new List<BlobInfo>();
    
        foreach (IListBlobItem item in container.ListBlobs())
        {
            var blob = item as CloudBlockBlob;
    
            if (blob != null)
            {
                blobs.Add(new BlobInfo()
                {
                    ImageUri = blob.Uri.ToString(),
                    ThumbnailUri = blob.Uri.ToString().Replace("/photos/", "/thumbnails/")
                });
            }
        }
    
        ViewBag.Blobs = blobs.ToArray();
        return View();
    }
    

    Index 메서드는 컨테이너의 Blob을 "photos" 열거하고 해당 Blob을 나타내는 BlobInfo 개체 배열을 ASP.NET MVC의 ViewBag 속성을 통해 뷰에 전달합니다. 나중에 이러한 개체를 열거하고 사진 썸네일 컬렉션을 표시하도록 보기를 수정합니다. 스토리지 계정에 액세스하고 Blob(CloudStorageAccount, CloudBlobClient, and CloudBlobContainer)을 열거하는 데 사용할 클래스는 NuGet을 통해 설치한 WindowsAzure.Storage 패키지에서 가져옵니다.

  12. HomeController.cs HomeController 클래스에 다음 메서드추가합니다.

    [HttpPost]
    public async Task<ActionResult> Upload(HttpPostedFileBase file)
    {
        if (file != null && file.ContentLength > 0)
        {
            // Make sure the user selected an image file
            if (!file.ContentType.StartsWith("image"))
            {
                TempData["Message"] = "Only image files may be uploaded";
            }
            else
            {
                try
                {
                    // Save the original image in the "photos" container
                    CloudStorageAccount account = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["StorageConnectionString"]);
                    CloudBlobClient client = account.CreateCloudBlobClient();
                    CloudBlobContainer container = client.GetContainerReference("photos");
                    CloudBlockBlob photo = container.GetBlockBlobReference(Path.GetFileName(file.FileName));
                    await photo.UploadFromStreamAsync(file.InputStream);
    
                    // Generate a thumbnail and save it in the "thumbnails" container
                    using (var outputStream = new MemoryStream())
                    {
                        file.InputStream.Seek(0L, SeekOrigin.Begin);
                        var settings = new ResizeSettings { MaxWidth = 192 };
                        ImageBuilder.Current.Build(file.InputStream, outputStream, settings);
                        outputStream.Seek(0L, SeekOrigin.Begin);
                        container = client.GetContainerReference("thumbnails");
                        CloudBlockBlob thumbnail = container.GetBlockBlobReference(Path.GetFileName(file.FileName));
                        await thumbnail.UploadFromStreamAsync(outputStream);
                    }
                }
                catch (Exception ex)
                {
                    // In case something goes wrong
                    TempData["Message"] = ex.Message;
                }
            }
        }
    
        return RedirectToAction("Index");
    }
    

    사진을 업로드할 때 호출되는 메서드입니다. 업로드된 각 이미지를 컨테이너에 "photos" Blob으로 저장하고, 패키지를 사용하여 ImageResizer 원본 이미지에서 썸네일 이미지를 만들고, 썸네일 이미지를 컨테이너에 "thumbnails" Blob으로 저장합니다.

  13. 프로젝트의 Views/Home 폴더의 Index.cshmtl을 열고 해당 콘텐츠를 다음 코드 및 태그로 바꿉니다.

    @{
        ViewBag.Title = "Intellipix Home Page";
    }
    
    @using Intellipix.Models
    
    <div class="container" style="padding-top: 24px">
        <div class="row">
            <div class="col-sm-8">
                @using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
                {
                    <input type="file" name="file" id="upload" style="display: none" onchange="$('#submit').click();" />
                    <input type="button" value="Upload a Photo" class="btn btn-primary btn-lg" onclick="$('#upload').click();" />
                    <input type="submit" id="submit" style="display: none" />
                }
            </div>
            <div class="col-sm-4 pull-right">
            </div>
        </div>
    
        <hr />
    
        <div class="row">
            <div class="col-sm-12">
                @foreach (BlobInfo blob in ViewBag.Blobs)
                {
                    <img src="@blob.ThumbnailUri" width="192" title="@blob.Caption" style="padding-right: 16px; padding-bottom: 16px" />
                }
            </div>
        </div>
    </div>
    
    @section scripts
    {
        <script type="text/javascript" language="javascript">
            if ("@TempData["Message"]" !== "") {
                alert("@TempData["Message"]");
            }
        </script>
    }
    

    여기에 사용된 언어는 HTML 태그에 실행 코드를 포함할 수 있는 Razor입니다. 파일 중간에 있는 문은 @foreach ViewBag의 컨트롤러에서 전달된 BlobInfo 개체를 열거하고 해당 개체에서 HTML <img> 요소를 만듭니다. 각 요소의 속성은 src 이미지 썸네일을 포함하는 Blob의 URI를 사용하여 초기화됩니다.

  14. GitHub 샘플 데이터 리포지토리에서 photos.zip 파일을 다운로드하고 압축을 풉니다. 이는 앱을 테스트하는 데 사용할 수 있는 다양한 사진의 구색입니다.

  15. 변경 내용을 저장하고 Ctrl+F5를 눌러 브라우저에서 애플리케이션을 시작합니다. 그런 다음 사진 업로드를 선택하고 다운로드한 이미지 중 하나를 업로드하세요. 사진의 축소판 그림 버전이 페이지에 표시되는지 확인합니다.

    Intellipix with one photo uploaded

  16. 사진 폴더에서 몇 가지 이미지를 더 업로드합니다. 이 페이지에도 표시되는지 확인합니다.

    Intellipix with three photos uploaded

  17. 브라우저에서 마우스 오른쪽 단추를 클릭하고 페이지 원본 보기를 선택하여 페이지의 소스 코드를 봅니다. 이미지 썸네일을 나타내는 <img> 요소를 찾습니다. 이미지에 할당된 URL은 Blob Storage의 Blob을 직접 참조하세요. 이는 컨테이너의 공용 액세스 수준Blob으로 설정하여 내부의 Blob을 공개적으로 액세스할 수 있게 하기 때문입니다.

  18. Azure Storage Explorer로 돌아가서(또는 실행 중인 상태로 두지 않은 경우 다시 시작) 스토리지 계정에서 컨테이너를 "photos" 선택합니다. 컨테이너의 Blob 수는 업로드한 사진 수와 같아야 합니다. Blob 중 하나를 두 번 클릭하여 다운로드하고 Blob에 저장된 이미지를 확인합니다.

    Contents of the

  19. "thumbnails" Storage Explorer에서 컨테이너를 엽니다. Blob 중 하나를 열어 이미지 업로드에서 생성된 썸네일 이미지를 봅니다.

앱은 업로드한 원본 이미지를 볼 수 있는 방법을 아직 제공하지 않습니다. 이상적으로는 이미지 축소판을 선택하면 원본 이미지가 표시되어야 합니다. 다음으로 해당 기능을 추가합니다.

사진을 보기 위한 라이트박스 추가

이 섹션에서는 무료 오픈 소스 JavaScript 라이브러리를 사용하여 사용자가 업로드한 원본 이미지(단순한 이미지 썸네일이 아님)를 볼 수 있도록 해주는 lightbox 뷰어를 추가합니다. 파일이 제공됩니다. 이를 프로젝트에 통합하고 Index.cshtml을 약간 수정하기만 하면 됩니다.

  1. GitHub 코드 리포지토리에서 lightbox.csslightbox.js 파일을 다운로드합니다.

  2. 솔루션 탐색기에서 프로젝트의 Scripts 폴더를 마우스 오른쪽 단추로 클릭하고 추가 -> 새 항목... 명령을 사용하여 lightbox.js 파일을 만듭니다. GitHub 코드 리포지토리에 파일 예의 내용을 붙여넣습니다.

  3. 프로젝트의 "Content" 폴더를 마우스 오른쪽 단추로 클릭하고 추가 -> 새 항목... 명령을 사용하여 lightbox.css 파일을 만듭니다. GitHub 코드 리포지토리에 파일 예의 내용을 붙여넣습니다.

  4. GitHub 데이터 파일 리포https://github.com/Azure-Samples/cognitive-services-sample-data-files/tree/master/ComputerVision/storage-lab-tutorial지토리에서 buttons.zip 파일의 압축을 풀고 다운로드합니다. 4개의 단추 이미지가 있어야 합니다.

  5. 솔루션 탐색기에서 Intellipix 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가 -> 새 폴더 명령을 사용하여 "Images"라는 폴더를 프로젝트에 추가합니다.

  6. Images 폴더를 마우스 오른쪽 단추로 클릭하고 추가 -> 기존 항목... 명령을 사용하여 다운로드한 4개의 이미지를 가져옵니다.

  7. 프로젝트의 "App_Start" 폴더에서 BundleConfig.cs를 엽니다. BundleConfig.cs 메서드에 RegisterBundles다음 문을 추가합니다.

    bundles.Add(new ScriptBundle("~/bundles/lightbox").Include(
              "~/Scripts/lightbox.js"));
    
  8. 동일한 메서드에서 "~/Content/css"에서 만든 StyleBundle 문을 찾아 번들의 스타일시트 목록에 lightbox.css 추가합니다. 수정된 문은 다음과 같습니다.

    bundles.Add(new StyleBundle("~/Content/css").Include(
              "~/Content/bootstrap.css",
              "~/Content/site.css",
              "~/Content/lightbox.css"));
    
  9. 프로젝트의 Views/Shared 폴더에서 _Layout.cshtml을 열고 문 바로 앞에 @RenderSection 다음 문을 추가합니다.

    @Scripts.Render("~/bundles/lightbox")
    
  10. 마지막 작업은 라이트박스 뷰어를 홈페이지에 통합하는 것입니다. 이렇게 하려면 Index.cshtml(프로젝트의 Views/Home 폴더에 있는)을 열고 루프를 @foreach 다음 항목으로 바꿉니다.

    @foreach (BlobInfo blob in ViewBag.Blobs)
    {
        <a href="@blob.ImageUri" rel="lightbox" title="@blob.Caption">
            <img src="@blob.ThumbnailUri" width="192" title="@blob.Caption" style="padding-right: 16px; padding-bottom: 16px" />
        </a>
    }
    
  11. 변경 내용을 저장하고 Ctrl+F5를 눌러 브라우저에서 애플리케이션을 시작합니다. 그런 다음 이전에 업로드한 이미지 중 하나를 선택합니다. 라이트박스가 나타나고 이미지의 확대 보기를 표시하는지 확인합니다.

    An enlarged image

  12. 라이트박스 오른쪽 하단에 있는 X를 선택하여 닫습니다.

이제 업로드한 이미지를 볼 수 있습니다. 다음 단계는 해당 이미지로 더 많은 작업을 수행하는 것입니다.

Azure AI Vision을 사용하여 메타데이터 생성

비전 리소스 만들기

Azure 계정에 대한 Computer Vision 리소스를 만들어야 합니다. 이 리소스는 Azure의 Azure AI Vision 서비스에 대한 액세스를 관리합니다.

  1. 다중 서비스 리소스 또는 Vision 리소스를 만들려면 Azure AI 서비스 리소스 만들기의 지침을 따르세요.

  2. 그런 다음 리소스 그룹의 메뉴로 이동하여 생성한 Vision 리소스를 선택합니다. 엔드포인트 아래의 URL을 잠시 후에 쉽게 검색할 수 있는 위치에 복사합니다. 그런 다음, 액세스 키 표시를 선택합니다.

    Azure portal page with the endpoint URL and access keys link outlined

    참고 항목

    2019년 7월 1일 이후에 만들어진 새 리소스는 사용자 지정 하위 도메인 이름을 사용합니다. 자세한 내용과 지역 엔드포인트의 전체 목록은 Azure AI 서비스에 대한 사용자 지정 하위 도메인 이름을 참조하세요.

  3. 다음 창에서 KEY 1 값을 클립보드에 복사합니다.

    Manage keys dialog, with the copy button outlined

Azure AI Vision 자격 증명 추가

다음으로 앱이 Vision 리소스에 액세스할 수 있도록 필요한 자격 증명을 앱에 추가합니다.

프로젝트의 루트에 있는 Web.config 파일로 이동합니다. 다음 문을 파일 섹션에 <appSettings> 추가하여 이전 단계에서 복사한 키와 VISION_ENDPOINT 이전 단계에서 저장한 URL로 바꿉 VISION_KEY 니다.

<add key="SubscriptionKey" value="VISION_KEY" />
<add key="VisionEndpoint" value="VISION_ENDPOINT" />

솔루션 탐색기에서. 마우스 오른쪽 단추로 프로젝트 솔루션을 선택하고 NuGet 패키지 관리를 선택합니다. 패키지 관리자가 열리면 찾아보기를 선택하고, 시험판 포함을 선택하고, Azure.AI.Vision.ImageAnalysis를 검색합니다. 설치를 선택합니다.

메타데이터 생성 코드 추가

다음으로 실제로 Azure AI Vision 서비스를 사용하여 이미지에 대한 메타데이터를 만드는 코드를 추가합니다.

  1. 프로젝트의 Controllers 폴더에서 HomeController.cs 파일을 열고 파일 맨 위에 다음 using 문을 추가합니다.

    using Azure;
    using Azure.AI.Vision.ImageAnalysis;
    using System;
    
  2. 그런 다음 Upload 메서드로 이동합니다. 이 메서드는 이미지를 변환하고 Blob Storage에 업로드합니다. 블록 // Generate a thumbnail 바로 뒤(또는 이미지 Blob 만들기 프로세스의 끝에) 다음 코드를 추가합니다. 이 코드는 이미지(photo)가 포함된 Blob을 사용하고 Azure AI Vision을 사용하여 해당 이미지에 대한 설명을 생성합니다. Azure AI Vision API는 이미지에 적용되는 키워드 목록도 생성합니다. 생성된 설명과 키워드는 나중에 검색할 수 있도록 Blob의 메타데이터에 저장됩니다.

    // create a new ImageAnalysisClient
    ImageAnalysisClient client = new ImageAnalysisClient(
            new Uri(Environment.GetEnvironmentVariable(ConfigurationManager.AppSettings["VisionEndpoint"])),
            new AzureKeyCredential(ConfigurationManager.AppSettings["SubscriptionKey"]));
    
    VisualFeatures = visualFeatures = VisualFeatures.Caption | VisualFeatures.Tags;
    
    ImageAnalysisOptions analysisOptions = new ImageAnalysisOptions()
    {
        GenderNeutralCaption = true,
        Language = "en",
    };
    
    Uri imageURL = new Uri(photo.Uri.ToString());
    
    ImageAnalysisResult  result = client.Analyze(imageURL,visualFeatures,analysisOptions);
    
    // Record the image description and tags in blob metadata
    photo.Metadata.Add("Caption", result.Caption.Text);
    
    for (int i = 0; i < result.Tags.Values.Count; i++)
    {
        string key = String.Format("Tag{0}", i);
        photo.Metadata.Add(key, result.Tags.Values[i]);
    }
    
    await photo.SetMetadataAsync();
    
  3. 다음으로, 동일한 파일에서 Index 메서드로 이동합니다. 이 메서드는 저장된 이미지 Blob을 대상 Blob 컨테이너(IListBlobItem 인스턴스로)에 열거하고 애플리케이션 뷰에 전달합니다. 이 메서드의 foreach 블록을 다음 코드로 바꿉니다. 이 코드는 CloudBlockBlob.FetchAttributes를 호출하여 각 Blob의 연결된 메타데이터를 가져옵니다. 메타데이터에서 컴퓨터로 생성된 설명(caption)을 추출하고 BlobInfo 개체에 추가하여 뷰에 전달합니다.

    foreach (IListBlobItem item in container.ListBlobs())
    {
        var blob = item as CloudBlockBlob;
    
        if (blob != null)
        {
            blob.FetchAttributes(); // Get blob metadata
            var caption = blob.Metadata.ContainsKey("Caption") ? blob.Metadata["Caption"] : blob.Name;
    
            blobs.Add(new BlobInfo()
            {
                ImageUri = blob.Uri.ToString(),
                ThumbnailUri = blob.Uri.ToString().Replace("/photos/", "/thumbnails/"),
                Caption = caption
            });
        }
    }
    

앱 테스트

Visual Studio에서 변경 내용을 저장하고 Ctrl+F5를 눌러 브라우저에서 애플리케이션을 시작합니다. 앱을 사용하여 다운로드한 사진 세트 또는 사용자 고유의 폴더에서 이미지를 몇 개 더 업로드할 수 있습니다. 보기의 새 이미지 중 하나에 커서를 놓으면 도구 설명 창이 표시되고 이미지에 대한 컴퓨터에서 생성된 캡션 표시됩니다.

The computer-generated caption

연결된 메타데이터를 모두 보려면 Azure Storage Explorer를 사용하여 이미지에 사용하는 스토리지 컨테이너를 봅니다. 컨테이너의 Blob을 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다. 대화 상자에 키-값 쌍 목록이 표시됩니다. 컴퓨터에서 생성된 이미지 설명은 항목Caption에 저장되며 검색 키워드(keyword) 등으로 Tag0Tag1저장됩니다. 완료되면 취소를 선택하여 대화상자를 닫습니다.

Image properties dialog window, with metadata tags listed

앱에 검색 추가

이 섹션에서는 홈페이지에 검색 상자를 추가하여 사용자가 업로드한 이미지에서 키워드(keyword) 검색을 수행할 수 있도록 합니다. 키워드는 Azure AI Vision API에서 생성되고 Blob 메타데이터에 저장되는 키워드입니다.

  1. 프로젝트의 Views/Home 폴더에서 Index.cshtml을 열고 특성을 사용하여 빈 <div> 요소 class="col-sm-4 pull-right" 에 다음 문을 추가합니다.

    @using (Html.BeginForm("Search", "Home", FormMethod.Post, new { enctype = "multipart/form-data", @class = "navbar-form" }))
    {
        <div class="input-group">
            <input type="text" class="form-control" placeholder="Search photos" name="term" value="@ViewBag.Search" style="max-width: 800px">
            <span class="input-group-btn">
                <button class="btn btn-primary" type="submit">
                    <i class="glyphicon glyphicon-search"></i>
                </button>
            </span>
        </div>
    }
    

    이 코드와 태그는 검색 상자와 검색 단추를 홈페이지에 추가합니다.

  2. 프로젝트의 Controllers 폴더에서 HomeController.cs 열고 HomeController 클래스에 다음 메서드를 추가합니다.

    [HttpPost]
    public ActionResult Search(string term)
    {
        return RedirectToAction("Index", new { id = term });
    }
    

    이전 단계에서 추가된 검색 버튼을 사용자가 선택할 때 호출되는 메서드입니다. 페이지를 새로 고치고 URL에 검색 매개 변수를 포함합니다.

  3. Index 메서드를 다음 구현으로 바꿉다.

    public ActionResult Index(string id)
    {
        // Pass a list of blob URIs and captions in ViewBag
        CloudStorageAccount account = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["StorageConnectionString"]);
        CloudBlobClient client = account.CreateCloudBlobClient();
        CloudBlobContainer container = client.GetContainerReference("photos");
        List<BlobInfo> blobs = new List<BlobInfo>();
    
        foreach (IListBlobItem item in container.ListBlobs())
        {
            var blob = item as CloudBlockBlob;
    
            if (blob != null)
            {
                blob.FetchAttributes(); // Get blob metadata
    
                if (String.IsNullOrEmpty(id) || HasMatchingMetadata(blob, id))
                {
                    var caption = blob.Metadata.ContainsKey("Caption") ? blob.Metadata["Caption"] : blob.Name;
    
                    blobs.Add(new BlobInfo()
                    {
                        ImageUri = blob.Uri.ToString(),
                        ThumbnailUri = blob.Uri.ToString().Replace("/photos/", "/thumbnails/"),
                        Caption = caption
                    });
                }
            }
        }
    
        ViewBag.Blobs = blobs.ToArray();
        ViewBag.Search = id; // Prevent search box from losing its content
        return View();
    }
    

    이제 Index 메서드가 사용자가 검색 상자에 입력한 값을 포함하는 매개 변수 id 를 허용하는지 확인합니다. 비어 있거나 누락된 id 매개 변수는 모든 사진을 표시해야 임을 나타냅니다.

  4. HomeController 클래스에 다음 도우미 메서드를 추가합니다.

    private bool HasMatchingMetadata(CloudBlockBlob blob, string term)
    {
        foreach (var item in blob.Metadata)
        {
            if (item.Key.StartsWith("Tag") && item.Value.Equals(term, StringComparison.InvariantCultureIgnoreCase))
                return true;
        }
    
        return false;
    }
    

    이 메서드는 지정된 이미지 Blob에 연결된 메타데이터 키워드(keyword) 사용자가 입력한 검색어를 포함하는지 여부를 확인하기 위해 Index 메서드에 의해 호출됩니다.

  5. 애플리케이션을 다시 시작하고 여러 장의 사진을 업로드합니다. 자습서와 함께 제공되는 사진뿐만 아니라 자신의 사진을 자유롭게 사용할 수 있습니다.

  6. 검색 상자에 "river"와 같은 키워드를 입력합니다. 그런 다음 검색 버튼을 선택합니다.

    Performing a search

  7. 검색 결과는 입력한 내용과 업로드한 이미지에 따라 달라집니다. 그러나 결과는 메타데이터 키워드(keyword) 입력한 키워드(keyword) 전부 또는 일부를 포함하는 필터링된 이미지 목록이어야 합니다.

    Search results

  8. 모든 이미지를 다시 표시하려면 브라우저의 뒤로 버튼을 선택하세요.

거의 완료되었습니다. 이제 앱을 클라우드에 배포할 때입니다.

Azure에 앱 배포

이 섹션에서는 Visual Studio에서 Azure에 앱을 배포합니다. Visual Studio에서 Azure Web App을 만들 수 있으므로 Azure Portal로 이동하여 별도로 만들 필요가 없습니다.

  1. 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 상황에 맞는 메뉴에서 게시...를 선택합니다. Microsoft Azure App Service새로 만들기가 선택되어 있는지 확인한 다음 게시 버튼을 선택합니다.

    Publishing the app

  2. 다음 대화 상자에서 리소스 그룹 아래에서 "IntellipixResources" 리소스 그룹을 선택합니다. "App Service 요금제" 옆에 있는 새로 만들기... 단추를 선택하고 스토리지 계정 만들기에서 스토리지 계정에 대해 선택한 동일한 위치에 새 App Service 요금제를 만들어 다른 모든 곳에서 기본값을 적용합니다. 만들기 버튼을 선택하여 완료합니다.

    Creating an Azure Web App

  3. 잠시 후 앱이 브라우저 창에 표시됩니다. 주소 표시줄의 URL을 확인합니다. 앱이 더 이상 로컬로 실행되지 않습니다. 공개적으로 연결할 수 있는 웹에 있습니다.

    The finished product!

앱을 변경하고 변경 사항을 웹에 푸시하려면 게시 프로세스를 다시 진행합니다. 웹에 게시하기 전에 변경 내용을 로컬로 테스트할 수 있습니다.

리소스 정리

웹앱에서 계속 작업하려면 다음 단계 섹션을 참조하세요. 이 애플리케이션을 계속 사용하지 않으려면 모든 앱별 리소스를 삭제해야 합니다. 리소스를 삭제하려면 Azure Storage 구독 및 Vision 리소스가 포함된 리소스 그룹을 삭제하면 됩니다. 그러면 스토리지 계정, 업로드된 Blob 및 ASP.NET 웹앱과 연결하는 데 필요한 App Service 리소스가 제거됩니다.

리소스 그룹을 삭제하려면 포털에서 리소스 그룹 탭을 열고 이 프로젝트에 사용한 리소스 그룹으로 이동한 후 보기 상단에서 리소스 그룹 삭제를 선택하세요. 삭제할 것인지 확인하기 위해 리소스 그룹의 이름을 입력하라는 메시지가 표시됩니다. 삭제되면 리소스 그룹을 복구할 수 없습니다.

다음 단계

Azure를 사용하고 Intellipix 앱을 더욱 발전하기 위해 수행할 수 있는 작업은 훨씬 더 많습니다. 예를 들어, 사용자 인증 및 사진 삭제에 대한 지원을 추가할 수 있으며, 업로드 후 Azure AI 서비스가 사진을 처리할 때까지 사용자를 기다리게 하는 대신 Azure Functions를 사용하여 Azure AI를 호출할 수 있습니다. Vision API는 이미지가 Blob Storage에 추가될 때마다 비동기적으로 수행됩니다. 개요에 설명된 이미지에 대해 여러 다른 이미지 분석 작업을 수행할 수도 있습니다.