教學課程:使用 Azure AI 視覺在 Azure 儲存體中產生影像中繼資料

在本教學課程中,您將了解如何將 Azure AI 視覺服務整合到 Web 應用程式中,為上傳的影像產生中繼資料。 這適用於數位資產管理 (DAM) 案例,例如,如果公司想要快速產生其所有影像的描述性 標題 或可搜尋關鍵詞。

您將使用 Visual Studio 撰寫 MVC Web 應用程式,以接受使用者上傳的影像,並將映像儲存在 Azure Blob 記憶體中。 您將瞭解如何在 C# 中讀取和寫入 Blob,並使用 Blob 元數據將其他資訊附加至您所建立的 Blob。 然後,您會將使用者上傳的每個影像提交至 Azure AI 視覺 API,以產生標題並在中繼資料搜尋影像。 最後,您可以使用 Visual Studio 將應用程式部署至雲端。

本教學課程會示範如何:

  • 使用 Azure 入口網站 建立記憶體帳戶和記憶體容器
  • 在 Visual Studio 中建立 Web 應用程式,並將其部署至 Azure
  • 使用 Azure AI 視覺 API 從影像中擷取資訊
  • 將元數據附加至 Azure 儲存體 影像
  • 使用 Azure 儲存體 總管檢查影像元數據

提示

使用 Azure AI 視覺來產生中繼資料一節與影像分析最為相關。 如果您只想查看影像分析如何整合到已建立的應用程式,請跳至該處。

如果您沒有 Azure 訂用帳戶,請在開始前建立免費帳戶

必要條件

建立儲存體帳戶

在本節中,您將使用 Azure 入口網站 來建立記憶體帳戶。 然後,您將建立一組容器:一個用來儲存使用者上傳的影像,另一個用來儲存從上傳影像產生的影像縮圖。

  1. 在網頁瀏覽器中,登入 Azure 入口網站。 如果系統要求您登入,請使用您的 Microsoft 帳戶進行登入。

  2. 若要建立儲存體帳戶,請選取左側功能區中的 [+ 建立資源]。 選取 [儲存體],接著按一下 [儲存體帳戶]

    Creating a storage account

  3. 在 [ 名稱 ] 字段中輸入記憶體帳戶的唯一名稱,並確定旁邊會出現綠色複選標記。 此名稱很重要,因為它會形成URL的一部分,透過此URL來存取在此帳戶下建立的 Blob。 將記憶體帳戶放在名為 「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,才能建立 Blob。 選取 [+ 容器] 以建立新的容器。 在 [名稱] 字段中輸入 photos ,然後選取 [Blob] 作為 [公用存取層級]。 然後選取 [確定],建立名為「相片」的容器。

    根據預設,容器及其內容是私人的。 選取 Blob 作為存取層級可公開存取「相片」容器中的 Blob,但不會讓容器本身成為公用。 這是您想要的,因為儲存在「相片」容器中的影像會從 Web 應用程式連結至 。

    Creating a

  8. 重複上一個步驟以建立名為「縮圖」的容器,再次確保容器的 公用存取層級 設定為 Blob

  9. 確認這兩個容器都出現在此記憶體帳戶的容器清單中,且名稱拼字正確。

    The new containers

  10. 關閉 [Blob 服務] 畫面。 選取儲存體帳戶畫面左側功能表中的 [存取金鑰],然後為 [key1] 選取 [KEY] 旁邊的 [複製] 按鈕。 將此存取鍵貼到您慣用的文字編輯器中,以供稍後使用。

    Copying the access key

您現在已建立記憶體帳戶,以保存上傳至您要建置之應用程式的映像,以及用來儲存映像的容器。

執行 Azure 儲存體 總管

