共用方式為


快速入門:使用自訂視覺用戶端程式庫建立物件偵測專案

開始使用適用於 .NET 的自訂視覺用戶端程式庫。 請遵循下列步驟來安裝套件,並試用建立物件偵測模型的程式碼範例。 您將建立專案、新增標記、在範例影像上將專案定型,並使用專案的預測端點 URL 以程式設計方式加以測試。 請使用此範例作為自行建置影像辨識應用程式的範本。

注意

如果您想要在「不用」撰寫程式碼的情況下,建立和訓練物件偵測模型,請改為參閱以瀏覽器為基礎的指引

參考文件 | 程式庫原始程式碼 (定型) (預測) | 套件 (NuGet) (定型) (預測) | 範例

必要條件

建立環境變數

在此範例中,您會在執行應用程式的本機電腦上將認證寫入環境變數。

前往 Azure 入口網站。 如果您在 [必要條件] 區段中建立的自訂視覺資源成功部署,請選取 [後續步驟] 底下的 [前往資源] 按鈕。 您可以在 [資源管理] 底下的 [金鑰和端點] 頁面中找到金鑰和端點。 您將需要為定型和預測資源取得金鑰以及 API 端點。

您可以在 Azure 入口網站中預測資源的 [屬性] 索引標籤上找到預測資源識別碼,該識別碼名為 [資源識別碼]。

提示

您也可以使用 https://www.customvision.ai/ 來取得這些值。 登入之後,請選取右上方的 [設定] 圖示。 在 [設定] 頁面上,您可以檢視所有金鑰、資源識別碼和端點。

警告

請勿在程式碼中直接包含索引碼,且切勿公開張貼索引碼。 如需更多驗證選項 (例如 Azure Key Vault),請參閱 Azure AI 服務安全性文章。

若要設定環境變數,請開啟主控台視窗,然後遵循作業系統和開發環境的指示進行。

  1. 若要設定 VISION_TRAINING KEY 環境變數,請以您的定型資源的其中一個金鑰取代 your-training-key
  2. 若要設定 VISION_TRAINING_ENDPOINT 環境變數,請將 your-training-endpoint 取代為定型資源的端點。
  3. 若要設定 VISION_PREDICTION_KEY 環境變數,請以您的預測資源的其中一個金鑰取代 your-prediction-key
  4. 若要設定 VISION_PREDICTION_ENDPOINT 環境變數,請將 your-prediction-endpoint 取代為預測資源的端點。
  5. 若要設定 VISION_PREDICTION_RESOURCE_ID 環境變數,請將 your-resource-id 取代為預測資源的資源識別碼。
setx VISION_TRAINING_KEY your-training-key
setx VISION_TRAINING_ENDPOINT your-training-endpoint
setx VISION_PREDICTION_KEY your-prediction-key
setx VISION_PREDICTION_ENDPOINT your-prediction-endpoint
setx VISION_PREDICTION_RESOURCE_ID your-resource-id

新增環境變數之後,您可能需要重新啟動任何將讀取環境變數的執行中程式,包括主控台視窗。

設定

建立新的 C# 應用程式

使用 Visual Studio,建立新的 .NET Core 應用程式。

安裝用戶端程式庫

建立新專案後,以滑鼠右鍵按一下 [方案總管] 中的專案解決方案,然後選取 [管理 NuGet 套件],以安裝用戶端程式庫。 在開啟的套件管理員中,選取 [瀏覽]、核取 [包含發行前版本],然後搜尋 Microsoft.Azure.CognitiveServices.Vision.CustomVision.TrainingMicrosoft.Azure.CognitiveServices.Vision.CustomVision.Prediction。 選取最新版本,然後選取 [安裝]

提示

想要立刻檢視整個快速入門程式碼檔案嗎? 您可以在 GitHub 上找到該檔案,其中包含本快速入門中的程式碼範例。

從專案目錄中中開啟 program.cs 檔案,並新增下列 using 指示詞:

using Microsoft.Azure.CognitiveServices.Vision.CustomVision.Prediction;
using Microsoft.Azure.CognitiveServices.Vision.CustomVision.Training;
using Microsoft.Azure.CognitiveServices.Vision.CustomVision.Training.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;

在應用程式的 Main 方法中,建立變數,以從環境變數擷取資源的金鑰和端點。 您也會宣告一些要在稍後使用的基本物件。

    string trainingEndpoint = Environment.GetEnvironmentVariable("VISION_TRAINING_ENDPOINT");

    string trainingKey = Environment.GetEnvironmentVariable("VISION_TRAINING_KEY");
    string predictionEndpoint = Environment.GetEnvironmentVariable("VISION_PREDICTION_ENDPOINT");
    string predictionKey = Environment.GetEnvironmentVariable("VISION_PREDICTION_KEY");

    private static Iteration iteration;
    private static string publishedModelName = "CustomODModel";

在應用程式的 Main 方法中,針對本快速入門中使用的方法新增呼叫。 您稍後會實作這些呼叫。

CustomVisionTrainingClient trainingApi = AuthenticateTraining(trainingEndpoint, trainingKey);
CustomVisionPredictionClient predictionApi = AuthenticatePrediction(predictionEndpoint, predictionKey);

Project project = CreateProject(trainingApi);
AddTags(trainingApi, project);
UploadImages(trainingApi, project);
TrainProject(trainingApi, project);
PublishIteration(trainingApi, project);
TestIteration(predictionApi, project);

驗證用戶端

在新方法中,使用您的端點和金鑰來具現化定型和預測用戶端。

private CustomVisionTrainingClient AuthenticateTraining(string endpoint, string trainingKey, string predictionKey)
{
    // Create the Api, passing in the training key
    CustomVisionTrainingClient trainingApi = new CustomVisionTrainingClient(new Microsoft.Azure.CognitiveServices.Vision.CustomVision.Training.ApiKeyServiceClientCredentials(trainingKey))
    {
        Endpoint = endpoint
    };
    return trainingApi;
}
private CustomVisionPredictionClient AuthenticatePrediction(string endpoint, string predictionKey)
{
    // Create a prediction endpoint, passing in the obtained prediction key
    CustomVisionPredictionClient predictionApi = new CustomVisionPredictionClient(new Microsoft.Azure.CognitiveServices.Vision.CustomVision.Prediction.ApiKeyServiceClientCredentials(predictionKey))
    {
        Endpoint = endpoint
    };
    return predictionApi;
}

建立新的自訂視覺專案

下一個方法會建立物件偵測專案。 所建立的專案會顯示在自訂視覺網站上。 當您建立專案時,請參閱 CreateProject 方法來指定其他選項 (如建置偵測器 Web 入口網站指南中所述)。

private Project CreateProject(CustomVisionTrainingClient trainingApi)
{
    // Find the object detection domain
    var domains = trainingApi.GetDomains();
    var objDetectionDomain = domains.FirstOrDefault(d => d.Type == "ObjectDetection");

    // Create a new project
    Console.WriteLine("Creating new project:");
    project = trainingApi.CreateProject("My New Project", null, objDetectionDomain.Id);

    return project;
}

將標記新增至專案

此方法會定義您將用來定型模型的標記。

private void AddTags(CustomVisionTrainingClient trainingApi, Project project)
{
    // Make two tags in the new project
    var forkTag = trainingApi.CreateTag(project.Id, "fork");
    var scissorsTag = trainingApi.CreateTag(project.Id, "scissors");
}

上傳並標記影像

首先,下載此專案的範例影像。 將範例影像資料夾的內容儲存到您的本機裝置。

為物件偵測專案中的影像加上標記時,您必須使用標準化座標來識別每個加上標記的物件所屬的區域。 下列程式碼會為每個範例影像及其已加上標記的區域建立關聯。

private void UploadImages(CustomVisionTrainingClient trainingApi, Project project)
{
    Dictionary<string, double[]> fileToRegionMap = new Dictionary<string, double[]>()
    {
        // FileName, Left, Top, Width, Height
        {"scissors_1", new double[] { 0.4007353, 0.194068655, 0.259803921, 0.6617647 } },
        {"scissors_2", new double[] { 0.426470578, 0.185898721, 0.172794119, 0.5539216 } },
        {"scissors_3", new double[] { 0.289215684, 0.259428144, 0.403186262, 0.421568632 } },
        {"scissors_4", new double[] { 0.343137264, 0.105833367, 0.332107842, 0.8055556 } },
        {"scissors_5", new double[] { 0.3125, 0.09766343, 0.435049027, 0.71405226 } },
        {"scissors_6", new double[] { 0.379901975, 0.24308826, 0.32107842, 0.5718954 } },
        {"scissors_7", new double[] { 0.341911763, 0.20714055, 0.3137255, 0.6356209 } },
        {"scissors_8", new double[] { 0.231617644, 0.08459154, 0.504901946, 0.8480392 } },
        {"scissors_9", new double[] { 0.170343131, 0.332957536, 0.767156839, 0.403594762 } },
        {"scissors_10", new double[] { 0.204656869, 0.120539248, 0.5245098, 0.743464053 } },
        {"scissors_11", new double[] { 0.05514706, 0.159754932, 0.799019635, 0.730392158 } },
        {"scissors_12", new double[] { 0.265931368, 0.169558853, 0.5061275, 0.606209159 } },
        {"scissors_13", new double[] { 0.241421565, 0.184264734, 0.448529422, 0.6830065 } },
        {"scissors_14", new double[] { 0.05759804, 0.05027781, 0.75, 0.882352948 } },
        {"scissors_15", new double[] { 0.191176474, 0.169558853, 0.6936275, 0.6748366 } },
        {"scissors_16", new double[] { 0.1004902, 0.279036, 0.6911765, 0.477124184 } },
        {"scissors_17", new double[] { 0.2720588, 0.131977156, 0.4987745, 0.6911765 } },
        {"scissors_18", new double[] { 0.180147052, 0.112369314, 0.6262255, 0.6666667 } },
        {"scissors_19", new double[] { 0.333333343, 0.0274019931, 0.443627447, 0.852941155 } },
        {"scissors_20", new double[] { 0.158088237, 0.04047389, 0.6691176, 0.843137264 } },
        {"fork_1", new double[] { 0.145833328, 0.3509314, 0.5894608, 0.238562092 } },
        {"fork_2", new double[] { 0.294117659, 0.216944471, 0.534313738, 0.5980392 } },
        {"fork_3", new double[] { 0.09191177, 0.0682516545, 0.757352948, 0.6143791 } },
        {"fork_4", new double[] { 0.254901975, 0.185898721, 0.5232843, 0.594771266 } },
        {"fork_5", new double[] { 0.2365196, 0.128709182, 0.5845588, 0.71405226 } },
        {"fork_6", new double[] { 0.115196079, 0.133611143, 0.676470637, 0.6993464 } },
        {"fork_7", new double[] { 0.164215669, 0.31008172, 0.767156839, 0.410130739 } },
        {"fork_8", new double[] { 0.118872553, 0.318251669, 0.817401946, 0.225490168 } },
        {"fork_9", new double[] { 0.18259804, 0.2136765, 0.6335784, 0.643790841 } },
        {"fork_10", new double[] { 0.05269608, 0.282303959, 0.8088235, 0.452614367 } },
        {"fork_11", new double[] { 0.05759804, 0.0894935, 0.9007353, 0.3251634 } },
        {"fork_12", new double[] { 0.3345588, 0.07315363, 0.375, 0.9150327 } },
        {"fork_13", new double[] { 0.269607842, 0.194068655, 0.4093137, 0.6732026 } },
        {"fork_14", new double[] { 0.143382356, 0.218578458, 0.7977941, 0.295751631 } },
        {"fork_15", new double[] { 0.19240196, 0.0633497, 0.5710784, 0.8398692 } },
        {"fork_16", new double[] { 0.140931368, 0.480016381, 0.6838235, 0.240196079 } },
        {"fork_17", new double[] { 0.305147052, 0.2512582, 0.4791667, 0.5408496 } },
        {"fork_18", new double[] { 0.234068632, 0.445702642, 0.6127451, 0.344771236 } },
        {"fork_19", new double[] { 0.219362751, 0.141781077, 0.5919118, 0.6683006 } },
        {"fork_20", new double[] { 0.180147052, 0.239820287, 0.6887255, 0.235294119 } }
    };

注意

在您自己的專案中,如果您沒有按住並拖曳公用程式可標示區域的座標,您可以使用自訂視覺網站上的 Web UI。 此範例已提供座標。

然後,此關聯對應會用來上傳每個範例影像及其區域座標。 您最多可以在單一批次中上傳 64 個影像。 您可能需要變更 imagePath 值,以指向正確的資料夾位置。

    // Add all images for fork
    var imagePath = Path.Combine("Images", "fork");
    var imageFileEntries = new List<ImageFileCreateEntry>();
    foreach (var fileName in Directory.EnumerateFiles(imagePath))
    {
        var region = fileToRegionMap[Path.GetFileNameWithoutExtension(fileName)];
        imageFileEntries.Add(new ImageFileCreateEntry(fileName, File.ReadAllBytes(fileName), null, new List<Region>(new Region[] { new Region(forkTag.Id, region[0], region[1], region[2], region[3]) })));
    }
    trainingApi.CreateImagesFromFiles(project.Id, new ImageFileCreateBatch(imageFileEntries));

    // Add all images for scissors
    imagePath = Path.Combine("Images", "scissors");
    imageFileEntries = new List<ImageFileCreateEntry>();
    foreach (var fileName in Directory.EnumerateFiles(imagePath))
    {
        var region = fileToRegionMap[Path.GetFileNameWithoutExtension(fileName)];
        imageFileEntries.Add(new ImageFileCreateEntry(fileName, File.ReadAllBytes(fileName), null, new List<Region>(new Region[] { new Region(scissorsTag.Id, region[0], region[1], region[2], region[3]) })));
    }
    trainingApi.CreateImagesFromFiles(project.Id, new ImageFileCreateBatch(imageFileEntries));
}

