Example #1
0
        public async void CreateImagesFromFiles()
        {
            var dataFileName = "hemlock_1.jpg";

            using (MockContext context = MockContext.Start(this.GetType()))
            {
                HttpMockServer.Initialize(this.GetType(), "CreateImagesFromFiles", RecorderMode);

                using (ICustomVisionTrainingClient client = GetTrainingClient())
                {
                    var newProject           = client.CreateProjectAsync(projName, projDescription, ProjectBuilderHelper.FoodDomain).Result;
                    var tag                  = client.CreateTagAsync(newProject.Id, tagName).Result;
                    var fileName             = Path.Combine("TestImages", "tag1", dataFileName);
                    var fileImages           = new ImageFileCreateEntry[] { new ImageFileCreateEntry(dataFileName, File.ReadAllBytes(fileName)) };
                    var tags                 = new Guid[] { tag.Id };
                    var imageCreatedFromFile = client.CreateImagesFromFilesAsync(newProject.Id, new ImageFileCreateBatch(fileImages, tags)).Result;

                    Assert.True(imageCreatedFromFile.IsBatchSuccessful);
                    Assert.Equal(1, imageCreatedFromFile.Images.Count);
                    Assert.Contains(dataFileName, imageCreatedFromFile.Images[0].SourceUrl);
                    Assert.Equal("OK", imageCreatedFromFile.Images[0].Status);
                    Assert.NotEqual(Guid.Empty, imageCreatedFromFile.Images[0].Image.Id);
                    Assert.NotEqual(0, imageCreatedFromFile.Images[0].Image.Width);
                    Assert.NotEqual(0, imageCreatedFromFile.Images[0].Image.Height);
                    Assert.NotEmpty(imageCreatedFromFile.Images[0].Image.OriginalImageUri);
                    Assert.NotEmpty(imageCreatedFromFile.Images[0].Image.ResizedImageUri);
                    Assert.NotEmpty(imageCreatedFromFile.Images[0].Image.ThumbnailUri);

                    await client.DeleteProjectAsync(newProject.Id);
                }
            }
        }
