public static FaceFeaturesDB ExtractFeaturesDB(PhotoSketchFeatureExtractor extractor, List <PhotoMetadata> photos, bool savedb = true)
        {
            var dbName = string.Format("features-{0}.csv", DateTimeOffset.Now.ToUnixTimeMilliseconds());
            var db     = new FaceFeaturesDB();

            Parallel.ForEach(photos, photo =>
            {
                try {
                    var feature = extractor.ExtractFaceFeatures(photo.AbsolutePath);
                    db.AddPhotoFeatures(photo, feature);
                } catch (ArgumentException) { }
            });

            if (savedb)
            {
                db.Dump(dbName);
                Console.WriteLine("Features db saved on: {0}", dbName);
            }

            return(db);
        }
        public TaskExtractGalleryFeatures(PhotoSketchFeatureExtractor extractor, string galleryPath)
        {
            WorkerReportsProgress = true;
            DoWork += (s, e) =>
            {
                var db              = new FaceFeaturesDB();
                var photos          = PhotoMetadataCsv.FromCSV(galleryPath).ToList();
                var totalPhotos     = photos.Count;
                var currentProgress = 0;

                Parallel.ForEach(photos, photo =>
                {
                    try {
                        var feature = extractor.ExtractFaceFeatures(photo.AbsolutePath);
                        db.AddPhotoFeatures(photo, feature);
                    } catch (ArgumentException) { }

                    Interlocked.Increment(ref currentProgress);
                    ReportProgress((int)(currentProgress / (float)totalPhotos * 100));
                });

                e.Result = db;
            };
        }