此時,您已上傳所有影像範例,並為每個影像 (叉子剪刀) 標記上相關聯的像素矩形。

為專案定型

此方法會建立專案中的第一個定型反覆運算。 其會查詢服務,直到定型完成為止。

private void TrainProject(CustomVisionTrainingClient trainingApi, Project project)
{

    // Now there are images with tags start training the project
    Console.WriteLine("\tTraining");
    iteration = trainingApi.TrainProject(project.Id);

    // The returned iteration will be in progress, and can be queried periodically to see when it has completed
    while (iteration.Status == "Training")
    {
        Thread.Sleep(1000);

        // Re-query the iteration to get its updated status
        iteration = trainingApi.GetIteration(project.Id, iteration.Id);
    }
}

提示

使用選取的標記進行訓練

您可以選擇只在已套用的標記子集上進行訓練。 您可以在尚未套用足夠的特定標記,但其他套用的標記已足夠時執行此操作。 在 TrainProject 呼叫中,使用 trainingParameters 參數。 建構 TrainingParameters,並將其 SelectedTags 屬性設定為您要使用的標記識別碼清單。 此模型將訓練為僅辨識該清單上的標記。

發佈目前的反覆項目

此方法會讓模型的目前反覆運算可供查詢。 您可以使用模型名稱作為參考,以傳送預測要求。 您必須針對 predictionResourceId 輸入自己的值。 您可以在 Azure 入口網站中資源的 [屬性] 索引標籤上找到預測資源識別碼,該識別碼名為 [資源識別碼]

private void PublishIteration(CustomVisionTrainingClient trainingApi, Project project)
{

    // The iteration is now trained. Publish it to the prediction end point.
    var predictionResourceId = Environment.GetEnvironmentVariable("VISION_PREDICTION_RESOURCE_ID");
    trainingApi.PublishIteration(project.Id, iteration.Id, publishedModelName, predictionResourceId);
    Console.WriteLine("Done!\n");
}

測試預測端點

此方法會載入測試影像、查詢模型端點,並將預測資料輸出至主控台。

private void TestIteration(CustomVisionPredictionClient predictionApi, Project project)
{

    // Make a prediction against the new project
    Console.WriteLine("Making a prediction:");
    var imageFile = Path.Combine("Images", "test", "test_image.jpg");
    using (var stream = File.OpenRead(imageFile))
    {
        var result = predictionApi.DetectImage(project.Id, publishedModelName, stream);

        // Loop over each prediction and write out the results
        foreach (var c in result.Predictions)
        {
            Console.WriteLine($"\t{c.TagName}: {c.Probability:P1} [ {c.BoundingBox.Left}, {c.BoundingBox.Top}, {c.BoundingBox.Width}, {c.BoundingBox.Height} ]");
        }
    }
    Console.ReadKey();
}

執行應用程式

按一下 IDE 視窗頂端的 [偵錯] 按鈕,以執行應用程式。

應用程式在執行時,應會開啟主控台視窗並寫入下列輸出:

Creating new project:
        Training
Done!

Making a prediction:
        fork: 98.2% [ 0.111609578, 0.184719115, 0.6607002, 0.6637112 ]
        scissors: 1.2% [ 0.112389535, 0.119195729, 0.658031344, 0.7023591 ]

接著,您可以確認測試影像 (位於 Images/Test/ 中) 是否已正確加上標記,以及偵測的區域是否正確。 此時,您可以按任意鍵以結束應用程式。

清除資源

如果您想要實作您自己的物件偵測專案 (或改為嘗試影像分類專案),您可以刪除此範例中的叉子/剪刀偵測專案。 免費訂用帳戶可使用兩個自訂視覺專案。

自訂視覺網站上,瀏覽至 [專案],然後選取 [我的新專案] 底下的資源回收筒。

面板的螢幕擷取畫面,該面板標示為 [我的新專案] 並有資源回收筒圖示。

下一步

現在,您已完成在程式碼中執行物件偵測程序的每個步驟。 此範例會執行單一的訓練反覆項目,但您通常必須對模型進行多次訓練和測試,以便提升其精確度。 下列指南會處理影像分類,但其原則類似於物件偵測。

本指南提供指示和範例程式碼,可協助您開始使用適用於 Go 的自訂視覺用戶端程式庫來建置物件偵測模型。 您將建立專案、新增標籤、將專案定型,並使用專案的預測端點 URL 以程式設計方式加以測試。 請使用此範例作為自行建置影像辨識應用程式的範本。

注意

如果您想要在「不用」撰寫程式碼的情況下,建立和訓練物件偵測模型,請改為參閱以瀏覽器為基礎的指引

使用適用於 Go 的自訂視覺用戶端程式庫可執行下列作業:

  • 建立新的自訂視覺專案
  • 將標記新增至專案
  • 上傳和標記影像
  • 為專案定型
  • 發佈目前的反覆項目
  • 測試預測端點

參考文件 (訓練)(預測)

必要條件

  • Azure 訂用帳戶 - 建立免費帳戶
  • Go 1.8+
  • 擁有 Azure 訂閱之後,在 Azure 入口網站中建立自訂視覺資源,以建立定型和預測資源。
    • 您可以使用免費定價層 (F0) 來試用服務,之後可升級至付費層以用於實際執行環境。

建立環境變數

在此範例中,您會在執行應用程式的本機電腦上將認證寫入環境變數。

前往 Azure 入口網站。 如果您在 [必要條件] 區段中建立的自訂視覺資源成功部署,請選取 [後續步驟] 底下的 [前往資源] 按鈕。 您可以在 [資源管理] 底下的 [金鑰和端點] 頁面中找到金鑰和端點。 您將需要為定型和預測資源取得金鑰以及 API 端點。

您可以在 Azure 入口網站中預測資源的 [屬性] 索引標籤上找到預測資源識別碼,該識別碼名為 [資源識別碼]。

提示

您也可以使用 https://www.customvision.ai/ 來取得這些值。 登入之後,請選取右上方的 [設定] 圖示。 在 [設定] 頁面上,您可以檢視所有金鑰、資源識別碼和端點。

警告

請勿在程式碼中直接包含索引碼,且切勿公開張貼索引碼。 如需更多驗證選項 (例如 Azure Key Vault),請參閱 Azure AI 服務安全性文章。

若要設定環境變數,請開啟主控台視窗,然後遵循作業系統和開發環境的指示進行。

  1. 若要設定 VISION_TRAINING KEY 環境變數,請以您的定型資源的其中一個金鑰取代 your-training-key
  2. 若要設定 VISION_TRAINING_ENDPOINT 環境變數,請將 your-training-endpoint 取代為定型資源的端點。
  3. 若要設定 VISION_PREDICTION_KEY 環境變數,請以您的預測資源的其中一個金鑰取代 your-prediction-key
  4. 若要設定 VISION_PREDICTION_ENDPOINT 環境變數,請將 your-prediction-endpoint 取代為預測資源的端點。
  5. 若要設定 VISION_PREDICTION_RESOURCE_ID 環境變數,請將 your-resource-id 取代為預測資源的資源識別碼。
setx VISION_TRAINING_KEY your-training-key
setx VISION_TRAINING_ENDPOINT your-training-endpoint
setx VISION_PREDICTION_KEY your-prediction-key
setx VISION_PREDICTION_ENDPOINT your-prediction-endpoint
setx VISION_PREDICTION_RESOURCE_ID your-resource-id

新增環境變數之後,您可能需要重新啟動任何將讀取環境變數的執行中程式,包括主控台視窗。

設定

安裝自訂視覺用戶端程式庫

若要使用適用於 Go 的自訂視覺來撰寫影像分析應用程式,您將需要自訂視覺服務用戶端程式庫。 在 PowerShell 中執行下列命令:

go get -u github.com/Azure/azure-sdk-for-go/...

或者,如果您使用 dep,請在存放庫中執行:

dep ensure -add github.com/Azure/azure-sdk-for-go

取得範例影像

此範例會使用 GitHub 上的 Azure AI 服務 Python SDK 範例存放庫中的影像。 將此存放庫複製或下載到您的開發環境。 請記住其資料夾位置以便執行後續步驟。