Azure 儲存體 總管是免費的工具,提供圖形化介面,可在執行 Windows、macOS 和 Linux 的電腦上使用 Azure 儲存體。 它提供與 Azure 入口網站 相同的大部分功能,並提供其他功能,例如檢視 Blob 元數據的功能。 在本節中,您將使用 Microsoft Azure 儲存體總管 來檢視您在上一節中建立的容器。

  1. 如果您尚未安裝 儲存體總管,或想要確定您執行的是最新版本,請移至 http://storageexplorer.com/ 並下載並安裝。

  2. 開始 儲存體總管。 如果系統要求您登入,請使用您的 Microsoft 帳戶來執行此動作,也就是您用來登入 Azure 入口網站 的帳戶。 如果您在儲存體總管的左窗格中看不到儲存體帳戶,請選取下方反白顯示的 [管理帳戶] 按鈕,並確定您的 Microsoft 帳戶和用來建立儲存體帳戶的訂用帳戶都已新增至儲存體總管。

    Managing accounts in Storage Explorer

  3. 選取儲存體帳戶旁的小箭號以顯示其內容,然後選取 [Blob 容器] 旁邊的箭號。 確認您建立的容器會出現在清單中。

    Viewing blob containers

容器目前是空的,但一旦部署應用程式並開始上傳相片,就會變更。 安裝 儲存體總管 可讓您輕鬆查看應用程式寫入 Blob 記憶體的內容。

在 Visual Studio 中建立新的 Web 應用程式

在本節中,您將在 Visual Studio 中建立新的 Web 應用程式,並新增程式代碼以實作上傳影像、將影像寫入 Blob 記憶體,並將其顯示在網頁中所需的基本功能。

  1. 啟動 Visual Studio 並使用 [檔案 -> 新增 -> 專案 ] 命令來建立名為 “Intellipix” 的新 Visual C# ASP.NET Web 應用程式 專案(簡稱 「智能圖片」)。

    Creating a new Web Application project

  2. 在 [新增 ASP.NET Web 應用程式] 對話框中,確定 已選取 MVC 。 然後選取確定

    Creating a new ASP.NET MVC project

  3. 花點時間檢閱 方案總管 中的項目結構。 除此之外,還有一個名為 Controllers 的資料夾 會保存專案的 MVC 控制器 ,還有一 個名為 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.儲存體 的 NuGet 套件新增至專案。 此套件包含從 .NET 應用程式存取 Azure 儲存體 的 API。 確定任何變更,並接受提供給您的任何授權。

    Installing WindowsAzure.Storage

  7. 開啟 Web.config 並將下列語句新增至 <appSettings> 區段,並以您在第一個區段中建立的記憶體帳戶名稱取代 ACCOUNT_NAME,並以您儲存的存取金鑰ACCOUNT_KEY。

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

    重要

    Web.config 檔案的目的是保存訂用帳戶金鑰等機密資訊,而具有 .config 副檔名的檔案的任何 HTTP 要求都是由 ASP.NET 引擎處理,這會傳回「未提供此類型的頁面」訊息。 不過,如果攻擊者能找到其他惡意探索,讓他們檢視 Web.config 內容,他們就能公開該資訊。 如需進一步保護 Web.config 資料所需的額外步驟,請參閱保護連接字串和其他設定資訊

  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 資料夾,並使用 Add -> Class... 命令,將名為 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 方法會列舉容器中的 "photos" Blob,並透過 ASP.NET MVC 的 ViewBag 屬性,將代表這些 Blob 的 Blob 數位傳遞至檢視。 稍後,您將修改檢視來列舉這些物件,並顯示相片縮圖的集合。 您將用來存取記憶體帳戶並列舉 Blob-Cloud 儲存體 AccountCloudBlobClient CloudBlobContainer 等類別,來自您透過 NuGet 安裝的 WindowsAzure.儲存體 套件。

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

    這裡使用的語言是 Razor,可讓您在 HTML 標記中內嵌可執行的程式代碼。 檔案@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 記憶體中的 Blob。 這是因為您將容器的 公用存取層級 設定為 Blob,讓 Blob 在可公開存取內。

  18. 返回 [Azure 儲存體 總管],或在記憶體帳戶下選取"photos"容器,然後重新啟動它。 容器中的 Blob 數目應等於您上傳的相片數目。 按兩下其中一個 Blob 來下載它,並查看儲存在 Blob 中的映像。

    Contents of the

  19. "thumbnails" 儲存體總管 中開啟容器。 開啟其中一個 Blob,以檢視從影像上傳產生的縮圖影像。