Example #2
0
        public async void QuerySuggestedImageCount()
        {
            using (MockContext context = MockContext.Start(this.GetType()))
            {
                HttpMockServer.Initialize(this.GetType(), "QuerySuggestedImageCount", RecorderMode);

                using (var project = CreateTrainedImageClassificationProject())
                    using (ICustomVisionTrainingClient client = BaseTests.GetTrainingClient())
                    {
                        // Add an untagged image we expect to be classified as tag1
                        var images = new ImageFileCreateEntry[] {
                            new ImageFileCreateEntry("suggest_ic.jpg", File.ReadAllBytes(Path.Combine("TestImages", "suggest_ic.jpg")))
                        };
                        var imageResult = await client.CreateImagesFromFilesAsync(project.ProjectId, new ImageFileCreateBatch(images));

                        Assert.True(imageResult.IsBatchSuccessful);
                        Assert.Equal(1, imageResult.Images.Count);

                        // Ask for suggestions
                        var suggestions = client.SuggestTagsAndRegions(project.ProjectId, project.IterationId, new Guid[] { imageResult.Images[0].Image.Id });

                        // Validate result
                        Assert.Equal(1, suggestions.Count);

                        var tags = await client.GetTagsAsync(project.ProjectId, project.IterationId);

                        // We expect to get Tag1 as the primary suggestion, so query with a high prediction
                        var countMapping = await client.QuerySuggestedImageCountAsync(project.ProjectId, project.IterationId, new TagFilter()
                        {
                            Threshold = 0.75,
                            TagIds    = new Guid[] { tags[0].Id }
                        });

                        Assert.Equal(1, countMapping.Count);
                        Assert.Equal(1, countMapping[tags[0].Id.ToString()]);

                        // We expect to get Tag2 to have a low probabilty, make sure we don't find it with a high threshold
                        countMapping = await client.QuerySuggestedImageCountAsync(project.ProjectId, project.IterationId, new TagFilter()
                        {
                            Threshold = 0.75,
                            TagIds    = new Guid[] { tags[1].Id }
                        });

                        Assert.Equal(1, countMapping.Count);
                        Assert.Equal(0, countMapping[tags[1].Id.ToString()]);

                        // Get results for all tags with a high threshold.
                        countMapping = await client.QuerySuggestedImageCountAsync(project.ProjectId, project.IterationId, new TagFilter()
                        {
                            Threshold = 0.75,
                            TagIds    = tags.Select(t => t.Id).ToList()
                        });

                        Assert.Equal(2, countMapping.Count);
                        Assert.Equal(1, countMapping[tags[0].Id.ToString()]);
                        Assert.Equal(0, countMapping[tags[1].Id.ToString()]);
                    }
            }
        }
        private async Task TagTestImages(Guid projectId, string folder, string tagName)
        {
            // Create the tag and get the ID
            var tag = await m_TrainingClient.CreateTagAsync(projectId, tagName);

            var tagIds = new List <Guid> {
                tag.Id
            };

            // Get a list of the training images in the folder.
            var files = Directory.GetFiles(folder);

            int count  = 0;
            var images = new List <ImageFileCreateEntry>();

            foreach (var file in files)
            {
                // Cerate an ImageFileCreateEntry for the file
                var imageFileCreateEntry = new ImageFileCreateEntry
                {
                    Name     = Path.GetFileName(file),
                    Contents = File.ReadAllBytes(file)
                };
                images.Add(imageFileCreateEntry);
                count++;
                if (count == ImagesPerClass)
                {
                    break;
                }

                // The maximum ImageFileCreateEntry size is 64
                if (images.Count == 64)
                {
                    // Create a batch, execute it and clear the list
                    var batch = new ImageFileCreateBatch
                    {
                        Images = images,
                        TagIds = tagIds
                    };
                    await m_TrainingClient.CreateImagesFromFilesAsync(projectId, batch);

                    images.Clear();
                }
            }

            // Create a batch and execute it
            if (images.Count > 0)
            {
                var batch = new ImageFileCreateBatch
                {
                    Images = images,
                    TagIds = tagIds
                };
                await m_TrainingClient.CreateImagesFromFilesAsync(projectId, batch);
            }
        }
        public async Task PublishImages(IList <string> imageFilePaths, string customVisionProjectName)
        {
            var imageFileEntries = new List <ImageFileCreateEntry>();

            foreach (var imageFilePath in imageFilePaths)
            {
                var fileName = Path.GetFileNameWithoutExtension(imageFilePath);
                var entry    = new ImageFileCreateEntry(fileName, await File.ReadAllBytesAsync(imageFilePath));
                imageFileEntries.Add(entry);
            }

            var projectId = await _projectService.GetProjectId(customVisionProjectName);

            await _trainingApi.CreateImagesFromFilesAsync(projectId, new ImageFileCreateBatch(imageFileEntries));

            // TODO - validations
            //64 item limit on publish batches
            //6MB limit on file sizes
        }
Example #5
0
        public async void QuerySuggestedImages()
        {
            using (MockContext context = MockContext.Start(this.GetType()))
            {
                HttpMockServer.Initialize(this.GetType(), "QuerySuggestedImages", RecorderMode);

                using (var project = CreateTrainedImageClassificationProject())
                    using (ICustomVisionTrainingClient client = BaseTests.GetTrainingClient())
                    {
                        // Add an untagged image we expect to be classified as tag1
                        var images = new ImageFileCreateEntry[] {
                            new ImageFileCreateEntry("suggest_ic.jpg", File.ReadAllBytes(Path.Combine("TestImages", "suggest_ic.jpg")))
                        };
                        var imageResult = await client.CreateImagesFromFilesAsync(project.ProjectId, new ImageFileCreateBatch(images));

                        Assert.True(imageResult.IsBatchSuccessful);
                        Assert.Equal(1, imageResult.Images.Count);

                        // Ask for suggestions
                        var suggestions = client.SuggestTagsAndRegions(project.ProjectId, project.IterationId, new Guid[] { imageResult.Images[0].Image.Id });

                        // Validate result
                        Assert.Equal(1, suggestions.Count);

                        // Get tags and build a query
                        var tags = await client.GetTagsAsync(project.ProjectId, project.IterationId);

                        var query = new SuggestedTagAndRegionQueryToken()
                        {
                            MaxCount  = 10,
                            TagIds    = tags.Select(t => t.Id).ToList(),
                            Threshold = 0
                        };

                        // This will return all suggested images (1 in this case)
                        var suggestedImages = await client.QuerySuggestedImagesAsync(project.ProjectId, project.IterationId, query);

                        Assert.Equal(1, suggestedImages.Results.Count);
                    }
            }
        }