建立自訂視覺專案

在您偏好的專案目錄中建立名為 sample.go 的新檔案,接著在您偏好的程式碼編輯器中開啟。

在指令碼中新增下列程式碼,以建立新的自訂視覺服務專案。

當您建立專案時,請參閱 CreateProject 方法來指定其他選項 (如建置偵測器 Web 入口網站指南中所述)。

import(
    "context"
    "bytes"
    "fmt"
    "io/ioutil"
    "path"
    "log"
    "time"
    "github.com/Azure/azure-sdk-for-go/services/cognitiveservices/v3.0/customvision/training"
    "github.com/Azure/azure-sdk-for-go/services/cognitiveservices/v3.0/customvision/prediction"
)

// retrieve environment variables:
var (
    training_key string = os.Getenv("VISION_TRAINING_KEY")
    prediction_key string = os.Getenv("VISION_PREDICTION_KEY")
    prediction_resource_id = os.Getenv("VISION_PREDICTION_RESOURCE_ID")
    endpoint string = os.Getenv("VISION_ENDPOINT")
   
    project_name string = "Go Sample OD Project"
    iteration_publish_name = "detectModel"
    sampleDataDirectory = "<path to sample images>"
)

func main() {
    fmt.Println("Creating project...")

    ctx = context.Background()

    trainer := training.New(training_key, endpoint)

    var objectDetectDomain training.Domain
    domains, _ := trainer.GetDomains(ctx)

    for _, domain := range *domains.Value {
        fmt.Println(domain, domain.Type)
        if domain.Type == "ObjectDetection" && *domain.Name == "General" {
            objectDetectDomain = domain
            break
        }
    }
    fmt.Println("Creating project...")
    project, _ := trainer.CreateProject(ctx, project_name, "", objectDetectDomain.ID, "")

在專案中建立標記

若要在專案中建立分類標記,請在 sample.go 結尾新增以下程式碼:

# Make two tags in the new project
forkTag, _ := trainer.CreateTag(ctx, *project.ID, "fork", "A fork", string(training.Regular))
scissorsTag, _ := trainer.CreateTag(ctx, *project.ID, "scissors", "Pair of scissors", string(training.Regular))

上傳並標記影像

為物件偵測專案中的影像加上標記時,您必須使用標準化座標來識別每個加上標記的物件所屬的區域。

注意

如果您沒有按住並拖曳公用程式可標示區域的座標,您可以使用 Customvision.ai 上的 Web UI。 此範例已提供座標。

若要將影像、標記和區域新增至專案,請在標記建立之後插入下列程式碼。 請注意,在本教學課程中,區域會以硬式編碼方式內嵌。 這些區域會在標準化座標中指定週框方塊,且座標會以下列順序指定:左、上、寬度、高度。

forkImageRegions := map[string][4]float64{
    "fork_1.jpg": [4]float64{ 0.145833328, 0.3509314, 0.5894608, 0.238562092 },
    "fork_2.jpg": [4]float64{ 0.294117659, 0.216944471, 0.534313738, 0.5980392 },
    "fork_3.jpg": [4]float64{ 0.09191177, 0.0682516545, 0.757352948, 0.6143791 },
    "fork_4.jpg": [4]float64{ 0.254901975, 0.185898721, 0.5232843, 0.594771266 },
    "fork_5.jpg": [4]float64{ 0.2365196, 0.128709182, 0.5845588, 0.71405226 },
    "fork_6.jpg": [4]float64{ 0.115196079, 0.133611143, 0.676470637, 0.6993464 },
    "fork_7.jpg": [4]float64{ 0.164215669, 0.31008172, 0.767156839, 0.410130739 },
    "fork_8.jpg": [4]float64{ 0.118872553, 0.318251669, 0.817401946, 0.225490168 },
    "fork_9.jpg": [4]float64{ 0.18259804, 0.2136765, 0.6335784, 0.643790841 },
    "fork_10.jpg": [4]float64{ 0.05269608, 0.282303959, 0.8088235, 0.452614367 },
    "fork_11.jpg": [4]float64{ 0.05759804, 0.0894935, 0.9007353, 0.3251634 },
    "fork_12.jpg": [4]float64{ 0.3345588, 0.07315363, 0.375, 0.9150327 },
    "fork_13.jpg": [4]float64{ 0.269607842, 0.194068655, 0.4093137, 0.6732026 },
    "fork_14.jpg": [4]float64{ 0.143382356, 0.218578458, 0.7977941, 0.295751631 },
    "fork_15.jpg": [4]float64{ 0.19240196, 0.0633497, 0.5710784, 0.8398692 },
    "fork_16.jpg": [4]float64{ 0.140931368, 0.480016381, 0.6838235, 0.240196079 },
    "fork_17.jpg": [4]float64{ 0.305147052, 0.2512582, 0.4791667, 0.5408496 },
    "fork_18.jpg": [4]float64{ 0.234068632, 0.445702642, 0.6127451, 0.344771236 },
    "fork_19.jpg": [4]float64{ 0.219362751, 0.141781077, 0.5919118, 0.6683006 },
    "fork_20.jpg": [4]float64{ 0.180147052, 0.239820287, 0.6887255, 0.235294119 },
}

scissorsImageRegions := map[string][4]float64{
    "scissors_1.jpg": [4]float64{ 0.4007353, 0.194068655, 0.259803921, 0.6617647 },
    "scissors_2.jpg": [4]float64{ 0.426470578, 0.185898721, 0.172794119, 0.5539216 },
    "scissors_3.jpg": [4]float64{ 0.289215684, 0.259428144, 0.403186262, 0.421568632 },
    "scissors_4.jpg": [4]float64{ 0.343137264, 0.105833367, 0.332107842, 0.8055556 },
    "scissors_5.jpg": [4]float64{ 0.3125, 0.09766343, 0.435049027, 0.71405226 },
    "scissors_6.jpg": [4]float64{ 0.379901975, 0.24308826, 0.32107842, 0.5718954 },
    "scissors_7.jpg": [4]float64{ 0.341911763, 0.20714055, 0.3137255, 0.6356209 },
    "scissors_8.jpg": [4]float64{ 0.231617644, 0.08459154, 0.504901946, 0.8480392 },
    "scissors_9.jpg": [4]float64{ 0.170343131, 0.332957536, 0.767156839, 0.403594762 },
    "scissors_10.jpg": [4]float64{ 0.204656869, 0.120539248, 0.5245098, 0.743464053 },
    "scissors_11.jpg": [4]float64{ 0.05514706, 0.159754932, 0.799019635, 0.730392158 },
    "scissors_12.jpg": [4]float64{ 0.265931368, 0.169558853, 0.5061275, 0.606209159 },
    "scissors_13.jpg": [4]float64{ 0.241421565, 0.184264734, 0.448529422, 0.6830065 },
    "scissors_14.jpg": [4]float64{ 0.05759804, 0.05027781, 0.75, 0.882352948 },
    "scissors_15.jpg": [4]float64{ 0.191176474, 0.169558853, 0.6936275, 0.6748366 },
    "scissors_16.jpg": [4]float64{ 0.1004902, 0.279036, 0.6911765, 0.477124184 },
    "scissors_17.jpg": [4]float64{ 0.2720588, 0.131977156, 0.4987745, 0.6911765 },
    "scissors_18.jpg": [4]float64{ 0.180147052, 0.112369314, 0.6262255, 0.6666667 },
    "scissors_19.jpg": [4]float64{ 0.333333343, 0.0274019931, 0.443627447, 0.852941155 },
    "scissors_20.jpg": [4]float64{ 0.158088237, 0.04047389, 0.6691176, 0.843137264 },
}

然後,使用此關聯對應,上傳每個範例影像及其區域座標 (您最多可以在單一批次中上傳 64 個影像)。 加入下列程式碼。

注意

您必須根據 Azure AI 服務 Go SDK 範例專案稍早的下載位置,來變更影像的路徑。

// Go through the data table above and create the images
fmt.Println("Adding images...")
var fork_images []training.ImageFileCreateEntry
for file, region := range forkImageRegions {
    imageFile, _ := ioutil.ReadFile(path.Join(sampleDataDirectory, "fork", file))

    regiontest := forkImageRegions[file]
    imageRegion := training.Region{
        TagID:  forkTag.ID,
        Left:   &regiontest[0],
        Top:    &regiontest[1],
        Width:  &regiontest[2],
        Height: &regiontest[3],
    }
    var fileName string = file

    fork_images = append(fork_images, training.ImageFileCreateEntry{
        Name:     &fileName,
        Contents: &imageFile,
        Regions:  &[]training.Region{imageRegion}
    })
}
    
fork_batch, _ := trainer.CreateImagesFromFiles(ctx, *project.ID, training.ImageFileCreateBatch{ 
    Images: &fork_images,
})

if (!*fork_batch.IsBatchSuccessful) {
    fmt.Println("Batch upload failed.")
}

var scissor_images []training.ImageFileCreateEntry
for file, region := range scissorsImageRegions {
    imageFile, _ := ioutil.ReadFile(path.Join(sampleDataDirectory, "scissors", file))

    imageRegion := training.Region { 
        TagID:scissorsTag.ID,
        Left:&region[0],
        Top:&region[1],
        Width:&region[2],
        Height:&region[3],
    }

    scissor_images = append(scissor_images, training.ImageFileCreateEntry {
        Name: &file,
        Contents: &imageFile,
        Regions: &[]training.Region{ imageRegion },
    })
}
    
scissor_batch, _ := trainer.CreateImagesFromFiles(ctx, *project.ID, training.ImageFileCreateBatch{ 
    Images: &scissor_images,
})
    
if (!*scissor_batch.IsBatchSuccessful) {
    fmt.Println("Batch upload failed.")
}     

訓練及發佈專案

此程式碼會在預測模型中建立第一個反覆項目,然後將該反覆項目發佈至預測端點。 提供給已發佈反覆項目的名稱可用來傳送預測要求。 反覆項目要等到發佈後才可在預測端點中使用。

iteration, _ := trainer.TrainProject(ctx, *project.ID)
fmt.Println("Training status:", *iteration.Status)
for {
    if *iteration.Status != "Training" {
        break
    }
    time.Sleep(5 * time.Second)
    iteration, _ = trainer.GetIteration(ctx, *project.ID, *iteration.ID)
    fmt.Println("Training status:", *iteration.Status)
}

trainer.PublishIteration(ctx, *project.ID, *iteration.ID, iteration_publish_name, prediction_resource_id))

使用預測端點

若要將影像傳送到預測端點並擷取預測,在檔案結尾處新增以下程式碼:

    fmt.Println("Predicting...")
    predictor := prediction.New(prediction_key, endpoint)

    testImageData, _ := ioutil.ReadFile(path.Join(sampleDataDirectory, "Test", "test_od_image.jpg"))
    results, _ := predictor.DetectImage(ctx, *project.ID, iteration_publish_name, ioutil.NopCloser(bytes.NewReader(testImageData)), "")

    for _, prediction := range *results.Predictions    {
        boundingBox := *prediction.BoundingBox

        fmt.Printf("\t%s: %.2f%% (%.2f, %.2f, %.2f, %.2f)", 
            *prediction.TagName,
            *prediction.Probability * 100,
            *boundingBox.Left,
            *boundingBox.Top,
            *boundingBox.Width,
            *boundingBox.Height)
        fmt.Println("")
    }
}

