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

開始使用適用於 .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 方法,以在建立專案時指定其他選項(如建置偵測器入口網站指南中所述)。

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");
}

上傳並標記影像

首先,下載此專案的範例映射。 將範例 Images 資料夾的內容儲存至本機裝置。

當您在物件偵測項目中標記影像時,您必須使用標準化座標來指定每個標記對象的區域。 下列程式代碼會將每個範例影像與其標記的區域產生關聯。

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/) 中已正確標記,且偵測區域正確。 此時,您可以按下任何按鍵來結束應用程式。

清除資源

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

自訂視覺 網站上,流覽至 [專案],然後選取 [我的新專案] 底下的垃圾桶。

Screenshot of a panel labeled My New Project with a trash can icon.

下一步

現在您已在程式代碼中完成物件偵測程式的每個步驟。 此範例會執行單一定型反覆專案,但您通常需要多次定型和測試模型,才能使其更精確。 下列指南會處理影像分類,但其原則與對象偵測類似。

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

注意

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

使用適用於 Go 的 自訂視覺 用戶端連結庫:

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

參考文件 (定型)(預測)

必要條件

建立環境變數

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

前往 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

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

設定

安裝 自訂視覺 客戶端連結庫

若要使用 自訂視覺 for 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 方法,以在建立專案時指定其他選項(如建置偵測器入口網站指南中所述)。

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

應用程式的輸出應該會出現在控制台中。 然後,您可以確認測試影像(在範例/視覺/影像/測試中找到)已正確標記,且偵測區域正確。

清除資源

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

自訂視覺 網站上,流覽至 [專案],然後選取 [我的新專案] 底下的垃圾桶。

Screenshot of a panel labeled My New Project with a trash can icon.

下一步

現在您已在程式代碼中完成物件偵測程式的每個步驟。 此範例會執行單一定型反覆專案,但您通常需要多次定型和測試模型,才能使其更精確。 下列指南會處理影像分類,但其原則與對象偵測類似。

開始使用適用於 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 或文本編輯器加以開啟。 然後複製下列組建組態。 此組態會將專案定義為 Java 應用程式,其進入點為 CustomVisionQuickstart 類別。 它會匯入 自訂視覺 連結庫。

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");

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

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

物件模型

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

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

程式碼範例

這些代碼段示範如何使用適用於 Java 的 自訂視覺 客戶端連結庫來執行下列工作:

驗證用戶端

在您的 主要 方法中,使用您的端點和密鑰具現化定型和預測用戶端。

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

建立新的自訂視覺專案

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

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();
}

上傳並標記影像

首先,下載此專案的範例映射。 將範例 Images 資料夾的內容儲存至本機裝置。

注意

您需要一組更廣泛的影像才能完成訓練嗎? Microsoft Garage 專案的 Trove 可讓您收集及購買一組影像以供訓練之用。 收集映射之後,您可以下載影像,然後以一般方式將其匯入至 自訂視覺 專案。 請流覽 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 服務訂用帳戶,則可以刪除資源或資源群組。 刪除資源群組也會刪除與其相關聯的任何其他資源。

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

自訂視覺 網站上,流覽至 [專案],然後選取 [我的新專案] 底下的垃圾桶。

Screenshot of a panel labeled My New Project with a trash can icon.

下一步

現在您已在程式代碼中完成物件偵測程式的每個步驟。 此範例會執行單一定型反覆專案,但您通常需要多次定型和測試模型,才能使其更精確。 下列指南會處理影像分類,但其原則與對象偵測類似。

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

注意

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

使用適用於 .NET 的 自訂視覺 用戶端連結庫來:

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

參考文件 (訓練)(預測) |連結庫原始碼 (訓練)(預測) |套件 (npm) (訓練)(預測) | 範例

必要條件

建立環境變數

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

前往 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");

上傳並標記影像

首先,下載此專案的範例映射。 將範例 Images 資料夾的內容儲存至本機裝置。

若要將範例影像新增至專案,請在標記建立之後插入下列程序代碼。 此程式代碼會上傳每個影像及其對應的標記。 當您在物件偵測項目中標記影像時,您必須使用標準化座標來指定每個標記對象的區域。 在本教學課程中,區域會以硬式編碼的方式內嵌程序代碼。 區域會以標準化座標指定周框方塊,並以下列順序指定座標:左、上、寬、高度。 您可以在單一批次中上傳最多 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/) 中<已正確標記,且偵測區域正確。 您也可以回到 自訂視覺 網站,並查看新建立專案的目前狀態。

清除資源

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

自訂視覺 網站上,流覽至 [專案],然後選取 [我的新專案] 底下的垃圾桶。

Screenshot of a panel labeled My New Project with a trash can icon.

下一步

現在您已在程式代碼中完成物件偵測程式的每個步驟。 此範例會執行單一定型反覆專案,但您通常需要多次定型和測試模型,才能使其更精確。 下列指南會處理影像分類,但其原則與對象偵測類似。

開始使用適用於 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方法來指定其他選項(如建置偵測器入口網站指南中所述)。

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")

上傳並標記影像

首先,下載此專案的範例映射。 將範例 Images 資料夾的內容儲存至本機裝置。

當您在物件偵測項目中標記影像時,您必須使用標準化座標來指定每個標記對象的區域。 下列程式代碼會將每個範例影像與其標記的區域產生關聯。 區域會以標準化座標指定周框方塊,並以下列順序指定座標:左、上、寬、高度。

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 中找到)已正確標記,且偵測區域正確。 您也可以回到 自訂視覺 網站,並查看新建立專案的目前狀態。

清除資源

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

自訂視覺 網站上,流覽至 [專案],然後選取 [我的新專案] 底下的垃圾桶。

Screenshot of a panel labeled My New Project with a trash can icon.

下一步

現在您已在程式代碼中完成物件偵測程式的每個步驟。 此範例會執行單一定型反覆專案,但您通常需要多次定型和測試模型,才能使其更精確。 下列指南會處理影像分類,但其原則與對象偵測類似。