Example #6
0
        public async void SuggestTagAndRegions()
        {
            using (MockContext context = MockContext.Start(this.GetType()))
            {
                HttpMockServer.Initialize(this.GetType(), "SuggestTagAndRegions", RecorderMode);

                using (var project = CreateTrainedImageClassificationProject())
                    using (ICustomVisionTrainingClient client = BaseTests.GetTrainingClient())
                    {
                        // Add an untagged image we expect to be classified as tag1
                        var images = new ImageFileCreateEntry[] {
                            new ImageFileCreateEntry("suggest_ic.jpg", File.ReadAllBytes(Path.Combine("TestImages", "suggest_ic.jpg")))
                        };
                        var imageResult = await client.CreateImagesFromFilesAsync(project.ProjectId, new ImageFileCreateBatch(images));

                        Assert.True(imageResult.IsBatchSuccessful);
                        Assert.Equal(1, imageResult.Images.Count);

                        // Ask for suggestions
                        var suggestions = client.SuggestTagsAndRegions(project.ProjectId, project.IterationId, new Guid[] { imageResult.Images[0].Image.Id });

                        // Validate result
                        Assert.Equal(1, suggestions.Count);
                        Assert.Equal(project.ProjectId, suggestions[0].Project);
                        Assert.Equal(project.IterationId, suggestions[0].Iteration);
                        Assert.NotEqual(0, suggestions[0].Predictions.Count);

                        foreach (var prediction in suggestions[0].Predictions)
                        {
                            var tag = await client.GetTagAsync(project.ProjectId, prediction.TagId, project.IterationId);

                            Assert.Equal(tag.Name, prediction.TagName);
                            Assert.Equal(tag.Id, prediction.TagId);
                            Assert.InRange(prediction.Probability, 0, 1);
                        }

                        // We expect Tag1 to have the highest probability
                        Assert.Equal("Tag1", suggestions[0].Predictions.OrderByDescending(p => p.Probability).First().TagName);
                    }
            }
        }
Example #7
0
        public static ImageFileCreateEntry GetImageFileEntry(string filepath, List <Tag> tags)
        {
            List <Guid>          tagsIDs   = new List <Guid>();
            ImageFileCreateEntry imageFile = null;

            foreach (Tag t in tags)
            {
                tagsIDs.Add(t.Id);
            }

            try
            {
                Console.WriteLine($"\nCreate image entry for file '{Path.GetFileName(filepath)}' located at '{filepath}'.");
                imageFile = new ImageFileCreateEntry(Path.GetFileName(filepath), File.ReadAllBytes(filepath), tagsIDs);
            }
            catch (Exception e)
            {
                Console.WriteLine($"\n{e.GetType().Name}: Could not create image file entry for image '{filepath}'.");
            }

            return(imageFile);
        }