執行應用程式

執行 sample.go

go run sample.go

應用程式的輸出應會顯示在主控台中。 接著,您可以確認測試影像 (位於 samples/vision/images/Test 中) 是否已正確加上標記,以及偵測的區域是否正確。

清除資源

如果您想要實作您自己的物件偵測專案 (或改為嘗試影像分類專案),您可以刪除此範例中的叉子/剪刀偵測專案。 免費訂用帳戶可使用兩個自訂視覺專案。

自訂視覺網站上,瀏覽至 [專案],然後選取 [我的新專案] 底下的資源回收筒。

面板的螢幕擷取畫面,該面板標示為 [我的新專案] 並有資源回收筒圖示。

下一步

現在,您已完成在程式碼中執行物件偵測程序的每個步驟。 此範例會執行單一的訓練反覆項目,但您通常必須對模型進行多次訓練和測試,以便提升其精確度。 下列指南會處理影像分類,但其原則類似於物件偵測。

開始使用適用於 Java 的自訂視覺用戶端程式庫來建置物件偵測模型。 請遵循下列步驟來安裝套件,並試用基本工作的程式碼範例。 請使用此範例作為自行建置影像辨識應用程式的範本。

注意

如果您想要在「不用」撰寫程式碼的情況下,建立和訓練物件偵測模型,請改為參閱以瀏覽器為基礎的指引

使用適用於 Java 的自訂視覺用戶端程式庫可執行下列作業:

  • 建立新的自訂視覺專案
  • 將標記新增至專案
  • 上傳和標記影像
  • 為專案定型
  • 發佈目前的反覆項目
  • 測試預測端點

參考文件 | 程式庫原始程式碼 (訓練) (預測)| 成品 (Maven) (訓練) (預測) | 範例

必要條件

建立環境變數

在此範例中,您會在執行應用程式的本機電腦上將認證寫入環境變數。

前往 Azure 入口網站。 如果您在 [必要條件] 區段中建立的自訂視覺資源成功部署,請選取 [後續步驟] 底下的 [前往資源] 按鈕。 您可以在 [資源管理] 底下的 [金鑰和端點] 頁面中找到金鑰和端點。 您將需要為定型和預測資源取得金鑰以及 API 端點。

您可以在 Azure 入口網站中預測資源的 [屬性] 索引標籤上找到預測資源識別碼,該識別碼名為 [資源識別碼]。

提示

您也可以使用 https://www.customvision.ai/ 來取得這些值。 登入之後,請選取右上方的 [設定] 圖示。 在 [設定] 頁面上,您可以檢視所有金鑰、資源識別碼和端點。

警告

請勿在程式碼中直接包含索引碼,且切勿公開張貼索引碼。 如需更多驗證選項 (例如 Azure Key Vault),請參閱 Azure AI 服務安全性文章。

若要設定環境變數,請開啟主控台視窗,然後遵循作業系統和開發環境的指示進行。

  1. 若要設定 VISION_TRAINING KEY 環境變數,請以您的定型資源的其中一個金鑰取代 your-training-key
  2. 若要設定 VISION_TRAINING_ENDPOINT 環境變數,請將 your-training-endpoint 取代為定型資源的端點。
  3. 若要設定 VISION_PREDICTION_KEY 環境變數,請以您的預測資源的其中一個金鑰取代 your-prediction-key
  4. 若要設定 VISION_PREDICTION_ENDPOINT 環境變數,請將 your-prediction-endpoint 取代為預測資源的端點。
  5. 若要設定 VISION_PREDICTION_RESOURCE_ID 環境變數,請將 your-resource-id 取代為預測資源的資源識別碼。
setx VISION_TRAINING_KEY your-training-key
setx VISION_TRAINING_ENDPOINT your-training-endpoint
setx VISION_PREDICTION_KEY your-prediction-key
setx VISION_PREDICTION_ENDPOINT your-prediction-endpoint
setx VISION_PREDICTION_RESOURCE_ID your-resource-id

新增環境變數之後,您可能需要重新啟動任何將讀取環境變數的執行中程式,包括主控台視窗。

設定

建立新的 Gradle 專案

在主控台視窗 (例如 cmd、PowerShell 或 Bash) 中,為您的應用程式建立新的目錄,並瀏覽至該目錄。

mkdir myapp && cd myapp

從您的工作目錄執行 gradle init 命令。 此命令會建立 Gradle 的基本組建檔案,包括 build.gradle.kts,此檔案將在執行階段用來建立及設定您的應用程式。

gradle init --type basic

出現選擇 DSL 的提示時,請選取 [Kotlin]

安裝用戶端程式庫

找出 build.gradle.kts,並使用您慣用的 IDE 或文字編輯器加以開啟。 然後,在其中複製下列組建組態。 此組態會將專案定義為進入點為 CustomVisionQuickstart 類別的 Java 應用程式。 這會匯入自訂視覺程式庫。

plugins {
    java
    application
}
application { 
    mainClassName = "CustomVisionQuickstart"
}
repositories {
    mavenCentral()
}
dependencies {
    compile(group = "com.azure", name = "azure-cognitiveservices-customvision-training", version = "1.1.0-preview.2")
    compile(group = "com.azure", name = "azure-cognitiveservices-customvision-prediction", version = "1.1.0-preview.2")
}

建立 Java 檔案

在您的工作目錄中執行下列命令,以建立專案來源資料夾:

mkdir -p src/main/java

瀏覽至新的資料夾,並建立名為 CustomVisionQuickstart.java 的檔案。 在您慣用的編輯器或 IDE 中開啟該檔案,並新增下列 import 陳述式:

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

import com.google.common.io.ByteStreams;

import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.Classifier;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.Domain;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.DomainType;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.ImageFileCreateBatch;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.ImageFileCreateEntry;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.Iteration;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.Project;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.Region;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.TrainProjectOptionalParameter;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.CustomVisionTrainingClient;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.Trainings;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.CustomVisionTrainingManager;
import com.microsoft.azure.cognitiveservices.vision.customvision.prediction.models.ImagePrediction;
import com.microsoft.azure.cognitiveservices.vision.customvision.prediction.models.Prediction;
import com.microsoft.azure.cognitiveservices.vision.customvision.prediction.CustomVisionPredictionClient;
import com.microsoft.azure.cognitiveservices.vision.customvision.prediction.CustomVisionPredictionManager;
import com.microsoft.azure.cognitiveservices.vision.customvision.training.models.Tag;

提示

想要立刻檢視整個快速入門程式碼檔案嗎? 您可以在 GitHub 上找到該檔案,其中包含本快速入門中的程式碼範例。

在應用程式的 CustomVisionQuickstart 方法中,建立變數,以從環境變數擷取資源的金鑰和端點。

// retrieve environment variables
final static String trainingApiKey = System.getenv("VISION_TRAINING_KEY");
final static String trainingEndpoint = System.getenv("VISION_TRAINING_ENDPOINT");
final static String predictionApiKey = System.getenv("VISION_PREDICTION_KEY");
final static String predictionEndpoint = System.getenv("VISION_PREDICTION_ENDPOINT");
final static String predictionResourceId = System.getenv("VISION_PREDICTION_RESOURCE_ID");

在應用程式的 main 方法中,針對本快速入門中使用的方法新增呼叫。 稍後您會定義這些項目。

Project projectOD = createProjectOD(trainClient);
addTagsOD(trainClient, projectOD);
uploadImagesOD(trainClient, projectOD);
trainProjectOD(trainClient, projectOD);
publishIterationOD(trainClient, project);
testProjectOD(predictor, projectOD);

物件模型

下列類別和介面會處理自訂視覺 Java 用戶端程式庫的一些主要功能。

名稱 描述
CustomVisionTrainingClient 此類別會處理模型的建立、定型和發佈。
CustomVisionPredictionClient 此類別會處理您的模型查詢,以進行物件偵測預測。
ImagePrediction 此類別會定義單一影像上的單一物件預測。 其中包含物件識別碼和名稱的屬性、物件的周框方塊位置,以及信賴分數。

程式碼範例

這些程式碼片段說明如何使用適用於 Java 的自訂視覺用戶端程式庫來執行下列工作:

驗證用戶端

在您的 main 方法中,使用您的端點和金鑰來具現化定型和預測用戶端。

// Authenticate
CustomVisionTrainingClient trainClient = CustomVisionTrainingManager
        .authenticate(trainingEndpoint, trainingApiKey)
        .withEndpoint(trainingEndpoint);
CustomVisionPredictionClient predictor = CustomVisionPredictionManager
        .authenticate(predictionEndpoint, predictionApiKey)
        .withEndpoint(predictionEndpoint);

建立新的自訂視覺專案

下一個方法會建立物件偵測專案。 所建立的專案會顯示在您稍早瀏覽過的自訂視覺網站上。 當您建立專案時,請參閱 CreateProject 方法多載來指定其他選項 (如建立偵測器 Web 入口網站指南中所述)。

public static Project createProjectOD(CustomVisionTrainingClient trainClient) {
    Trainings trainer = trainClient.trainings();

    // find the object detection domain to set the project type
    Domain objectDetectionDomain = null;
    List<Domain> domains = trainer.getDomains();
    for (final Domain domain : domains) {
        if (domain.type() == DomainType.OBJECT_DETECTION) {
            objectDetectionDomain = domain;
            break;
        }
    }

    if (objectDetectionDomain == null) {
        System.out.println("Unexpected result; no objects were detected.");
    }

    System.out.println("Creating project...");
    // create an object detection project
    Project project = trainer.createProject().withName("Sample Java OD Project")
            .withDescription("Sample OD Project").withDomainId(objectDetectionDomain.id())
            .withClassificationType(Classifier.MULTILABEL.toString()).execute();

    return project;
}

將標記新增到您的專案

此方法會定義您將用來定型模型的標記。

public static void addTagsOD(CustomVisionTrainingClient trainClient, Project project) {
    Trainings trainer = trainClient.trainings();
    // create fork tag
    Tag forkTag = trainer.createTag().withProjectId(project.id()).withName("fork").execute();

    // create scissors tag
    Tag scissorsTag = trainer.createTag().withProjectId(project.id()).withName("scissor").execute();
}

上傳並標記影像

首先,下載此專案的範例影像。 將範例影像資料夾的內容儲存到您的本機裝置。

注意

您需要一組更廣泛的影像來完成訓練嗎? Trove 是 Microsoft Garage 專案,可讓您收集和購買影像集以供訓練使用。 收集影像之後,您可以下載影像,然後以一般方式將其匯入至自訂視覺專案。 如需深入了解,請造訪 Trove 頁面

為物件偵測專案中的影像加上標記時,您必須使用標準化座標來識別每個加上標記的物件所屬的區域。 下列程式碼會為每個範例影像及其已加上標記的區域建立關聯。