應用程式尚未提供一種方式來檢視您上傳的原始影像。 在理想情況下,選取影像縮圖應該會顯示原始影像。 接下來,您將新增該功能。

新增用於檢視相片的燈箱

在本節中,您將使用免費的開放原始碼 JavaScript 連結庫來新增 Lightbox 查看器,讓使用者能夠查看他們上傳的原始影像(而非影像縮圖)。 系統會為您提供這些檔案。 您只需要將它們整合到專案中,並稍微修改 Index.cshtml

  1. GitHub 程式代碼存放下載lightbox.csslightbox.js檔案。

  2. 在 方案總管 中,以滑鼠右鍵按兩下專案的 Scripts 資料夾,並使用[新增-> 新增專案...] 命令來建立lightbox.js檔案。 貼上 GitHub 程式代碼存放庫中範例檔案的內容。

  3. 以滑鼠右鍵按兩下專案的 [內容] 資料夾,然後使用 [新增 -> 新增專案... ] 命令來建立 lightbox.css 檔案。 貼上 GitHub 程式代碼存放庫中範例檔案的內容。

  4. 從 GitHub 資料檔存放庫下載並解壓縮 buttons.zip 檔案: https://github.com/Azure-Samples/cognitive-services-sample-data-files/tree/master/ComputerVision/storage-lab-tutorial。 您應該有四個按鈕影像。

  5. 以滑鼠右鍵按兩下 方案總管中的 Intellipix 專案,並使用 [新增 -> 新增資料夾] 命令,將名為 “Images” 的資料夾新增至專案。

  6. 以滑鼠右鍵按兩下 Images 資料夾,並使用 [新增 -> 現有專案... ] 命令匯入您下載的四個影像。

  7. 在專案的 「App_Start」 資料夾中開啟 BundleConfig.cs 。 將下列語句新增至 RegisterBundles BundleConfig.cs 中的 方法:

    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. 最後一項工作是將 lightbox 查看器併入首頁。 若要這樣做,請開啟 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. 選取 Lightbox 右下角的 X 來將其關閉。

現在您可以檢視已上傳的影像。 下一個步驟是使用這些映像執行更多動作。

使用 Azure AI 視覺來產生中繼資料

建立視覺資源

您必須為 Azure 帳戶建立 電腦視覺 資源;此資源會管理您對 Azure 的 Azure AI 視覺服務的存取權。

  1. 請遵循建立 Azure AI 服務資源中的指示來建立多服務資源或視覺資源。

  2. 然後移至資源群組的功能表,選取您建立的視覺資源。 將 [端點] 底下的 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 視覺認證

接著,您會將必要的認證新增至您的應用程式,使其可存取視覺資源。

流覽至 專案根目錄的 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 視覺服務來建立影像中繼資料的程式碼。

  1. 在專案的 Controllers 資料夾中開啟HomeController.cs檔案,並在檔案頂端新增下列using語句:

    using Azure;
    using Azure.AI.Vision.ImageAnalysis;
    using System;
    
  2. 然後,移至 Upload 方法;這個方法會將影像轉換為 Blob 記憶體。 在開頭 // Generate a thumbnail 為 的區塊後面立即新增下列程式代碼(或在 image-blob-creation 程序結束時)。 此程式碼會取用包含影像的 Blob (photo),並使用 Azure AI 視覺產生該影像的描述。 Azure AI 視覺 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 儲存體 Explorer 來檢視您用於映像的記憶體容器。 以滑鼠右鍵按兩下容器中的任何 Blob,然後選取 [ 屬性]。 在對話框中,您會看到索引鍵/值組的清單。 計算機產生的影像描述會儲存在專案中 Caption,而搜尋關鍵詞會儲存在 Tag0Tag1等等。 完成作業後,請選取 [取消] 以關閉對話方塊。