Example #8
0
        static void Main(string[] args)
        {
            var keys = GetApiKeys();

            var trainingApi = new TrainingApi {
                ApiKey = keys.TrainingKey
            };
            var predictionEndpoint = new PredictionEndpoint {
                ApiKey = keys.PredictionKey
            };

            var projects    = trainingApi.GetProjects();
            var herbProject = projects.FirstOrDefault(p => p.Name == "Herbs");

            Console.WriteLine("Press 1 to predict and 2 to train:");
            var pathChoice = Console.ReadLine();

            if ("1".Equals(pathChoice))
            {
                Console.WriteLine("Press 1 to predict on a URL or 2 to predict on a local file:");
                var predictType = Console.ReadLine();

                if ("1".Equals(predictType))
                {
                    Console.WriteLine("Input the URL to an image to test:");
                    var imageUrl = Console.ReadLine();

                    if (herbProject != null)
                    {
                        var result = predictionEndpoint.PredictImageUrl(herbProject.Id, new Microsoft.Cognitive.CustomVision.Prediction.Models.ImageUrl(imageUrl));

                        PrintResults(result);
                    }
                }
                else
                {
                    Console.WriteLine("Input path to image to test:");
                    var imagePath = Console.ReadLine();

                    if (!File.Exists(imagePath))
                    {
                        Console.WriteLine("File does not exist. Press enter to exit.");
                        Console.ReadLine();
                        return;
                    }

                    Console.WriteLine("Image predictions:");

                    var imageFile = File.OpenRead(imagePath);

                    if (herbProject != null)
                    {
                        var result = predictionEndpoint.PredictImage(herbProject.Id, imageFile);

                        PrintResults(result);
                    }
                    else
                    {
                        Console.WriteLine("Project doesn't exist.");
                    }
                }

                Console.ReadLine();
            }
            else
            {
                Console.WriteLine("Input path to image to train model with:");
                var imagePath = Console.ReadLine();

                Console.WriteLine("What tag would you give this image? Rosemary, cilantro, or basil?");
                var imageTag = Console.ReadLine();

                var capitilizedTag = char.ToUpper(imageTag.First()) + imageTag.Substring(1).ToLower();

                if (!File.Exists(imagePath))
                {
                    Console.WriteLine("File does not exist. Press enter to exit.");
                    Console.ReadLine();
                    return;
                }

                var imageFile = File.OpenRead(imagePath);

                var tags = trainingApi.GetTags(herbProject.Id);

                var matchedTag = tags.Tags.FirstOrDefault(t => t.Name == capitilizedTag);

                var memoryStream = new MemoryStream();
                imageFile.CopyTo(memoryStream);

                var fileCreateEntry = new ImageFileCreateEntry(imageFile.Name, memoryStream.ToArray());
                var fileCreateBatch = new ImageFileCreateBatch {
                    Images = new List <ImageFileCreateEntry> {
                        fileCreateEntry
                    }, TagIds = new List <Guid> {
                        matchedTag.Id
                    }
                };

                var result = trainingApi.CreateImagesFromFiles(herbProject.Id, fileCreateBatch);

                var resultImage = result.Images.FirstOrDefault();

                switch (resultImage.Status)
                {
                case "OKDuplicate":
                    Console.WriteLine("Image is already used for training. Please use another to train with");
                    Console.ReadLine();
                    break;

                default:
                    break;
                }

                var iteration = trainingApi.TrainProject(herbProject.Id);

                while (iteration.Status != "Completed")
                {
                    System.Threading.Thread.Sleep(1000);

                    iteration = trainingApi.GetIteration(herbProject.Id, iteration.Id);
                }

                iteration.IsDefault = true;
                trainingApi.UpdateIteration(herbProject.Id, iteration.Id, iteration);
                Console.WriteLine("Done training!");

                Console.ReadLine();
            }
        }