注意

如果您沒有按住並拖曳公用程式可標示區域的座標,您可以使用 Customvision.ai 上的 Web UI。 此範例已提供座標。

public static void uploadImagesOD(CustomVisionTrainingClient trainClient, Project project) {
    // Mapping of filenames to their respective regions in the image. The
    // coordinates are specified
    // as left, top, width, height in normalized coordinates. I.e. (left is left in
    // pixels / width in pixels)

    // This is a hardcoded mapping of the files we'll upload along with the bounding
    // box of the object in the
    // image. The boudning box is specified as left, top, width, height in
    // normalized coordinates.
    // Normalized Left = Left / Width (in Pixels)
    // Normalized Top = Top / Height (in Pixels)
    // Normalized Bounding Box Width = (Right - Left) / Width (in Pixels)
    // Normalized Bounding Box Height = (Bottom - Top) / Height (in Pixels)
    HashMap<String, double[]> regionMap = new HashMap<String, double[]>();
    regionMap.put("scissors_1.jpg", new double[] { 0.4007353, 0.194068655, 0.259803921, 0.6617647 });
    regionMap.put("scissors_2.jpg", new double[] { 0.426470578, 0.185898721, 0.172794119, 0.5539216 });
    regionMap.put("scissors_3.jpg", new double[] { 0.289215684, 0.259428144, 0.403186262, 0.421568632 });
    regionMap.put("scissors_4.jpg", new double[] { 0.343137264, 0.105833367, 0.332107842, 0.8055556 });
    regionMap.put("scissors_5.jpg", new double[] { 0.3125, 0.09766343, 0.435049027, 0.71405226 });
    regionMap.put("scissors_6.jpg", new double[] { 0.379901975, 0.24308826, 0.32107842, 0.5718954 });
    regionMap.put("scissors_7.jpg", new double[] { 0.341911763, 0.20714055, 0.3137255, 0.6356209 });
    regionMap.put("scissors_8.jpg", new double[] { 0.231617644, 0.08459154, 0.504901946, 0.8480392 });
    regionMap.put("scissors_9.jpg", new double[] { 0.170343131, 0.332957536, 0.767156839, 0.403594762 });
    regionMap.put("scissors_10.jpg", new double[] { 0.204656869, 0.120539248, 0.5245098, 0.743464053 });
    regionMap.put("scissors_11.jpg", new double[] { 0.05514706, 0.159754932, 0.799019635, 0.730392158 });
    regionMap.put("scissors_12.jpg", new double[] { 0.265931368, 0.169558853, 0.5061275, 0.606209159 });
    regionMap.put("scissors_13.jpg", new double[] { 0.241421565, 0.184264734, 0.448529422, 0.6830065 });
    regionMap.put("scissors_14.jpg", new double[] { 0.05759804, 0.05027781, 0.75, 0.882352948 });
    regionMap.put("scissors_15.jpg", new double[] { 0.191176474, 0.169558853, 0.6936275, 0.6748366 });
    regionMap.put("scissors_16.jpg", new double[] { 0.1004902, 0.279036, 0.6911765, 0.477124184 });
    regionMap.put("scissors_17.jpg", new double[] { 0.2720588, 0.131977156, 0.4987745, 0.6911765 });
    regionMap.put("scissors_18.jpg", new double[] { 0.180147052, 0.112369314, 0.6262255, 0.6666667 });
    regionMap.put("scissors_19.jpg", new double[] { 0.333333343, 0.0274019931, 0.443627447, 0.852941155 });
    regionMap.put("scissors_20.jpg", new double[] { 0.158088237, 0.04047389, 0.6691176, 0.843137264 });
    regionMap.put("fork_1.jpg", new double[] { 0.145833328, 0.3509314, 0.5894608, 0.238562092 });
    regionMap.put("fork_2.jpg", new double[] { 0.294117659, 0.216944471, 0.534313738, 0.5980392 });
    regionMap.put("fork_3.jpg", new double[] { 0.09191177, 0.0682516545, 0.757352948, 0.6143791 });
    regionMap.put("fork_4.jpg", new double[] { 0.254901975, 0.185898721, 0.5232843, 0.594771266 });
    regionMap.put("fork_5.jpg", new double[] { 0.2365196, 0.128709182, 0.5845588, 0.71405226 });
    regionMap.put("fork_6.jpg", new double[] { 0.115196079, 0.133611143, 0.676470637, 0.6993464 });
    regionMap.put("fork_7.jpg", new double[] { 0.164215669, 0.31008172, 0.767156839, 0.410130739 });
    regionMap.put("fork_8.jpg", new double[] { 0.118872553, 0.318251669, 0.817401946, 0.225490168 });
    regionMap.put("fork_9.jpg", new double[] { 0.18259804, 0.2136765, 0.6335784, 0.643790841 });
    regionMap.put("fork_10.jpg", new double[] { 0.05269608, 0.282303959, 0.8088235, 0.452614367 });
    regionMap.put("fork_11.jpg", new double[] { 0.05759804, 0.0894935, 0.9007353, 0.3251634 });
    regionMap.put("fork_12.jpg", new double[] { 0.3345588, 0.07315363, 0.375, 0.9150327 });
    regionMap.put("fork_13.jpg", new double[] { 0.269607842, 0.194068655, 0.4093137, 0.6732026 });
    regionMap.put("fork_14.jpg", new double[] { 0.143382356, 0.218578458, 0.7977941, 0.295751631 });
    regionMap.put("fork_15.jpg", new double[] { 0.19240196, 0.0633497, 0.5710784, 0.8398692 });
    regionMap.put("fork_16.jpg", new double[] { 0.140931368, 0.480016381, 0.6838235, 0.240196079 });
    regionMap.put("fork_17.jpg", new double[] { 0.305147052, 0.2512582, 0.4791667, 0.5408496 });
    regionMap.put("fork_18.jpg", new double[] { 0.234068632, 0.445702642, 0.6127451, 0.344771236 });
    regionMap.put("fork_19.jpg", new double[] { 0.219362751, 0.141781077, 0.5919118, 0.6683006 });
    regionMap.put("fork_20.jpg", new double[] { 0.180147052, 0.239820287, 0.6887255, 0.235294119 });

下一個程式碼區塊會將影像新增至專案。 您需要變更 GetImage 呼叫的引數以指向您先前下載的分支交叉資料夾。

    Trainings trainer = trainClient.trainings();

    System.out.println("Adding images...");
    for (int i = 1; i <= 20; i++) {
        String fileName = "fork_" + i + ".jpg";
        byte[] contents = GetImage("/fork", fileName);
        AddImageToProject(trainer, project, fileName, contents, forkTag.id(), regionMap.get(fileName));
    }

    for (int i = 1; i <= 20; i++) {
        String fileName = "scissors_" + i + ".jpg";
        byte[] contents = GetImage("/scissors", fileName);
        AddImageToProject(trainer, project, fileName, contents, scissorsTag.id(), regionMap.get(fileName));
    }
}

先前的程式碼片段利用兩個協助程式函式,將影像擷取為資源串流,然後上傳到服務 (您最多可以在單一批次中上傳 64 個影像)。 定義這些方法。

private static void AddImageToProject(Trainings trainer, Project project, String fileName, byte[] contents,
        UUID tag, double[] regionValues) {
    System.out.println("Adding image: " + fileName);
    ImageFileCreateEntry file = new ImageFileCreateEntry().withName(fileName).withContents(contents);

    ImageFileCreateBatch batch = new ImageFileCreateBatch().withImages(Collections.singletonList(file));

    // If Optional region is specified, tack it on and place the tag there,
    // otherwise
    // add it to the batch.
    if (regionValues != null) {
        Region region = new Region().withTagId(tag).withLeft(regionValues[0]).withTop(regionValues[1])
                .withWidth(regionValues[2]).withHeight(regionValues[3]);
        file = file.withRegions(Collections.singletonList(region));
    } else {
        batch = batch.withTagIds(Collections.singletonList(tag));
    }

    trainer.createImagesFromFiles(project.id(), batch);
}

private static byte[] GetImage(String folder, String fileName) {
    try {
        return ByteStreams.toByteArray(CustomVisionSamples.class.getResourceAsStream(folder + "/" + fileName));
    } catch (Exception e) {
        System.out.println(e.getMessage());
        e.printStackTrace();
    }
    return null;
}

為專案定型

此方法會建立專案中的第一個定型反覆運算。 其會查詢服務,直到定型完成為止。

public static String trainProjectOD(CustomVisionTrainingClient trainClient, Project project) {
    Trainings trainer = trainClient.trainings();
    System.out.println("Training...");
    Iteration iteration = trainer.trainProject(project.id(), new TrainProjectOptionalParameter());

    while (iteration.status().equals("Training")) {
        System.out.println("Training Status: " + iteration.status());
        Thread.sleep(5000);
        iteration = trainer.getIteration(project.id(), iteration.id());
    }
    System.out.println("Training Status: " + iteration.status());
}

發佈目前的反覆項目

此方法會讓模型的目前反覆運算可供查詢。 您可以使用模型名稱作為參考,以傳送預測要求。 您必須針對 predictionResourceId 輸入自己的值。 您可以在 Azure 入口網站中資源的 [屬性] 索引標籤上找到預測資源識別碼,該識別碼名為 [資源識別碼]

public static String publishIterationOD(CustomVisionTrainingClient trainClient, Project project) {
    Trainings trainer = trainClient.trainings();

    // The iteration is now trained. Publish it to the prediction endpoint.
    String publishedModelName = "myModel";
    String predictionID = "<your-prediction-resource-ID>";
    trainer.publishIteration(project.id(), iteration.id(), publishedModelName, predictionID);
    return publishedModelName;
}

測試預測端點

此方法會載入測試影像、查詢模型端點,並將預測資料輸出至主控台。

public static void testProjectOD(CustomVisionPredictionClient predictor, Project project) {

    // load test image
    byte[] testImage = GetImage("/ObjectTest", "test_image.jpg");

    // predict
    ImagePrediction results = predictor.predictions().detectImage().withProjectId(project.id())
            .withPublishedName(publishedModelName).withImageData(testImage).execute();

    for (Prediction prediction : results.predictions()) {
        System.out.println(String.format("\t%s: %.2f%% at: %.2f, %.2f, %.2f, %.2f", prediction.tagName(),
                prediction.probability() * 100.0f, prediction.boundingBox().left(), prediction.boundingBox().top(),
                prediction.boundingBox().width(), prediction.boundingBox().height()));
    }
}

執行應用程式

您可以使用下列命令來建置應用程式:

gradle build

使用 gradle run 命令執行應用程式:

gradle run

清除資源

如果您想要清除和移除 Azure AI 服務訂用帳戶,則可以刪除資源或資源群組。 刪除資源群組也會刪除與其相關聯的任何其他資源。

如果您想要實作您自己的物件偵測專案 (或改為嘗試影像分類專案),您可以刪除此範例中的叉子/剪刀偵測專案。 免費訂用帳戶可使用兩個自訂視覺專案。

