Der Einstieg in Machine Learning ist nicht unbedingt einfach – zumindest hat es sich für mich als gestandenen Entwickler so angefühlt. Es gibt mittlerweile ziemlich viele vorgefertigte DataSets, wie beispielsweise das Hunde- und Katzen-Dataset bei Kaggle https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition/data, aber ich wollte auch die Möglichkeit haben mein eigenes Dataset zusammenzustellen.
Dabei kann uns die Bing Search API mit den Azure Cognitive Services gute Dienste leisten.
Also wie wäre es mit einem Dataset, welches Bilder der beliebtesten Hunde- und Katzenrassen beinhaltet? Ja, das wäre doch etwas. Zuerst brauchen wir also eine Top-10 Liste ebendieser. Das lässt sich schnell finden und diese sieht angeblich so aus:
Beliebteste Hunderassen
|
Beliebteste Katzenrassen
|
Französische Bulldogge
|
Maine Coon
|
Labrador
|
Norwegische Waldkatze
|
Australian Shepherd
|
Britisch Kurzhaar
|
Chihuahua
|
Bengalkatze
|
Golden Retriever
|
Siamkatze
|
Border Collie
|
Savannah-Katze
|
Labradoodle
|
Ragdoll
|
Rottweiler
|
Perserkatze
|
Beagle
|
Heilige Birma
|
Mops
|
Hauskatze
|
Französische Bulldogge
|
Maine Coon
|
Azure Dienst erstellen
Soweit, so gut. Jetzt müssen dazu noch Bilder her. Dafür bedienen wir uns der Bing Bildersuche, allerdings unterstützt von der Bing-Suche der Azure Cognitive Services.
Dazu müssen wir uns den Dienst abonnieren, das geht wie bei allen Azure Diensten mit ein paar Mausklicks, los geht es einmal hier:
https://portal.azure.com/#create/Microsoft.CognitiveServicesBingSearch-v7
Auf die Schnelle einen Namen wählen und den passenden Tarif (ich habe mich für S7 entschieden, dieser unterstützt die Bildersuche und lässt 150 Aufrufe pro Sekunde zu, und das für gerade einmal €4,22 im Monat bei 1000 Aufrufen).
Den Client erstellen
Eine einfache Konsolen-App reicht vollkommen, egal ob .NET > 4.5.2, oder .NET Core. Die Bing-API wird mittels REST angesprochen, das könnten wir auch selbst implementieren, aber lassen wir die Arbeit doch den C# Wrapper durchführen, den gibt es zum Glück fix und fertig(Microsoft.Azure.CognitiveServices.Search.ImageSearch) als Nuget-Paket.
Derzeit ist die aktuelle Version v2.0.0, diese nehmen wir.
Die Referenz zu System.Drawing wird noch benötigt, um das heruntergeladene Bild aus dem Stream wieder herzustellen.
Dann kann es auch schon los gehen mit dem Download der Bilder:
using Microsoft.Azure.CognitiveServices.Search.ImageSearch;
using Microsoft.Azure.CognitiveServices.Search.ImageSearch.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
namespace DataSetGen
{
class Program
{
static void Main(string[] args)
{
//args = new string[] { "Britisch Kurzhaar,Katze" };
string destinationPath = @"c:\dataset";
string bingAPIKey = "XXXXXXXXXXXXXXXXX";
int maxResultCount = 10;
int minFileSize = 1_000_000; //1MB
int maxFileSize = 4_000_000; //4MB
string license = "All"; //"Any", "Public", "Share", "ShareCommercially", "Modify", "ModifyCommercially", "All"
string safeSearch = SafeSearch.Strict;
if (args.Length == 0)
return;
string searchTerm = args[0];
SearchBing(bingAPIKey, searchTerm, maxResultCount, minFileSize, maxFileSize, license, safeSearch, destinationPath);
Console.ReadKey(true);
}
private static async Task SearchBing(string bingAPIKey, string searchTerm, int maxResultCount, int minFileSize, int maxFileSize, string license, string safeSearch, string destinationPath)
{
Console.WriteLine("Searching images for: " + searchTerm);
var client = new ImageSearchClient(new ApiKeyServiceClientCredentials(bingAPIKey));
//client.Endpoint = BingUri;
var images = await client.Images.SearchAsync(query: searchTerm,
count: maxResultCount,
minFileSize: minFileSize,
maxFileSize: maxFileSize,
license: license,
safeSearch: safeSearch);
if (images != null)
{
Console.WriteLine($"Images found: {images.Value.Count}");
string path = Path.Combine(destinationPath, searchTerm);
var savedCount = await SaveBingImages(images.Value, path);
Console.WriteLine($"{Environment.NewLine}Images saved: {savedCount}");
}
}
private static async Task<int> SaveBingImages(IList<ImageObject> items, string targetFolder)
{
if(!Directory.Exists(targetFolder))
Directory.CreateDirectory(targetFolder);
HttpClient httpClient = new HttpClient();
List<Task> tasks = new List<Task>();
int savedCount = 0;
foreach (var item in items)
{
var task = Task.Run(async () =>
{
try
{
Console.Write(".");
var request = new HttpRequestMessage(HttpMethod.Get, item.ContentUrl);
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var stream = await response.Content.ReadAsStreamAsync();
//add reference: System.Drawing.dll
var img = System.Drawing.Image.FromStream(stream);
string extension = Path.GetExtension(item.ContentUrl).ToLower();
string filePath = Path.Combine(targetFolder, item.ImageId + extension);
img.Save(filePath);
savedCount++;
}
catch (Exception e)
{
Console.WriteLine($"{Environment.NewLine}Download failed: {item.ContentUrl} ERROR: {e.Message}");
}
});
tasks.Add(task);
}
await Task.WhenAll(tasks.ToArray());
return savedCount;
}
}
}
Die Konsolen-APP kompilieren und mit folgenden Parametern aufrufen (Name der Rasse – ein Beistrich – und der Typ der Bilder, wir werden das im nächsten Teil benötigen, wenn wir Bilder mit unserem DataSet vergleichen wollen):
dataSetGen.exe "Border Collie, Hund"
dataSetGen.exe "Chihuahua, Hund"
dataSetGen.exe "Mops, Hund"
dataSetGen.exe "Britisch Kurzhaar,Katze"
dataSetGen.exe "Maine Coon, Katze"
dataSetGen.exe "Norwegische Waldkatze, Katze"
Es können noch weitere Rassen heruntergeladen werden, aber ich möchte das DataSet nicht allzu groß machen, da wir im nächsten Teil die Bilder mittels Azure Cognitive CustomVision klassifizieren lassen und dazu die Bilder hoch geladen werden müssen.
Das Resultat sollte im Datei-Explorer so aussehen, in jedem Verzeichnis sollten 9, oder 10 Bilder zu finden sein – nicht alle Bilder können heruntergeladen werden, dadurch kommt es vereinzelt zu Fehlern.
Ich wünsche euch viel Spaß beim zusammen stellen eures eigenen Datasets mit der Bing-Bildersuche!