Image properties dialog window, with metadata tags listed

將搜尋新增至應用程式

在本節中,您會將搜尋方塊新增至首頁,讓使用者在已上傳的影像上執行關鍵詞搜尋。 關鍵字是 Azure AI 視覺 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;
    }
    

    Index 方法會呼叫這個方法,以判斷附加至指定影像 Blob 的元數據關鍵詞是否包含使用者輸入的搜尋字詞。

  5. 再次啟動應用程式並上傳數張相片。 您可以隨意使用自己的相片,而不只是教學課程所提供的相片。

  6. 在搜尋方塊中輸入關鍵詞,例如 「river」。。 然後選取 [搜尋] 按鈕。

    Performing a search

  7. 搜尋結果會根據您輸入的內容和您上傳的影像而有所不同。 但結果應該是已篩選的影像清單,其元數據關鍵詞包含您輸入之關鍵詞的所有或部分。

    Search results

  8. 選取瀏覽器的上一頁按鈕,來重新顯示所有影像。

您只剩下最後一步。 是時候將應用程式部署至雲端了。

將應用程式部署至 Azure

在本節中,您會從 Visual Studio 將應用程式部署至 Azure。 您將允許 Visual Studio 為您建立 Azure Web 應用程式,讓您不必進入 Azure 入口網站 並個別建立。

  1. 以滑鼠右鍵按兩下 方案總管中的項目,然後從操作功能表中選取 [發佈...]。 確定已選取 Microsoft Azure App Service[建立新項目],然後選取 [發佈] 按鈕。

    Publishing the app

  2. 在下一個對話框中,選取 [資源群組] 底下的 [IntellipixResources] 資源群組。 選取 [App Service 方案] 旁邊的 [新增...] 按鈕,並在 [建立儲存體帳戶] 中為儲存體帳戶選取的同一位置中建立新的 App Service 方案,同時接受其他任何地方的預設值。 選取 [建立] 按鈕來完成。

    Creating an Azure Web App

  3. 幾分鐘后,應用程式會出現在瀏覽器視窗中。 記下網址列中的URL。 應用程式不再在本機執行;它位於網路上,可公開接觸。

    The finished product!

如果您對應用程式進行變更,並想要將變更推送至 Web,請再次執行發佈程式。 您仍然可以在本機測試變更,再發佈至 Web。

清除資源

如果您想要繼續處理 Web 應用程式,請參閱 後續步驟 一節。 如果您不打算繼續使用此應用程式,您應該刪除所有應用程式特定的資源。 若要刪除資源,您可以刪除包含 Azure 儲存體訂用帳戶和視覺資源的資源群組。 這會移除記憶體帳戶、上傳至它的 Blob,以及與 ASP.NET Web 應用程式連線所需的 App Service 資源。

若要刪除資源群組,請在入口網站中開啟 [資源群組] 索引標籤,並瀏覽至您用於此專案的資源群組,然後選取檢視頂端的 [刪除資源群組]。 系統會要求您輸入資源組名,以確認您想要將其刪除。 刪除之後,就無法復原資源群組。

下一步

您可以執行更多動作來使用 Azure 並進一步開發 Intellipix 應用程式。 例如,您可以新增驗證使用者和刪除相片的支援,而不是強制使用者等候 Azure AI 服務在上傳之後處理相片,您可以使用 Azure Functions,在每次將影像新增至 Blob 儲存體時,以非同步方式呼叫 Azure AI 視覺 API。 您也可以在影像上執行任意數目的其他影像分析作業,如概觀中所述。