自訂視覺網站上,瀏覽至 [專案],然後選取 [我的新專案] 底下的資源回收筒。

面板的螢幕擷取畫面,該面板標示為 [我的新專案] 並有資源回收筒圖示。

下一步

現在,您已完成在程式碼中執行物件偵測程序的每個步驟。 此範例會執行單一的訓練反覆項目,但您通常必須對模型進行多次訓練和測試,以便提升其精確度。 下列指南會處理影像分類,但其原則類似於物件偵測。

本指南提供指示和範例程式碼,可協助您開始使用適用於 Node.js 的自訂視覺用戶端程式庫來建置物件偵測模型。 您將建立專案、新增標籤、將專案定型,並使用專案的預測端點 URL 以程式設計方式加以測試。 請使用此範例作為自行建置影像辨識應用程式的範本。

注意

如果您想要在「不用」撰寫程式碼的情況下,建立和訓練物件偵測模型,請改為參閱以瀏覽器為基礎的指引

使用適用於 .NET 的自訂視覺用戶端程式庫可執行下列作業:

  • 建立新的自訂視覺專案
  • 將標記新增至專案
  • 上傳和標記影像
  • 為專案定型
  • 發佈目前的反覆項目
  • 測試預測端點

參考文件 (訓練)(預測)| 套件 (npm) (訓練)(預測) | 範例

必要條件

  • Azure 訂用帳戶 - 建立免費帳戶
  • 最新版的 Node.js
  • 擁有 Azure 訂閱之後,在 Azure 入口網站中建立自訂視覺資源,以建立定型和預測資源。
    • 您可以使用免費定價層 (F0) 來試用服務,之後可升級至付費層以用於實際執行環境。

建立環境變數

在此範例中,您會在執行應用程式的本機電腦上將認證寫入環境變數。

前往 Azure 入口網站。 如果您在 [必要條件] 區段中建立的自訂視覺資源成功部署,請選取 [後續步驟] 底下的 [前往資源] 按鈕。 您可以在 [資源管理] 底下的 [金鑰和端點] 頁面中找到金鑰和端點。 您將需要為定型和預測資源取得金鑰以及 API 端點。

您可以在 Azure 入口網站中預測資源的 [屬性] 索引標籤上找到預測資源識別碼,該識別碼名為 [資源識別碼]。

提示

您也可以使用 https://www.customvision.ai/ 來取得這些值。 登入之後,請選取右上方的 [設定] 圖示。 在 [設定] 頁面上,您可以檢視所有金鑰、資源識別碼和端點。

警告

請勿在程式碼中直接包含索引碼,且切勿公開張貼索引碼。 如需更多驗證選項 (例如 Azure Key Vault),請參閱 Azure AI 服務安全性文章。

若要設定環境變數,請開啟主控台視窗,然後遵循作業系統和開發環境的指示進行。

  1. 若要設定 VISION_TRAINING KEY 環境變數,請以您的定型資源的其中一個金鑰取代 your-training-key
  2. 若要設定 VISION_TRAINING_ENDPOINT 環境變數,請將 your-training-endpoint 取代為定型資源的端點。
  3. 若要設定 VISION_PREDICTION_KEY 環境變數,請以您的預測資源的其中一個金鑰取代 your-prediction-key
  4. 若要設定 VISION_PREDICTION_ENDPOINT 環境變數,請將 your-prediction-endpoint 取代為預測資源的端點。
  5. 若要設定 VISION_PREDICTION_RESOURCE_ID 環境變數,請將 your-resource-id 取代為預測資源的資源識別碼。
setx VISION_TRAINING_KEY your-training-key
setx VISION_TRAINING_ENDPOINT your-training-endpoint
setx VISION_PREDICTION_KEY your-prediction-key
setx VISION_PREDICTION_ENDPOINT your-prediction-endpoint
setx VISION_PREDICTION_RESOURCE_ID your-resource-id

新增環境變數之後,您可能需要重新啟動任何將讀取環境變數的執行中程式,包括主控台視窗。

設定

建立新的 Node.js 應用程式

在主控台視窗 (例如 cmd、PowerShell 或 Bash) 中,為您的應用程式建立新的目錄,並瀏覽至該目錄。

mkdir myapp && cd myapp

執行命令 npm init,以使用 package.json 檔案建立節點應用程式。

npm init

安裝用戶端程式庫

若要使用適用於 Node.js 的自訂視覺來撰寫影像分析應用程式,您將需要自訂視覺 NPM 套件。 若要加以安裝,請在 PowerShell 中執行下列命令:

npm install @azure/cognitiveservices-customvision-training
npm install @azure/cognitiveservices-customvision-prediction

您應用程式的 package.json 檔案會隨著相依性而更新。

建立名為 index.js 的檔案,並匯入下列程式庫:

const util = require('util');
const fs = require('fs');
const TrainingApi = require("@azure/cognitiveservices-customvision-training");
const PredictionApi = require("@azure/cognitiveservices-customvision-prediction");
const msRest = require("@azure/ms-rest-js");

提示

想要立刻檢視整個快速入門程式碼檔案嗎? 您可以在 GitHub 上找到該檔案,其中包含本快速入門中的程式碼範例。

為資源的 Azure 端點和金鑰建立變數。

// retrieve environment variables
const trainingKey = process.env["VISION_TRAINING_KEY"];
const trainingEndpoint = process.env["VISION_TRAINING_ENDPOINT"];

const predictionKey = process.env["VISION_PREDICTION_KEY"];
const predictionResourceId = process.env["VISION_PREDICTION_RESOURCE_ID"];
const predictionEndpoint = process.env["VISION_PREDICTION_ENDPOINT"];

同時新增專案名稱的欄位,以及非同步呼叫的逾時參數。

const publishIterationName = "detectModel";
const setTimeoutPromise = util.promisify(setTimeout);

物件模型

名稱 描述
TrainingAPIClient 此類別會處理模型的建立、定型和發佈。
PredictionAPIClient 此類別會處理您的模型查詢,以進行物件偵測預測。
預測 此介面會定義單一影像上的單一預測。 其中包含物件識別碼和名稱的屬性,以及信賴分數。

程式碼範例

這些程式碼片段說明如何使用適用於 JavaScript 的自訂視覺用戶端程式庫來執行下列工作:

驗證用戶端

使用端點和金鑰將用戶端物件具現化。 使用金鑰建立 ApiKeyCredentials 物件,並使用該物件與您的端點建立 TrainingAPIClientPredictionAPIClient 物件。

const credentials = new msRest.ApiKeyCredentials({ inHeader: { "Training-key": trainingKey } });
const trainer = new TrainingApi.TrainingAPIClient(credentials, trainingEndpoint);
const predictor_credentials = new msRest.ApiKeyCredentials({ inHeader: { "Prediction-key": predictionKey } });
const predictor = new PredictionApi.PredictionAPIClient(predictor_credentials, predictionEndpoint);

新增協助程式函式

新增下列函數,以協助進行多個非同步呼叫。 您稍後將會用到此資訊。

const credentials = new msRest.ApiKeyCredentials({ inHeader: { "Training-key": trainingKey } });
const trainer = new TrainingApi.TrainingAPIClient(credentials, trainingEndpoint);
const predictor_credentials = new msRest.ApiKeyCredentials({ inHeader: { "Prediction-key": predictionKey } });
const predictor = new PredictionApi.PredictionAPIClient(predictor_credentials, predictionEndpoint);

建立新的自訂視覺專案

啟動新的函式,以包含所有的自訂視覺函式呼叫。 新增下列程式碼,以建立新的自訂視覺服務專案。