Example #9
0
        static async Task Main(string[] args)
        {
            const string FORMAT_LABELBOX = "labelbox";
            const string FORMAT_CNTK     = "cntk";

            var builder = new ConfigurationBuilder()
                          .SetBasePath(Directory.GetCurrentDirectory())
                          .AddJsonFile("appsettings.json");

            var configuration = builder.Build();

            // -------------------------------

            bool   online = bool.Parse(configuration["online"]);
            string format = configuration["bboxFormat"];

            if (format == FORMAT_LABELBOX)
            {
                if (Directory.EnumerateFiles(configuration["imagesPath"]).Count() > 0)
                {
                    Console.Write("Download directory is not empty.\nDo you want to re-download images and potentially overwrite existing files? ('y' to accept, Enter to continue)");
                    var input = Console.ReadLine();
                    if (input.ToLowerInvariant() == "y")
                    {
                        await DownloadLabelBox(configuration["labelBoxFile"], configuration["imagesPath"], configuration["imageExtension"]);
                    }
                }
                else
                {
                    await DownloadLabelBox(configuration["labelBoxFile"], configuration["imagesPath"], configuration["imageExtension"]);
                }
            }

            var imageFileEntries = new List <ImageFileCreateEntry>();
            var imageFiles       = Directory.EnumerateFiles(configuration["imagesPath"], $"*.{configuration["imageExtension"]}");
            var imageBatches     = Batch(imageFiles, 60);

            int fullWidth  = 800; // default - will try to detect later
            int fullHeight = 600;

            var client = new CustomVisionTrainingClient()
            {
                ApiKey   = configuration["trainingKey"],
                Endpoint = configuration["endpoint"]
            };

            Guid projectId = string.IsNullOrWhiteSpace(configuration["visionProjectId"]) ? Guid.Empty : Guid.Parse(configuration["visionProjectId"]);

            if (online)
            {
                var domains            = client.GetDomains();
                var objDetectionDomain = domains.FirstOrDefault(d => d.Type == "ObjectDetection" && d.Exportable == true);

                if (projectId == Guid.Empty)
                {
                    Console.WriteLine("Creating new project.");
                    projectId = client.CreateProject(configuration["projectName"], domainId: objDetectionDomain.Id).Id;
                }
                else
                {
                    var tags = client.GetTags(projectId);
                    tagIdMapping = new Dictionary <string, Guid>(tags.Select((t) => new KeyValuePair <string, Guid>(t.Name, t.Id)));
                    tagCounting  = new Dictionary <string, int>(tags.Select((t) => new KeyValuePair <string, int>(t.Name, t.ImageCount)));
                }
            }

            foreach (var batchItem in imageBatches)
            {
                Console.WriteLine("Processing batch...");

                foreach (var fileName in batchItem)
                {
                    var fn = Path.GetFileNameWithoutExtension(fileName);

                    using (System.Drawing.Image measureImg = System.Drawing.Image.FromFile(fileName))
                    {
                        fullWidth  = measureImg.Width;
                        fullHeight = measureImg.Height;
                    }

                    Console.WriteLine($"Image: {fn} {fullWidth}x{fullHeight}");

                    var newEntry = new ImageFileCreateEntry()
                    {
                        Name     = fn,
                        Contents = File.ReadAllBytes(fileName),
                        Regions  = new List <Region>(),
                    };

                    if (format == FORMAT_CNTK)
                    {
                        Console.WriteLine("Processing " + fn);

                        var classes = File.ReadAllLines(Path.Join(configuration["imagesPath"], fn + ".bboxes.labels.tsv"));
                        var boxes   = File.ReadAllLines(Path.Join(configuration["imagesPath"], fn + ".bboxes.tsv"));

                        for (int i = 0; i < boxes.Length; i++)
                        {
                            if (string.IsNullOrWhiteSpace(classes[i]))
                            {
                                continue;
                            }

                            // break boxes and normalize them (0-1)
                            var    coords = boxes[i].Split('\t');
                            double left   = double.Parse(coords[0], CultureInfo.InvariantCulture) / fullWidth;
                            double top    = double.Parse(coords[1], CultureInfo.InvariantCulture) / fullHeight;
                            double width  = (double.Parse(coords[2], CultureInfo.InvariantCulture) / fullWidth) - left;
                            double height = (double.Parse(coords[3], CultureInfo.InvariantCulture) / fullHeight) - top;

                            // create tag if needed
                            if (!tagIdMapping.ContainsKey(classes[i]))
                            {
                                if (online)
                                {
                                    var createdTag = client.CreateTag(projectId, classes[i]);
                                    tagIdMapping.Add(createdTag.Name, createdTag.Id);
                                    tagCounting.Add(createdTag.Name, 0);
                                }
                                else
                                {
                                    tagIdMapping.Add(classes[i], Guid.Empty);
                                    tagCounting.Add(classes[i], 0);
                                }

                                Console.WriteLine("New tag " + classes[i]);
                            }

                            // add boxes
                            newEntry.Regions.Add(new Region(tagIdMapping[classes[i]], left, top, width, height));
                            tagCounting[classes[i]]++;
                            Console.WriteLine($"TagCounting: {classes[i]} = {tagCounting[classes[i]]}");
                        }

                        imageFileEntries.Add(newEntry);
                    }

                    if (format == FORMAT_LABELBOX)
                    {
                        var labels = File.ReadAllLines(Path.Join(configuration["imagesPath"], fn + ".txt"));

                        foreach (var l in labels)
                        {
                            var explodedL   = l.Split('\t'); // 7->75 9 75 29 87 29 87 9 112 8 112 28 123 28 123 8
                            var labelName   = explodedL[0];  // 7
                            var coordinates = explodedL[1].Split(' ');

                            // one label can have multiple rectangles
                            do
                            {
                                var coords = coordinates.Take(8).ToArray(); // 75 9 75 29 87 29 87 9 112 8 112 28 123 28 123 8

                                // no coordinates, skip this label
                                if (string.IsNullOrWhiteSpace(explodedL[1]))
                                {
                                    continue;
                                }

                                // candidate for top left point
                                double left = double.Parse(coords[0]);
                                double top  = double.Parse(coords[1]);

                                // go through the rest of the coords to find if the candidate is really top-left
                                for (int i = 2; i < 8; i += 2)
                                {
                                    if (double.Parse(coords[i]) <= left && double.Parse(coords[i + 1]) <= top)
                                    {
                                        left = double.Parse(coords[i]);
                                        top  = double.Parse(coords[i + 1]);
                                    }
                                }

                                // candidate for bottom right point
                                double right  = double.Parse(coords[4]);
                                double bottom = double.Parse(coords[5]);

                                // go through the coords to find if the candidate is really bottom-right
                                for (int i = 0; i < 8; i += 2)
                                {
                                    if (double.Parse(coords[i]) >= right && double.Parse(coords[i + 1]) >= bottom)
                                    {
                                        right  = double.Parse(coords[i]);
                                        bottom = double.Parse(coords[i + 1]);
                                    }
                                }

                                // normalize for Custom Vision
                                left   = left / fullWidth;
                                top    = top / fullHeight;
                                right  = right / fullWidth;
                                bottom = bottom / fullHeight;

                                // calculate width, height for custom vision
                                double width  = Difference(right, left);
                                double height = Difference(bottom, top);

                                if (!tagIdMapping.ContainsKey(labelName))
                                {
                                    if (online)
                                    {
                                        var createdTag = client.CreateTag(projectId, labelName);
                                        tagIdMapping.Add(createdTag.Name, createdTag.Id);
                                        tagCounting.Add(createdTag.Name, 0);
                                    }
                                    else
                                    {
                                        tagIdMapping.Add(labelName, Guid.Empty);
                                        tagCounting.Add(labelName, 0);
                                    }

                                    Console.WriteLine("New tag " + labelName);
                                }

                                // add boxes
                                newEntry.Regions.Add(new Region(tagIdMapping[labelName], left, top, width, height));
                                tagCounting[labelName]++;
                                Console.WriteLine($"TagCounting: {labelName} = {tagCounting[labelName]}");
                            }while ((coordinates = coordinates.Skip(8).ToArray()).Length > 0);
                        }

                        // no boxes, skip this image
                        if (newEntry.Regions.Count == 0)
                        {
                            continue;
                        }

                        imageFileEntries.Add(newEntry);
                    }
                }

                if (imageFileEntries.Count > 0 && online)
                {
                    Console.WriteLine("Uploading batch...");
                    client.CreateImagesFromFiles(projectId, new ImageFileCreateBatch(imageFileEntries));
                }

                // store everything to a text file for further inspection
                if (bool.Parse(configuration["dumpResults"]))
                {
                    File.AppendAllText(Path.Join(configuration["imagesPath"], "dump.txt"), JsonConvert.SerializeObject(imageFileEntries));
                }

                imageFileEntries.Clear();
            }

            if (bool.Parse(configuration["tagCleanup"]))
            {
                Console.WriteLine("Cleanup...");
                foreach (var tag in tagCounting)
                {
                    // Less than 15 images per tag is not enough for Custom Vision.
                    // Not enough images for this tag => gone.
                    if (tag.Value < 15)
                    {
                        if (online)
                        {
                            Console.WriteLine($"Deleting tag {tag.Key} with {tag.Value} images.");
                            client.DeleteTag(projectId, tagIdMapping[tag.Key]);
                        }
                        else
                        {
                            Console.WriteLine($"Would delete tag {tag.Key} with {tag.Value} images.");
                        }
                    }
                }
            }

            Console.WriteLine("Done.");
            Console.ReadKey();
        }