(async () => {
    console.log("Creating project...");
    const domains = await trainer.getDomains()
    const objDetectDomain = domains.find(domain => domain.type === "ObjectDetection");
    const sampleProject = await trainer.createProject("Sample Obj Detection Project", { domainId: objDetectDomain.id });

將標記新增至專案

若要在專案中建立分類標記,請在函式中新增以下程式碼:

const forkTag = await trainer.createTag(sampleProject.id, "Fork");
const scissorsTag = await trainer.createTag(sampleProject.id, "Scissors");

上傳並標記影像

首先,下載此專案的範例影像。 將範例影像資料夾的內容儲存到您的本機裝置。

若要將範例影像新增到專案,在標記建立之後插入下列程式碼。 此程式碼會上傳每個影像及其對應標記。 為物件偵測專案中的影像加上標記時,您必須使用標準化座標來識別每個加上標記的物件所屬的區域。 本教學課程中的區域是以硬式編碼內嵌於程式碼中。 這些區域會在標準化座標中指定週框方塊,且座標會以下列順序指定:左、上、寬度、高度。 您最多可以在單一批次中上傳 64 個影像。

const sampleDataRoot = "Images";

const forkImageRegions = {
    "fork_1.jpg": [0.145833328, 0.3509314, 0.5894608, 0.238562092],
    "fork_2.jpg": [0.294117659, 0.216944471, 0.534313738, 0.5980392],
    "fork_3.jpg": [0.09191177, 0.0682516545, 0.757352948, 0.6143791],
    "fork_4.jpg": [0.254901975, 0.185898721, 0.5232843, 0.594771266],
    "fork_5.jpg": [0.2365196, 0.128709182, 0.5845588, 0.71405226],
    "fork_6.jpg": [0.115196079, 0.133611143, 0.676470637, 0.6993464],
    "fork_7.jpg": [0.164215669, 0.31008172, 0.767156839, 0.410130739],
    "fork_8.jpg": [0.118872553, 0.318251669, 0.817401946, 0.225490168],
    "fork_9.jpg": [0.18259804, 0.2136765, 0.6335784, 0.643790841],
    "fork_10.jpg": [0.05269608, 0.282303959, 0.8088235, 0.452614367],
    "fork_11.jpg": [0.05759804, 0.0894935, 0.9007353, 0.3251634],
    "fork_12.jpg": [0.3345588, 0.07315363, 0.375, 0.9150327],
    "fork_13.jpg": [0.269607842, 0.194068655, 0.4093137, 0.6732026],
    "fork_14.jpg": [0.143382356, 0.218578458, 0.7977941, 0.295751631],
    "fork_15.jpg": [0.19240196, 0.0633497, 0.5710784, 0.8398692],
    "fork_16.jpg": [0.140931368, 0.480016381, 0.6838235, 0.240196079],
    "fork_17.jpg": [0.305147052, 0.2512582, 0.4791667, 0.5408496],
    "fork_18.jpg": [0.234068632, 0.445702642, 0.6127451, 0.344771236],
    "fork_19.jpg": [0.219362751, 0.141781077, 0.5919118, 0.6683006],
    "fork_20.jpg": [0.180147052, 0.239820287, 0.6887255, 0.235294119]
};

const scissorsImageRegions = {
    "scissors_1.jpg": [0.4007353, 0.194068655, 0.259803921, 0.6617647],
    "scissors_2.jpg": [0.426470578, 0.185898721, 0.172794119, 0.5539216],
    "scissors_3.jpg": [0.289215684, 0.259428144, 0.403186262, 0.421568632],
    "scissors_4.jpg": [0.343137264, 0.105833367, 0.332107842, 0.8055556],
    "scissors_5.jpg": [0.3125, 0.09766343, 0.435049027, 0.71405226],
    "scissors_6.jpg": [0.379901975, 0.24308826, 0.32107842, 0.5718954],
    "scissors_7.jpg": [0.341911763, 0.20714055, 0.3137255, 0.6356209],
    "scissors_8.jpg": [0.231617644, 0.08459154, 0.504901946, 0.8480392],
    "scissors_9.jpg": [0.170343131, 0.332957536, 0.767156839, 0.403594762],
    "scissors_10.jpg": [0.204656869, 0.120539248, 0.5245098, 0.743464053],
    "scissors_11.jpg": [0.05514706, 0.159754932, 0.799019635, 0.730392158],
    "scissors_12.jpg": [0.265931368, 0.169558853, 0.5061275, 0.606209159],
    "scissors_13.jpg": [0.241421565, 0.184264734, 0.448529422, 0.6830065],
    "scissors_14.jpg": [0.05759804, 0.05027781, 0.75, 0.882352948],
    "scissors_15.jpg": [0.191176474, 0.169558853, 0.6936275, 0.6748366],
    "scissors_16.jpg": [0.1004902, 0.279036, 0.6911765, 0.477124184],
    "scissors_17.jpg": [0.2720588, 0.131977156, 0.4987745, 0.6911765],
    "scissors_18.jpg": [0.180147052, 0.112369314, 0.6262255, 0.6666667],
    "scissors_19.jpg": [0.333333343, 0.0274019931, 0.443627447, 0.852941155],
    "scissors_20.jpg": [0.158088237, 0.04047389, 0.6691176, 0.843137264]
};

console.log("Adding images...");
let fileUploadPromises = [];

const forkDir = `${sampleDataRoot}/fork`;
const forkFiles = fs.readdirSync(forkDir);

await asyncForEach(forkFiles, async (file) => {
    const region = { tagId: forkTag.id, left: forkImageRegions[file][0], top: forkImageRegions[file][1], width: forkImageRegions[file][2], height: forkImageRegions[file][3] };
    const entry = { name: file, contents: fs.readFileSync(`${forkDir}/${file}`), regions: [region] };
    const batch = { images: [entry] };
    // Wait one second to accommodate rate limit.
    await setTimeoutPromise(1000, null);
    fileUploadPromises.push(trainer.createImagesFromFiles(sampleProject.id, batch));
});

const scissorsDir = `${sampleDataRoot}/scissors`;
const scissorsFiles = fs.readdirSync(scissorsDir);

await asyncForEach(scissorsFiles, async (file) => {
    const region = { tagId: scissorsTag.id, left: scissorsImageRegions[file][0], top: scissorsImageRegions[file][1], width: scissorsImageRegions[file][2], height: scissorsImageRegions[file][3] };
    const entry = { name: file, contents: fs.readFileSync(`${scissorsDir}/${file}`), regions: [region] };
    const batch = { images: [entry] };
    // Wait one second to accommodate rate limit.
    await setTimeoutPromise(1000, null);
    fileUploadPromises.push(trainer.createImagesFromFiles(sampleProject.id, batch));
});

await Promise.all(fileUploadPromises);

重要

您必須根據 Azure AI 服務 Python SDK 範例存放庫的下載位置,變更影像的路徑 (sampleDataRoot)。

注意

如果您沒有按住並拖曳公用程式可標示區域的座標,您可以使用 Customvision.ai 上的 Web UI。 此範例已提供座標。

為專案定型

此程式碼會建立預測模型的第一個反覆運算專案。

console.log("Training...");
let trainingIteration = await trainer.trainProject(sampleProject.id);

// Wait for training to complete
console.log("Training started...");
while (trainingIteration.status == "Training") {
    console.log("Training status: " + trainingIteration.status);
    // wait for ten seconds
    await setTimeoutPromise(10000, null);
    trainingIteration = await trainer.getIteration(sampleProject.id, trainingIteration.id)
}
console.log("Training status: " + trainingIteration.status);

發佈目前的反覆項目

此程式碼會將定型的反覆運算發佈至預測端點。 提供給已發佈反覆項目的名稱可用來傳送預測要求。 反覆項目要等到發佈後才可在預測端點中使用。

// Publish the iteration to the end point
await trainer.publishIteration(sampleProject.id, trainingIteration.id, publishIterationName, predictionResourceId);    

測試預測端點

若要將影像傳送到預測端點並擷取預測,請在函式新增以下程式碼。

const testFile = fs.readFileSync(`${sampleDataRoot}/test/test_image.jpg`);
const results = await predictor.detectImage(sampleProject.id, publishIterationName, testFile)

// Show results
console.log("Results:");
results.predictions.forEach(predictedResult => {
    console.log(`\t ${predictedResult.tagName}: ${(predictedResult.probability * 100.0).toFixed(2)}% ${predictedResult.boundingBox.left},${predictedResult.boundingBox.top},${predictedResult.boundingBox.width},${predictedResult.boundingBox.height}`);
});

然後,關閉您的自訂視覺函式並加以呼叫。

})()

執行應用程式

使用快速入門檔案上使用 node 命令執行應用程式。

node index.js

應用程式的輸出應會顯示在主控台中。 接著,您可以確認測試影像 (位於 <sampleDataRoot>/Test/) 是否已正確加上標記,以及偵測的區域是否正確。 您也可以返回自訂視覺網站,然後查看新建立專案的目前狀態。

清除資源

如果您想要實作您自己的物件偵測專案 (或改為嘗試影像分類專案),您可以刪除此範例中的叉子/剪刀偵測專案。 免費訂用帳戶可使用兩個自訂視覺專案。

自訂視覺網站上,瀏覽至 [專案],然後選取 [我的新專案] 底下的資源回收筒。

面板的螢幕擷取畫面,該面板標示為 [我的新專案] 並有資源回收筒圖示。

下一步

現在,您已完成在程式碼中執行物件偵測程序的每個步驟。 此範例會執行單一的訓練反覆項目,但您通常必須對模型進行多次訓練和測試,以便提升其精確度。 下列指南會處理影像分類,但其原則類似於物件偵測。

開始使用適用於 Python 的自訂視覺用戶端程式庫。 請遵循下列步驟來安裝套件,並試用建立物件偵測模型的程式碼範例。 您將建立專案、新增標籤、將專案定型,並使用專案的預測端點 URL 以程式設計方式加以測試。 請使用此範例作為自行建置影像辨識應用程式的範本。

注意

如果您想要在「不用」撰寫程式碼的情況下,建立和訓練物件偵測模型,請改為參閱以瀏覽器為基礎的指引

使用適用於 Python 的自訂視覺用戶端程式庫可執行下列作業:

  • 建立新的自訂視覺專案
  • 將標記新增至專案
  • 上傳和標記影像
  • 為專案定型
  • 發佈目前的反覆項目
  • 測試預測端點

參考文件 | 程式庫來源程式碼 | 套件 (PyPI) | 範例

必要條件

  • Azure 訂用帳戶 - 建立免費帳戶
  • Python 3.x
    • 您安裝的 Python 應包含 pip。 您可以在命令列上執行 pip --version 來檢查是否已安裝 pip。 安裝最新版本的 Python 以取得 pip。
  • 擁有 Azure 訂閱之後,在 Azure 入口網站中建立自訂視覺資源,以建立定型和預測資源。
    • 您可以使用免費定價層 (F0) 來試用服務,之後可升級至付費層以用於實際執行環境。

建立環境變數

在此範例中,您會在執行應用程式的本機電腦上將認證寫入環境變數。

前往 Azure 入口網站。 如果您在 [必要條件] 區段中建立的自訂視覺資源成功部署,請選取 [後續步驟] 底下的 [前往資源] 按鈕。 您可以在 [資源管理] 底下的 [金鑰和端點] 頁面中找到金鑰和端點。 您將需要為定型和預測資源取得金鑰以及 API 端點。

您可以在 Azure 入口網站中預測資源的 [屬性] 索引標籤上找到預測資源識別碼,該識別碼名為 [資源識別碼]。

提示

您也可以使用 https://www.customvision.ai/ 來取得這些值。 登入之後,請選取右上方的 [設定] 圖示。 在 [設定] 頁面上,您可以檢視所有金鑰、資源識別碼和端點。

警告

請勿在程式碼中直接包含索引碼,且切勿公開張貼索引碼。 如需更多驗證選項 (例如 Azure Key Vault),請參閱 Azure AI 服務安全性文章。

若要設定環境變數,請開啟主控台視窗,然後遵循作業系統和開發環境的指示進行。

  1. 若要設定 VISION_TRAINING KEY 環境變數,請以您的定型資源的其中一個金鑰取代 your-training-key
  2. 若要設定 VISION_TRAINING_ENDPOINT 環境變數,請將 your-training-endpoint 取代為定型資源的端點。
  3. 若要設定 VISION_PREDICTION_KEY 環境變數,請以您的預測資源的其中一個金鑰取代 your-prediction-key
  4. 若要設定 VISION_PREDICTION_ENDPOINT 環境變數,請將 your-prediction-endpoint 取代為預測資源的端點。
  5. 若要設定 VISION_PREDICTION_RESOURCE_ID 環境變數,請將 your-resource-id 取代為預測資源的資源識別碼。
setx VISION_TRAINING_KEY your-training-key
setx VISION_TRAINING_ENDPOINT your-training-endpoint
setx VISION_PREDICTION_KEY your-prediction-key
setx VISION_PREDICTION_ENDPOINT your-prediction-endpoint
setx VISION_PREDICTION_RESOURCE_ID your-resource-id

新增環境變數之後,您可能需要重新啟動任何將讀取環境變數的執行中程式,包括主控台視窗。

設定

安裝用戶端程式庫

若要使用適用於 Python 的自訂視覺來撰寫影像分析應用程式,您將需要自訂視覺用戶端程式庫。 安裝 Python 之後,請在 PowerShell 或主控台視窗中執行下列命令:

pip install azure-cognitiveservices-vision-customvision

建立新的 Python 應用程式

建立新的 Python 檔案,並匯入下列程式庫。

from azure.cognitiveservices.vision.customvision.training import CustomVisionTrainingClient
from azure.cognitiveservices.vision.customvision.prediction import CustomVisionPredictionClient
from azure.cognitiveservices.vision.customvision.training.models import ImageFileCreateBatch, ImageFileCreateEntry, Region
from msrest.authentication import ApiKeyCredentials
import os, time, uuid

提示

想要立刻檢視整個快速入門程式碼檔案嗎? 您可以在 GitHub 上找到該檔案,其中包含本快速入門中的程式碼範例。

為資源的 Azure 端點和金鑰建立變數。

# Replace with valid values
ENDPOINT = os.environ["VISION_TRAINING_ENDPOINT"]
training_key = os.environ["VISION_TRAINING_KEY"]
prediction_key = os.environ["VISION_PREDICTION_KEY"]
prediction_resource_id = os.environ["VISION_PREDICTION_RESOURCE_ID"]

物件模型

名稱 描述
CustomVisionTrainingClient 此類別會處理模型的建立、定型和發佈。
CustomVisionPredictionClient 此類別會處理您的模型查詢,以進行物件偵測預測。
ImagePrediction 此類別會定義單一影像上的單一物件預測。 其中包含物件識別碼和名稱的屬性、物件的周框方塊位置,以及信賴分數。

程式碼範例

這些程式碼片段說明如何使用適用於 Python 的自訂視覺用戶端程式庫來執行下列工作:

驗證用戶端

使用您的端點和金鑰將訓練具現化並預測用戶端。 使用您的金鑰建立 ApiKeyServiceClientCredentials 物件,並與您的端點搭配使用,以建立 CustomVisionTrainingClientCustomVisionPredictionClient 物件。

credentials = ApiKeyCredentials(in_headers={"Training-key": training_key})
trainer = CustomVisionTrainingClient(ENDPOINT, credentials)
prediction_credentials = ApiKeyCredentials(in_headers={"Prediction-key": prediction_key})
predictor = CustomVisionPredictionClient(ENDPOINT, prediction_credentials)

建立新的自訂視覺專案

在指令碼中新增下列程式碼,以建立新的自訂視覺服務專案。

當您建立專案時,請參閱 create_project 方法來指定其他選項 (如建立偵測器 Web 入口網站指南中所述)。

publish_iteration_name = "detectModel"

# Find the object detection domain
obj_detection_domain = next(domain for domain in trainer.get_domains() if domain.type == "ObjectDetection" and domain.name == "General")

# Create a new project
print ("Creating project...")
# Use uuid to avoid project name collisions.
project = trainer.create_project(str(uuid.uuid4()), domain_id=obj_detection_domain.id)

將標記新增至專案

若要在專案中建立物件標記,請新增以下程式碼:

# Make two tags in the new project
fork_tag = trainer.create_tag(project.id, "fork")
scissors_tag = trainer.create_tag(project.id, "scissors")

上傳並標記影像

首先,下載此專案的範例影像。 將範例影像資料夾的內容儲存到您的本機裝置。

為物件偵測專案中的影像加上標記時,您必須使用標準化座標來識別每個加上標記的物件所屬的區域。 下列程式碼會為每個範例影像及其已加上標記的區域建立關聯。 這些區域會在標準化座標中指定週框方塊,且座標會以下列順序指定:左、上、寬度、高度。

fork_image_regions = {
    "fork_1": [ 0.145833328, 0.3509314, 0.5894608, 0.238562092 ],
    "fork_2": [ 0.294117659, 0.216944471, 0.534313738, 0.5980392 ],
    "fork_3": [ 0.09191177, 0.0682516545, 0.757352948, 0.6143791 ],
    "fork_4": [ 0.254901975, 0.185898721, 0.5232843, 0.594771266 ],
    "fork_5": [ 0.2365196, 0.128709182, 0.5845588, 0.71405226 ],
    "fork_6": [ 0.115196079, 0.133611143, 0.676470637, 0.6993464 ],
    "fork_7": [ 0.164215669, 0.31008172, 0.767156839, 0.410130739 ],
    "fork_8": [ 0.118872553, 0.318251669, 0.817401946, 0.225490168 ],
    "fork_9": [ 0.18259804, 0.2136765, 0.6335784, 0.643790841 ],
    "fork_10": [ 0.05269608, 0.282303959, 0.8088235, 0.452614367 ],
    "fork_11": [ 0.05759804, 0.0894935, 0.9007353, 0.3251634 ],
    "fork_12": [ 0.3345588, 0.07315363, 0.375, 0.9150327 ],
    "fork_13": [ 0.269607842, 0.194068655, 0.4093137, 0.6732026 ],
    "fork_14": [ 0.143382356, 0.218578458, 0.7977941, 0.295751631 ],
    "fork_15": [ 0.19240196, 0.0633497, 0.5710784, 0.8398692 ],
    "fork_16": [ 0.140931368, 0.480016381, 0.6838235, 0.240196079 ],
    "fork_17": [ 0.305147052, 0.2512582, 0.4791667, 0.5408496 ],
    "fork_18": [ 0.234068632, 0.445702642, 0.6127451, 0.344771236 ],
    "fork_19": [ 0.219362751, 0.141781077, 0.5919118, 0.6683006 ],
    "fork_20": [ 0.180147052, 0.239820287, 0.6887255, 0.235294119 ]
}

scissors_image_regions = {
    "scissors_1": [ 0.4007353, 0.194068655, 0.259803921, 0.6617647 ],
    "scissors_2": [ 0.426470578, 0.185898721, 0.172794119, 0.5539216 ],
    "scissors_3": [ 0.289215684, 0.259428144, 0.403186262, 0.421568632 ],
    "scissors_4": [ 0.343137264, 0.105833367, 0.332107842, 0.8055556 ],
    "scissors_5": [ 0.3125, 0.09766343, 0.435049027, 0.71405226 ],
    "scissors_6": [ 0.379901975, 0.24308826, 0.32107842, 0.5718954 ],
    "scissors_7": [ 0.341911763, 0.20714055, 0.3137255, 0.6356209 ],
    "scissors_8": [ 0.231617644, 0.08459154, 0.504901946, 0.8480392 ],
    "scissors_9": [ 0.170343131, 0.332957536, 0.767156839, 0.403594762 ],
    "scissors_10": [ 0.204656869, 0.120539248, 0.5245098, 0.743464053 ],
    "scissors_11": [ 0.05514706, 0.159754932, 0.799019635, 0.730392158 ],
    "scissors_12": [ 0.265931368, 0.169558853, 0.5061275, 0.606209159 ],
    "scissors_13": [ 0.241421565, 0.184264734, 0.448529422, 0.6830065 ],
    "scissors_14": [ 0.05759804, 0.05027781, 0.75, 0.882352948 ],
    "scissors_15": [ 0.191176474, 0.169558853, 0.6936275, 0.6748366 ],
    "scissors_16": [ 0.1004902, 0.279036, 0.6911765, 0.477124184 ],
    "scissors_17": [ 0.2720588, 0.131977156, 0.4987745, 0.6911765 ],
    "scissors_18": [ 0.180147052, 0.112369314, 0.6262255, 0.6666667 ],
    "scissors_19": [ 0.333333343, 0.0274019931, 0.443627447, 0.852941155 ],
    "scissors_20": [ 0.158088237, 0.04047389, 0.6691176, 0.843137264 ]
}

注意

如果您沒有按住並拖曳公用程式可標示區域的座標,您可以使用 Customvision.ai 上的 Web UI。 此範例已提供座標。

然後,使用此關聯對應,上傳每個範例影像及其區域座標 (您最多可以在單一批次中上傳 64 個影像)。 加入下列程式碼。

base_image_location = os.path.join (os.path.dirname(__file__), "Images")

# Go through the data table above and create the images
print ("Adding images...")
tagged_images_with_regions = []

for file_name in fork_image_regions.keys():
    x,y,w,h = fork_image_regions[file_name]
    regions = [ Region(tag_id=fork_tag.id, left=x,top=y,width=w,height=h) ]

    with open(os.path.join (base_image_location, "fork", file_name + ".jpg"), mode="rb") as image_contents:
        tagged_images_with_regions.append(ImageFileCreateEntry(name=file_name, contents=image_contents.read(), regions=regions))

for file_name in scissors_image_regions.keys():
    x,y,w,h = scissors_image_regions[file_name]
    regions = [ Region(tag_id=scissors_tag.id, left=x,top=y,width=w,height=h) ]

    with open(os.path.join (base_image_location, "scissors", file_name + ".jpg"), mode="rb") as image_contents:
        tagged_images_with_regions.append(ImageFileCreateEntry(name=file_name, contents=image_contents.read(), regions=regions))

upload_result = trainer.create_images_from_files(project.id, ImageFileCreateBatch(images=tagged_images_with_regions))
if not upload_result.is_batch_successful:
    print("Image batch upload failed.")
    for image in upload_result.images:
        print("Image status: ", image.status)
    exit(-1)

注意

您必須根據稍早 Azure AI 服務 Python SDK 範例存放庫的下載位置,變更影像的路徑。

為專案定型

此程式碼會建立預測模型的第一個反覆運算專案。

print ("Training...")
iteration = trainer.train_project(project.id)
while (iteration.status != "Completed"):
    iteration = trainer.get_iteration(project.id, iteration.id)
    print ("Training status: " + iteration.status)
    time.sleep(1)

提示

使用選取的標記進行訓練

您可以選擇只在已套用的標記子集上進行訓練。 您可以在尚未套用足夠的特定標記,但其他套用的標記已足夠時執行此操作。 在 train_project 呼叫中,將選擇性參數 selected_tags設定為您要使用的標記識別碼字串清單。 此模型將訓練為僅辨識該清單上的標記。

發佈目前的反覆項目

反覆項目要等到發佈後才可在預測端點中使用。 下列程式碼會讓模型的目前反覆運算可供查詢。

# The iteration is now trained. Publish it to the project endpoint
trainer.publish_iteration(project.id, iteration.id, publish_iteration_name, prediction_resource_id)
print ("Done!")

測試預測端點

若要將影像傳送到預測端點並擷取預測,在檔案結尾處新增以下程式碼:

# Now there is a trained endpoint that can be used to make a prediction

# Open the sample image and get back the prediction results.
with open(os.path.join (base_image_location, "test", "test_image.jpg"), mode="rb") as test_data:
    results = predictor.detect_image(project.id, publish_iteration_name, test_data)

# Display the results.    
for prediction in results.predictions:
    print("\t" + prediction.tag_name + ": {0:.2f}% bbox.left = {1:.2f}, bbox.top = {2:.2f}, bbox.width = {3:.2f}, bbox.height = {4:.2f}".format(prediction.probability * 100, prediction.bounding_box.left, prediction.bounding_box.top, prediction.bounding_box.width, prediction.bounding_box.height))

執行應用程式

執行 CustomVisionQuickstart.py

python CustomVisionQuickstart.py

應用程式的輸出應會顯示在主控台中。 接著,您可以確認測試影像 (位於 <base_image_location>/images/Test 中) 是否已正確加上標記,以及偵測的區域是否正確。 您也可以返回自訂視覺網站,然後查看新建立專案的目前狀態。

清除資源

如果您想要實作您自己的物件偵測專案 (或改為嘗試影像分類專案),您可以刪除此範例中的叉子/剪刀偵測專案。 免費訂用帳戶可使用兩個自訂視覺專案。

自訂視覺網站上,瀏覽至 [專案],然後選取 [我的新專案] 底下的資源回收筒。

面板的螢幕擷取畫面,該面板標示為 [我的新專案] 並有資源回收筒圖示。

下一步

現在,您已完成在程式碼中執行物件偵測程序的每個步驟。 此範例會執行單一的訓練反覆項目,但您通常必須對模型進行多次訓練和測試,以便提升其精確度。 下列指南會處理影像分類,但其原則類似於物件偵測。