Example #1
0
 /// <inheritdoc />
 public void Apply(ImageContext context)
 {
     this.ApplyConvolution(this.Kernel, _kernelWidth, _kernelHeight, context);
 }
Example #2
0
        public void PerformMetaDataScan()
        {
            Logging.LogVerbose("Full Metadata scan starting...");

            try
            {
                var watch = new Stopwatch("FullMetaDataScan", -1);

                using var db = new ImageContext();

                const int batchSize = 100;
                bool      complete  = false;

                while (!complete)
                {
                    var queueQueryWatch = new Stopwatch("MetaDataQueueQuery", -1);

                    // Find all images where there's either no metadata, or where the image
                    // was updated more recently than the image metadata
                    var imagesToScan = db.Images.Where(x => x.MetaData == null || x.MetaData.LastUpdated < x.LastUpdated)
                                       .OrderByDescending(x => x.LastUpdated)
                                       .Take(batchSize)
                                       .Include(x => x.Folder)
                                       .Include(x => x.MetaData)
                                       .ToArray();

                    queueQueryWatch.Stop();

                    complete = !imagesToScan.Any();

                    if (!complete)
                    {
                        var batchWatch = new Stopwatch("MetaDataBatch", 100000);

                        // Aggregate stuff that we'll collect up as we scan
                        var imageKeywords = new ConcurrentDictionary <Image, string[]>();

                        var newMetadataEntries = new List <ImageMetaData>();
                        var updatedEntries     = new List <ImageMetaData>();
                        var updatedImages      = new List <Image>();

                        foreach (var img in imagesToScan)
                        {
                            ImageMetaData imgMetaData = img.MetaData;

                            if (imgMetaData == null)
                            {
                                // New metadata
                                imgMetaData = new ImageMetaData {
                                    ImageId = img.ImageId, Image = img
                                };
                                newMetadataEntries.Add(imgMetaData);
                            }
                            else
                            {
                                updatedEntries.Add(imgMetaData);
                            }

                            GetImageMetaData(ref imgMetaData, out var keywords);

                            if (img.SortDate != imgMetaData.DateTaken)
                            {
                                // Update the image sort date with the date taken
                                img.SortDate    = imgMetaData.DateTaken;
                                img.LastUpdated = DateTime.UtcNow;
                                updatedImages.Add(img);
                            }

                            if (keywords.Any())
                            {
                                imageKeywords[img] = keywords;
                            }

                            // Yield a bit. TODO: must be a better way of doing this
                            Thread.Sleep(50);
                        }

                        var saveWatch = new Stopwatch("MetaDataSave");
                        Logging.LogTrace($"Adding {newMetadataEntries.Count()} and updating {updatedEntries.Count()} metadata entries.");

                        if (!ImageContext.ReadOnly)
                        {
                            db.BulkInsert(newMetadataEntries);
                            db.BulkUpdate(updatedEntries);
                            db.BulkUpdate(updatedImages);
                        }

                        saveWatch.Stop();

                        var tagWatch = new Stopwatch("AddTagsSave");

                        // Now save the tags
                        AddTags(imageKeywords);

                        tagWatch.Stop();

                        batchWatch.Stop();

                        Logging.Log($"Completed metadata scan batch ({imagesToScan.Length} images in {batchWatch.HumanElapsedTime}, save: {saveWatch.HumanElapsedTime}, tags: {tagWatch.HumanElapsedTime}).");
                    }
                }

                watch.Stop();
            }
            catch (Exception ex)
            {
                Logging.LogError($"Exception caught during metadata scan: {ex}");
            }

            Logging.LogVerbose("Metadata Scan Complete.");
        }
 /// <inheritdoc />
 public void Apply(ImageContext context)
 {
     throw new NotImplementedException();
 }
Example #4
0
    /// <summary>
    /// Given a collection of images and their keywords, performs a bulk insert
    /// of them all. This is way more performant than adding the keywords as
    /// each image is indexed, and allows us to bulk-update the freetext search
    /// too.
    /// </summary>
    /// <param name="imageKeywords"></param>
    /// <param name="type"></param>
    private async Task <int> WriteTagsForImage(Image image, List <string> imageKeywords)
    {
        int tagsAdded = 0;
        var watch     = new Stopwatch("WriteTagsForImage");

        if (ImageContext.ReadOnly)
        {
            return(tagsAdded);
        }

        try
        {
            // First, find all the distinct keywords, and check whether
            // they're in the cache. If not, create them in the DB.
            await CreateTagsFromStrings(imageKeywords);
        }
        catch (Exception ex)
        {
            Logging.LogError("Exception adding Tags: {0}", ex);
        }

        using ImageContext db = new ImageContext();

        using (var transaction = db.Database.BeginTransaction())
        {
            try
            {
                // Create the new tag objects, pulling the tags from the cache
                var newImageTags = imageKeywords.Select(keyword => new ImageTag
                {
                    ImageId = image.ImageId,
                    TagId   = _tagCache[keyword].TagId
                })
                                   .ToList();

                Logging.LogTrace($"Updating {newImageTags.Count()} ImageTags");

                // First, get the image tags for the image
                var existingImageTagIds = image.ImageTags.Select(x => x.TagId).ToList();

                // Figure out which tags are new, and which existing tags need to be removed.
                var toDelete = existingImageTagIds.Where(id => !newImageTags.Select(x => x.TagId).Contains(id)).ToList();
                var toAdd    = newImageTags.Where(x => !existingImageTagIds.Contains(x.TagId)).ToList();

                if (toDelete.Any())
                {
                    Stopwatch delWatch = new Stopwatch("AddTagsDelete");
                    await db.BatchDelete(db.ImageTags.Where(y => y.ImageId == image.ImageId && toDelete.Contains(y.TagId)));

                    delWatch.Stop();
                }

                if (toAdd.Any())
                {
                    Stopwatch addWatch = new Stopwatch("AddTagsInsert");
                    await db.BulkInsert(db.ImageTags, toAdd);;
                    addWatch.Stop();
                }
                transaction.Commit();
                tagsAdded = newImageTags.Count;
            }
            catch (Exception ex)
            {
                Logging.LogError("Exception adding ImageTags: {0}", ex);
            }
        }

        watch.Stop();

        return(tagsAdded);
    }
Example #5
0
        /// <summary>
        /// Indexes all of the images in a folder, optionally filtering for a last-mod
        /// threshold and only indexing those images which have changed since that date.
        /// </summary>
        /// <param name="folder"></param>
        /// <param name="threshold"></param>
        /// <param name="parent"></param>
        public void IndexFolder(DirectoryInfo folder, Folder parent, bool isFullIndex)
        {
            Folder folderToScan = null;

            // Get all the sub-folders on the disk, but filter out
            // ones we're not interested in.
            var subFolders = folder.SafeGetSubDirectories()
                             .Where(x => x.IsMonitoredFolder())
                             .ToList();

            try
            {
                using (var db = new ImageContext())
                {
                    // Load the existing folder and its images from the DB
                    folderToScan = db.Folders
                                   .Where(x => x.Path.Equals(folder.FullName))
                                   .Include(x => x.Images)
                                   .FirstOrDefault();

                    if (folderToScan == null)
                    {
                        Logging.LogVerbose("Scanning new folder: {0}\\{1}", folder.Parent.Name, folder.Name);
                        folderToScan = new Folder {
                            Path = folder.FullName
                        };
                    }
                    else
                    {
                        Logging.LogVerbose("Scanning existing folder: {0}\\{1} ({2} images in DB)", folder.Parent.Name, folder.Name, folderToScan.Images.Count());
                    }

                    if (parent != null)
                    {
                        folderToScan.ParentFolderId = parent.FolderId;
                    }

                    bool foldersChanged = false;

                    if (folderToScan.FolderId == 0)
                    {
                        Logging.Log($"Adding new folder: {folderToScan.Path}");
                        // New folder, add it.
                        db.Folders.Add(folderToScan);
                        db.SaveChanges("AddFolders");
                        foldersChanged = true;
                    }

                    // Now, check for missing folders, and clean up if appropriate.
                    foldersChanged = RemoveMissingChildDirs(db, folderToScan) || foldersChanged;

                    if (foldersChanged)
                    {
                        NotifyFolderChanged();
                    }
                }

                // Now scan the images:
                ScanFolderImages(folderToScan, isFullIndex);

                CreateFileWatcher(folder);
            }
            catch (Exception ex)
            {
                Logging.LogError($"Unexpected exception scanning folder {folderToScan.Name}: {ex.Message}");
                if (ex.InnerException != null)
                {
                    Logging.LogError($" Inner exception: {ex.InnerException.Message}");
                }
            }

            // Scan subdirs recursively.
            foreach (var sub in subFolders)
            {
                IndexFolder(sub, folderToScan, isFullIndex);
            }
        }
Example #6
0
 public string GetPotentialLicensePlateFullPath(ImageContext imageContext, int number) => @$ "{imageContext.FolderPath}\Potential\{imageContext.FileName}\{number}.png";
Example #7
0
    /// <summary>
    /// Select or deselect an image - adding or removing it from the basket.
    /// </summary>
    /// <param name="image"></param>
    /// <param name="newState"></param>
    /// <param name="basket"></param>
    public async Task SetBasketState(ICollection <Image> images, bool newState, Basket basket)
    {
        try
        {
            using var db = new ImageContext();
            bool changed = false;
            var  watch   = new Stopwatch("SetSelection");

            var existingEntries = db.BasketEntries.Where(x => x.BasketId == basket.BasketId &&
                                                         images.Select(img => img.ImageId).Contains(x.ImageId)).ToList();

            if (newState)
            {
                // TODO: skip existing. Do we need this?!
                var imagesToAdd = images.Where(img => !existingEntries.Select(x => x.ImageId).Contains(img.ImageId)).ToList();

                var basketEntries = imagesToAdd.Select(img => new BasketEntry
                {
                    ImageId   = img.ImageId,
                    BasketId  = basket.BasketId,
                    DateAdded = DateTime.UtcNow
                }).ToList();

                if (basketEntries.Any())
                {
                    await db.BulkInsert(db.BasketEntries, basketEntries);

                    if (CurrentBasket.BasketId == basket.BasketId)
                    {
                        imagesToAdd.ForEach(img =>
                        {
                            if (img.BasketEntries.Any(x => x.BasketId == basket.BasketId))
                            {
                                // Associate the basket entry with the image
                                img.BasketEntries.Add(basketEntries.First(x => x.ImageId == img.ImageId));
                            }

                            BasketImages.Add(img);
                        });

                        changed = true;
                        _statusService.StatusText = $"Added {imagesToAdd.Count} image to the basket.";
                    }
                }
            }
            else if (!newState)
            {
                if (await db.BulkDelete(db.BasketEntries, existingEntries))
                {
                    foreach (var image in images)
                    {
                        image.BasketEntries.RemoveAll(x => x.BasketId == basket.BasketId);
                    }

                    if (CurrentBasket.BasketId == basket.BasketId)
                    {
                        BasketImages.RemoveAll(x => images.Select(x => x.ImageId).Contains(x.ImageId));
                        changed = true;

                        _statusService.StatusText = $"Removed {existingEntries.Count} images from the basket.";
                    }
                }
            }

            watch.Stop();

            if (changed)
            {
                NotifyStateChanged();
            }
        }
        catch (Exception ex)
        {
            Logging.LogError($"Unable to update the basket: {ex.Message}");
        }
    }
 public SubmittedImageRepository(ImageContext dbContext)
 {
     _dbContext = dbContext;
     _images    = dbContext.Images;
 }
 /// <summary>
 /// Detects document text in a single image asynchronously.
 /// </summary>
 /// <remarks>
 /// If <see cref="AnnotateImageException"/> is thrown, the original response can still be retrieved using
 /// <see cref="AnnotateImageException.Response"/>.
 /// </remarks>
 /// <param name="image">The image to process. Must not be null.</param>
 /// <param name="context">Additional contextual information, if any.</param>
 /// <param name="callSettings">Call settings to apply to the RPC, if any.</param>
 /// <exception cref="AnnotateImageException">The RPC returns a response, but the response contains an error.</exception>
 /// <returns>A task representing the asynchronous operation. The task result will be a set of annotations.</returns>
 public virtual Task <TextAnnotation> DetectDocumentTextAsync(Image image, ImageContext context = null, CallSettings callSettings = null)
 => AnnotateSingleSingularFeatureTypeAsync(Feature.Types.Type.DocumentTextDetection, r => r.FullTextAnnotation, image, context, callSettings);
        private bool TryDetectText(Image image, out string resultText, out List <string> otherText)
        {
            resultText = null;
            otherText  = new List <string>();

            // Create ImageAnnotatorClient
            ImageAnnotatorClient client;

            if (_googleCredentialFilePath != null)
            {
                var googleCredential = GoogleCredential.FromStream(System.IO.File.OpenRead(_googleCredentialFilePath));
                var channel          = new Grpc.Core.Channel(ImageAnnotatorClient.DefaultEndpoint.Host, googleCredential.ToChannelCredentials());
                client = ImageAnnotatorClient.Create(channel);
            }
            else
            {
                client = ImageAnnotatorClient.Create();
            }

            //
            var context = new ImageContext();

            context.LanguageHints.Add("ja");
            context.LanguageHints.Add("en");

            // Detect text
            var response = client.DetectDocumentText(image, context);

            if (response == null || string.IsNullOrWhiteSpace(response.Text))
            {
                return(false);
            }

            resultText = response.Text.Trim();

            // Remove spaces and Replace characters.
            var lines = resultText.Split(new[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);

            foreach (var page in response.Pages)
            {
                foreach (var block in page.Blocks)
                {
                    foreach (var paragraph in block.Paragraphs)
                    {
                        // Create MySymbol list
                        var list = new List <MySymbol>();

                        var symbols = paragraph.Words.SelectMany(w => w.Symbols).ToList();
                        for (var i = 0; i < symbols.Count - 1; i++)
                        {
                            var s = new MySymbol
                            {
                                Text       = symbols[i].Text,
                                SpaceWidth = symbols[i + 1].BoundingBox.Vertices.Min(v => v.X)
                                             - symbols[i].BoundingBox.Vertices.Max(v => v.X),
                                BreakType = symbols[i].Property?.DetectedBreak?.Type
                            };

                            list.Add(s);
                        }
                        list.Add(new MySymbol
                        {
                            Text = symbols.Last().Text
                        });

                        if (list.All(i => i.BreakType == null))
                        {
                            continue;
                        }

                        // Remove spaces
                        var median  = list.Where(i => i.BreakType == TextAnnotation.Types.DetectedBreak.Types.BreakType.Space).Select(i => i.SpaceWidth)?.Median();
                        var builder = new StringBuilder();
                        foreach (var s in list)
                        {
                            builder.Append(s.Text);

                            if (median.HasValue &&
                                s.BreakType != null &&
                                s.SpaceWidth > median * 1.5)
                            {
                                builder.Append(" ");
                            }

                            Debug.WriteLine($"{s.Text}: {s.SpaceWidth}");
                        }

                        var text = builder.ToString().Trim();
                        Debug.WriteLine(text);
                        if (!lines.Contains(text))
                        {
                            otherText.Add(text);
                        }

                        // 1 -> l
                        if (text.Contains("1"))
                        {
                            var text2 = text.Replace("1", "l");
                            if (!lines.Contains(text2))
                            {
                                otherText.Add(text2);
                            }
                        }
                    }
                }
            }
            return(true);
        }
Example #11
0
        /// <summary>
        /// Apply a convolution based on the kernel passed in.
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        /// <param name="kernelWidth">The kernel's width.</param>
        /// <param name="kernelHeight">The kernel's height.</param>
        /// <param name="context">An image context providing additional metadata on the data passed in.</param>
        public void ApplyConvolution(double[,] kernel, int kernelWidth, int kernelHeight, ImageContext context)
        {
            var localContext = context.Raw ? context : CloneToRawBitmap(context);

            bool storeFromRaw = context.Raw && context.StoreFormat != null;

            var analyser = new FrameAnalyser
            {
                HorizonalCellCount = _horizontalCellCount,
                VerticalCellCount  = _verticalCellCount,
            };

            analyser.Apply(localContext);

            Parallel.ForEach(analyser.CellRect, (cell)
                             => ProcessCell(cell, localContext.Data, kernel, kernelWidth, kernelHeight, analyser.Metadata, storeFromRaw));

            if (context.StoreFormat != null)
            {
                FormatRawBitmap(localContext, context);
                context.Raw = false; // context is never raw after formatting
            }
            else
            {
                if (!context.Raw)
                {
                    // TakePicture doesn't set the Resolution, copy it from the cloned version which stored it from Bitmap
                    context.Resolution = new Resolution(localContext.Resolution.Width, localContext.Resolution.Height);

                    context.Data = new byte[localContext.Data.Length];
                    Array.Copy(localContext.Data, context.Data, context.Data.Length);
                    context.Raw = true; // we just copied raw data to the source context
                }
            }
        }
 public ImageController(IFileProvider FileProvider, IConfiguration configuration, ImageContext _dbcontext)
 {
     this.FileProvider = FileProvider;
     Configuration     = configuration;
     this._dbcontext   = _dbcontext;
 }
 /// <summary>
 /// Detects text in a single image.
 /// </summary>
 /// <remarks>
 /// If <see cref="AnnotateImageException"/> is thrown, the original response can still be retrieved using
 /// <see cref="AnnotateImageException.Response"/>.
 /// </remarks>
 /// <param name="image">The image to process. Must not be null.</param>
 /// <param name="context">Additional contextual information, if any.</param>
 /// <param name="maxResults">The maximum number of results to return. 0 (the default) means "unlimited". Must not be negative.</param>
 /// <param name="callSettings">Call settings to apply to the RPC, if any.</param>
 /// <exception cref="AnnotateImageException">The RPC returns a response, but the response contains an error.</exception>
 /// <returns>A set of annotations.</returns>
 public IReadOnlyList <EntityAnnotation> DetectText(Image image, ImageContext context = null, int maxResults = 0, CallSettings callSettings = null)
 => AnnotateSingleFeatureType(Feature.Types.Type.TextDetection, r => r.TextAnnotations, image, context, maxResults, callSettings);
Example #14
0
 public ImageService(ImageContext imageContext, IYandexDiskService yandexDiskService)
 {
     _imageContext      = imageContext;
     _yandexDiskService = yandexDiskService;
 }
Example #15
0
        public void DataObject()
        {
            NORTHWINDEntities db = new NORTHWINDEntities();
            var records = (from o in db.Orders
                           select o).AsEnumerable();
            //db.Orders();
            //Moq.Linq();
            ImageContext image = new ImageContext();
            for (int i = 0; i <= 100; i++) {

                image.Images.Add(new ImageModel() {
                    Id = int.MinValue
                });
            }
            IEnumerable<ImageModel> img = (from r in image.Images
                                           where r != null
                                           select r).AsEnumerable();
            //var ll = new LazyLoader;
            //LazyLoader;

            //Moq.Linq(img);
            //img.Cast<ImagesDBContext>(image)(img);

            Assert.IsNotNull(image);
        }
 /// <summary>
 /// Suggests crop hints for a single image asynchronously.
 /// </summary>
 /// <remarks>
 /// If <see cref="AnnotateImageException"/> is thrown, the original response can still be retrieved using
 /// <see cref="AnnotateImageException.Response"/>.
 /// </remarks>
 /// <param name="image">The image to process. Must not be null.</param>
 /// <param name="context">Additional contextual information, if any.</param>
 /// <param name="callSettings">Call settings to apply to the RPC, if any.</param>
 /// <exception cref="AnnotateImageException">The RPC returns a response, but the response contains an error.</exception>
 /// <returns>A task representing the asynchronous operation. The task result will be a set of annotations.</returns>
 public virtual Task <CropHintsAnnotation> DetectCropHintsAsync(Image image, ImageContext context = null, CallSettings callSettings = null)
 => AnnotateSingleSingularFeatureTypeAsync(Feature.Types.Type.CropHints, r => r.CropHintsAnnotation, image, context, callSettings);
Example #17
0
        public void GetNWEntities()
        {
            ImageContext images = new ImageContext();

            //var records = (from r in images.Images
            //               where r != null
            //               select r).AsEnumerable();

            //Assert.IsNotNull(records);
        }
 /// <summary>
 /// Performs web detection for a single image asynchronously.
 /// </summary>
 /// <remarks>
 /// If <see cref="AnnotateImageException"/> is thrown, the original response can still be retrieved using
 /// <see cref="AnnotateImageException.Response"/>.
 /// </remarks>
 /// <param name="image">The image to process. Must not be null.</param>
 /// <param name="context">Additional contextual information, if any.</param>
 /// <param name="callSettings">Call settings to apply to the RPC, if any.</param>
 /// <exception cref="AnnotateImageException">The RPC returns a response, but the response contains an error.</exception>
 /// <returns>A task representing the asynchronous operation. The task result will be a set of annotations.</returns>
 public virtual Task <WebDetection> DetectWebInformationAsync(Image image, ImageContext context = null, CallSettings callSettings = null)
 => AnnotateSingleSingularFeatureTypeAsync(Feature.Types.Type.WebDetection, r => r.WebDetection, image, context, callSettings);
Example #19
0
            public bool RefreshEffectParameters(IVideoPlayer player, Texture texture)
            {
                ISharpDXVideoPlayer sdvPlayer = player as ISharpDXVideoPlayer;

                if (sdvPlayer == null || texture == null || texture.IsDisposed)
                {
                    return(false);
                }
                SizeF      aspectRatio   = sdvPlayer.VideoAspectRatio.ToSize2F();
                Size       playerSize    = sdvPlayer.VideoSize.ToSize2();
                Rectangle  cropVideoRect = sdvPlayer.CropVideoRect;
                IGeometry  geometry      = ChooseVideoGeometry(player);
                string     effectName    = player.EffectOverride;
                int        deviceWidth   = GraphicsDevice.Width; // To avoid threading issues if the device size changes
                int        deviceHeight  = GraphicsDevice.Height;
                RectangleF vertsBounds   = GetVertBounds();

                // Do we need a refresh?
                if (!_refresh &&
                    _lastVideoSize == playerSize &&
                    _lastAspectRatio == aspectRatio &&
                    _lastCropVideoRect == cropVideoRect &&
                    _lastGeometry == geometry &&
                    _lastEffect == effectName &&
                    _lastDeviceWidth == deviceWidth &&
                    _lastDeviceHeight == deviceHeight &&
                    _lastVertsBounds == vertsBounds)
                {
                    return(true);
                }

                _lastVertsBounds = vertsBounds;
                SizeF targetSize = vertsBounds.Size;

                lock (sdvPlayer.SurfaceLock)
                {
                    SurfaceDescription desc = texture.GetLevelDescription(0);
                    _videoTextureClip = new RectangleF(cropVideoRect.X / desc.Width, cropVideoRect.Y / desc.Height,
                                                       cropVideoRect.Width / desc.Width, cropVideoRect.Height / desc.Height);
                }
                _scaledVideoSize = new SizeF(cropVideoRect.Width, cropVideoRect.Height);

                // Correct aspect ratio for anamorphic video
                if (!aspectRatio.IsEmpty() && geometry.RequiresCorrectAspectRatio)
                {
                    float pixelRatio = aspectRatio.Width / aspectRatio.Height;
                    _scaledVideoSize.Width = _scaledVideoSize.Height * pixelRatio;
                }
                // Adjust target size to match final Skin scaling
                targetSize = ImageContext.AdjustForSkinAR(targetSize);

                // Adjust video size to fit desired geometry
                _scaledVideoSize = geometry.Transform(_scaledVideoSize.ToDrawingSizeF(), targetSize.ToDrawingSizeF()).ToSize2F();

                // Cache inverse RelativeTransform
                Transform relativeTransform = GetRelativeTransform();

                _inverseRelativeTransformCache = (relativeTransform == null) ? Matrix.Identity : Matrix.Invert(relativeTransform.GetTransform());

                // Prepare our ImageContext
                _imageContext.FrameSize       = targetSize;
                _imageContext.ShaderBase      = EFFECT_BASE_VIDEO;
                _imageContext.ShaderTransform = geometry.Shader;
                _imageContext.ShaderEffect    = player.EffectOverride;

                // Store state
                _lastFrameData     = new Vector4(playerSize.Width, playerSize.Height, 0.0f, 0.0f);
                _lastVideoSize     = playerSize;
                _lastAspectRatio   = aspectRatio;
                _lastGeometry      = geometry;
                _lastCropVideoRect = cropVideoRect;
                _lastEffect        = effectName;
                _lastDeviceWidth   = deviceWidth;
                _lastDeviceHeight  = deviceHeight;

                _refresh = false;
                return(true);
            }
 /// <summary>
 /// Performs "safe search" processing on a single image asynchronously.
 /// </summary>
 /// <remarks>
 /// If <see cref="AnnotateImageException"/> is thrown, the original response can still be retrieved using
 /// <see cref="AnnotateImageException.Response"/>.
 /// </remarks>
 /// <param name="image">The image to process. Must not be null.</param>
 /// <param name="context">Additional contextual information, if any.</param>
 /// <param name="callSettings">Call settings to apply to the RPC, if any.</param>
 /// <exception cref="AnnotateImageException">The RPC returns a response, but the response contains an error.</exception>
 /// <returns>A task representing the asynchronous operation. The task result will be the safe search categorization for the image.</returns>
 public virtual Task <SafeSearchAnnotation> DetectSafeSearchAsync(Image image, ImageContext context = null, CallSettings callSettings = null)
 => AnnotateSingleSingularFeatureTypeAsync(Feature.Types.Type.SafeSearchDetection, r => r.SafeSearchAnnotation, image, context, callSettings);
Example #21
0
    /// <summary>
    /// Scan the metadata for an image - including the EXIF data, keywords
    /// and any XMP/ON1 sidecars. Then the metadata is written to the DB.
    /// </summary>
    /// <param name="imageId"></param>
    /// <returns></returns>
    public async Task ScanMetaData(int imageId)
    {
        Stopwatch watch = new Stopwatch("ScanMetadata");

        var writeSideCarTagsToImages = _configService.GetBool(ConfigSettings.ImportSidecarKeywords);

        using var db = new ImageContext();
        var                updateTimeStamp = DateTime.UtcNow;
        var                imageKeywords   = new List <string>();
        List <string>      sideCarTags     = new List <string>();
        List <ImageObject> xmpFaces        = null;

        var img = await _imageCache.GetCachedImage(imageId);

        db.Attach(img);

        try
        {
            var lastWriteTime = File.GetLastWriteTimeUtc(img.FullPath);

            if (lastWriteTime > DateTime.UtcNow.AddSeconds(-10))
            {
                // If the last-write time is within 30s of now,
                // skip it, as it's possible it might still be
                // mid-copy.
                // TODO: We need a better way of managing this
                Logging.LogVerbose($"Skipping metadata scan for {img.FileName} - write time is too recent.");
                return;
            }

            ImageMetaData imgMetaData = img.MetaData;

            if (imgMetaData == null)
            {
                imgMetaData = new ImageMetaData {
                    ImageId = img.ImageId, Image = img
                };
                img.MetaData = imgMetaData;
                db.ImageMetaData.Add(imgMetaData);
            }
            else
            {
                db.ImageMetaData.Update(imgMetaData);
            }

            // Update the timestamp regardless of whether we succeeded to read the metadata
            imgMetaData.LastUpdated = updateTimeStamp;

            // Scan the image from the
            if (GetImageMetaData(ref imgMetaData, out var exifKeywords, out xmpFaces))
            {
                // Scan for sidecar files
                sideCarTags = GetSideCarKeywords(img, exifKeywords, writeSideCarTagsToImages);

                imageKeywords = sideCarTags.Union(exifKeywords, StringComparer.OrdinalIgnoreCase).ToList();
            }

            if (imgMetaData.DateTaken != img.SortDate)
            {
                Logging.LogTrace($"Updating image {img.FileName} with DateTaken: {imgMetaData.DateTaken}.");
                // Always update the image sort date with the date taken,
                // if one was found in the metadata
                img.SortDate    = imgMetaData.DateTaken;
                img.LastUpdated = updateTimeStamp;
                db.Images.Update(img);
            }
            else
            {
                if (imgMetaData.DateTaken == DateTime.MinValue)
                {
                    Logging.LogTrace($"Not updating image {img.FileName} with DateTaken as no valid value.");
                }
            }
        }
        catch (Exception ex)
        {
            Logging.LogError($"Exception caught during metadata scan for {img.FullPath}: {ex.Message}.");
        }

        await db.SaveChangesAsync("ImageMetaDataSave");

        // Now save the tags
        var tagsAdded = await WriteTagsForImage(img, imageKeywords);

        await WriteXMPFaces(img, xmpFaces);

        _imageCache.Evict(imageId);

        watch.Stop();

        if (sideCarTags.Any() && writeSideCarTagsToImages)
        {
            // If we've enabled the option to write any sidecar keywords to IPTC
            // keywords if they're missing in the EXIF data of the image submit
            // the tags; note they won't get created immediately, but in batch.
            Logging.LogVerbose($"Applying {sideCarTags.Count} keywords from sidecar files to image {img.FileName}");

            // Fire and forget this asynchronously - we don't care about waiting for it
            _ = _exifService.UpdateTagsAsync(img, sideCarTags, null);
        }
    }
 /// <summary>
 /// Performs image property processing on a single image asynchronously.
 /// </summary>
 /// <remarks>
 /// If <see cref="AnnotateImageException"/> is thrown, the original response can still be retrieved using
 /// <see cref="AnnotateImageException.Response"/>.
 /// </remarks>
 /// <param name="image">The image to process. Must not be null.</param>
 /// <param name="context">Additional contextual information, if any.</param>
 /// <param name="callSettings">Call settings to apply to the RPC, if any.</param>
 /// <exception cref="AnnotateImageException">The RPC returns a response, but the response contains an error.</exception>
 /// <returns>A task representing the asynchronous operation. The task result will be the detected properties for the image.</returns>
 public virtual Task <ImageProperties> DetectImagePropertiesAsync(Image image, ImageContext context = null, CallSettings callSettings = null)
 => AnnotateSingleSingularFeatureTypeAsync(Feature.Types.Type.ImageProperties, r => r.ImagePropertiesAnnotation, image, context, callSettings);
Example #23
0
        /// <summary>
        /// Given a collection of images and their keywords, performs a bulk insert
        /// of them all. This is way more performant than adding the keywords as
        /// each image is indexed, and allows us to bulk-update the freetext search
        /// too.
        /// </summary>
        /// <param name="imageKeywords"></param>
        private void AddTags(IDictionary <Image, string[]> imageKeywords)
        {
            // See if we have any images that were written to the DB and have IDs
            if (!imageKeywords.Where(x => x.Key.ImageId != 0).Any())
            {
                return;
            }

            var watch = new Stopwatch("AddTags");

            using ImageContext db = new ImageContext();

            try
            {
                var newTags = imageKeywords.Where(x => x.Value != null && x.Value.Any())
                              .SelectMany(x => x.Value)
                              .Distinct()
                              .Where(x => _tagCache != null && !_tagCache.ContainsKey(x))
                              .Select(x => new Models.Tag {
                    Keyword = x, Type = "IPTC"
                })
                              .ToList();


                if (newTags.Any())
                {
                    Logging.LogTrace("Adding {0} tags", newTags.Count());

                    if (!ImageContext.ReadOnly)
                    {
                        var config = new BulkConfig {
                            SetOutputIdentity = true
                        };
                        db.BulkInsert(newTags, config);
                    }

                    // Add the new items to the cache.
                    foreach (var tag in newTags)
                    {
                        _tagCache[tag.Keyword] = tag;
                    }
                }
            }
            catch (Exception ex)
            {
                Logging.LogError("Exception adding Tags: {0}", ex);
            }

            if (!ImageContext.ReadOnly)
            {
                using (var transaction = db.Database.BeginTransaction())
                {
                    try
                    {
                        var newImageTags = imageKeywords.SelectMany(i => i.Value.Select(
                                                                        v => new ImageTag
                        {
                            ImageId = i.Key.ImageId,
                            TagId   = _tagCache[v].TagId
                        }))
                                           .ToList();

                        // Note that we need to delete all of the existing tags for an image,
                        // and then insert all of the new tags. This is so that if somebody adds
                        // one tag, and removes another, we maintain the list correctly.
                        Logging.LogTrace($"Updating {newImageTags.Count()} ImageTags");

                        db.ImageTags.Where(y => newImageTags.Select(x => x.ImageId).Contains(y.ImageId)).BatchDelete();
                        db.BulkInsertOrUpdate(newImageTags);

                        transaction.Commit();

                        db.FullTextTags(false);
                    }
                    catch (Exception ex)
                    {
                        Logging.LogError("Exception adding ImageTags: {0}", ex);
                    }
                }
            }

            watch.Stop();
        }
        // TODO: Async Detect* overloads accepting a CancellationToken? Can't be the last parameter, as it's not optional...

        /// <summary>
        /// Detects the faces in a single image.
        /// </summary>
        /// <remarks>
        /// If <see cref="AnnotateImageException"/> is thrown, the original response can still be retrieved using
        /// <see cref="AnnotateImageException.Response"/>.
        /// </remarks>
        /// <param name="image">The image to process. Must not be null.</param>
        /// <param name="context">Additional contextual information, if any.</param>
        /// <param name="maxResults">The maximum number of results to return. 0 (the default) means "unlimited". Must not be negative.</param>
        /// <param name="callSettings">Call settings to apply to the RPC, if any.</param>
        /// <exception cref="AnnotateImageException">The RPC returns a response, but the response contains an error.</exception>
        /// <returns>A set of annotations.</returns>
        public virtual IReadOnlyList <FaceAnnotation> DetectFaces(Image image, ImageContext context = null, int maxResults = 0, CallSettings callSettings = null)
        => AnnotateSingleFeatureType(Feature.Types.Type.FaceDetection, r => r.FaceAnnotations, image, context, maxResults, callSettings);
Example #25
0
        /// <summary>
        /// For a given folder, scans the disk to find all the images in that folder,
        /// and then indexes all of those images for metadata etc. Optionally takes
        /// a last-mod threshold which, if set, will mean that only images changed
        /// since that date will be processed.
        /// </summary>
        /// <param name="folderToScan"></param>
        /// <param name="force">Force the folder to be scanned</param>
        /// <returns></returns>
        private bool ScanFolderImages(Folder folderToScan, bool force = false)
        {
            int folderImageCount = 0;

            var folder        = new DirectoryInfo(folderToScan.Path);
            var allImageFiles = folder.SafeGetImageFiles();

            if (allImageFiles == null)
            {
                // Null here means we weren't able to read the contents of the directory.
                // So bail, and give up on this folder altogether.
                return(false);
            }

            // First, see if images have been added or removed since we last indexed.
            // If so, we disregard the last scan date of the folder and force the
            // update.
            int knownDBImages = folderToScan.Images.Count();

            if (knownDBImages != allImageFiles.Count())
            {
                Logging.LogVerbose($"New or removed images in folder {folderToScan.Name}.");
                force = true;
            }

            if (folderToScan.FolderScanDate != null && !force)
            {
                return(true);
            }

            using (var db = new ImageContext())
            {
                var watch = new Stopwatch("ScanFolderFiles");

                // Select just JPGs
                var imageFiles = allImageFiles.Where(x => x.IsImageFileType()).ToList();
                folderImageCount = imageFiles.Count();

                int newImages = 0, updatedImages = 0;
                foreach (var file in imageFiles)
                {
                    try
                    {
                        var existingImage = folderToScan.Images.FirstOrDefault(x => x.FileName.Equals(file.Name, StringComparison.OrdinalIgnoreCase));

                        if (existingImage != null && file.WriteTimesMatch(existingImage.FileLastModDate))
                        {
                            Logging.LogTrace("Indexed image {0} unchanged - skipping.", existingImage.FileName);
                            continue;
                        }

                        Image image = existingImage;

                        if (image == null)
                        {
                            image = new Image {
                                FileName = file.Name
                            };
                        }

                        // Store some info about the disk file
                        image.FileSizeBytes    = (ulong)file.Length;
                        image.FileCreationDate = file.CreationTimeUtc;
                        image.FileLastModDate  = file.LastWriteTimeUtc;

                        image.Folder      = folderToScan;
                        image.LastUpdated = DateTime.UtcNow;

                        if (existingImage == null)
                        {
                            // Default the sort date to the last write time. It'll get updated
                            // later during indexing to set it to the date-taken date.
                            image.SortDate = file.LastWriteTimeUtc;

                            Logging.LogTrace("Adding new image {0}", image.FileName);
                            folderToScan.Images.Add(image);
                            newImages++;
                        }
                        else
                        {
                            db.Images.Update(image);
                            updatedImages++;
                        }
                    }
                    catch (Exception ex)
                    {
                        Logging.LogError($"Exception while scanning for new image {file}: {ex.Message}");
                    }
                }

                // Now look for files to remove.
                // TODO - Sanity check that these don't hit the DB
                var filesToRemove  = folderToScan.Images.Select(x => x.FileName).Except(imageFiles.Select(x => x.Name));
                var dbImages       = folderToScan.Images.Select(x => x.FileName);
                var imagesToDelete = folderToScan.Images
                                     .Where(x => filesToRemove.Contains(x.FileName))
                                     .ToList();

                if (imagesToDelete.Any())
                {
                    imagesToDelete.ForEach(x => Logging.LogVerbose("Deleting image {0} (ID: {1})", x.FileName, x.ImageId));

                    // Removing these will remove the associated ImageTag and selection references.
                    db.Images.RemoveRange(imagesToDelete);
                }

                // Now update the folder to say we've processed it
                folderToScan.FolderScanDate = DateTime.UtcNow;
                db.Folders.Update(folderToScan);

                db.SaveChanges("FolderImageScan");

                watch.Stop();

                StatusService.Instance.StatusText = string.Format("Indexed folder {0}: processed {1} images ({2} new, {3} updated, {4} removed) in {5}.",
                                                                  folderToScan.Name, folderToScan.Images.Count(), newImages, updatedImages, imagesToDelete.Count(), watch.HumanElapsedTime);
            }

            return(true);
        }
 /// <summary>
 /// Detects labels for a single image asynchronously.
 /// </summary>
 /// <remarks>
 /// If <see cref="AnnotateImageException"/> is thrown, the original response can still be retrieved using
 /// <see cref="AnnotateImageException.Response"/>.
 /// </remarks>
 /// <param name="image">The image to process. Must not be null.</param>
 /// <param name="context">Additional contextual information, if any.</param>
 /// <param name="maxResults">The maximum number of results to return. 0 (the default) means "unlimited". Must not be negative.</param>
 /// <param name="callSettings">Call settings to apply to the RPC, if any.</param>
 /// <exception cref="AnnotateImageException">The RPC returns a response, but the response contains an error.</exception>
 /// <returns>A task representing the asynchronous operation. The task result will be a set of annotations.</returns>
 public virtual Task <IReadOnlyList <EntityAnnotation> > DetectLabelsAsync(Image image, ImageContext context = null, int maxResults = 0, CallSettings callSettings = null)
 => AnnotateSingleFeatureTypeAsync(Feature.Types.Type.LabelDetection, r => r.LabelAnnotations, image, context, maxResults, callSettings);
 public DockerImageRepository(
     ImageContext db,
     ILogger <DockerImage> logger) : base(db, logger)
 {
 }
        public void GroupBy_with_aggregate_does_not_throw_for_types_incompatible_with_GroupBy()
        {
            using (var context = new ImageContext())
            {
                var query2 = context.Users.GroupBy(o => o, u => new { u.Image, u.Name }, (k, g) => g.Count());

                Assert.DoesNotThrow(() => query2.ToList());
            }
        }
Example #29
0
 /// <inheritdoc />
 public void Apply(ImageContext context)
 {
     this.ApplyConvolution(_kernels[_kernelType], _kernelWidth, _kernelHeight, context);
 }
        public void GroupBy_fails_when_image_column_is_included()
        {
            using (var context = new ImageContext())
            {
                var query0 = from u in context.Users
                    group u by u.Image
                    into g
                    select new { Image = g.Key };

                Assert.Throws<EntityCommandExecutionException>(() => query0.ToList());   
            }            
        }
 /// <summary>
 /// Detects landmarks in a single image.
 /// </summary>
 /// <remarks>
 /// If <see cref="AnnotateImageException"/> is thrown, the original response can still be retrieved using
 /// <see cref="AnnotateImageException.Response"/>.
 /// </remarks>
 /// <param name="image">The image to process. Must not be null.</param>
 /// <param name="context">Additional contextual information, if any.</param>
 /// <param name="maxResults">The maximum number of results to return. 0 (the default) means "unlimited". Must not be negative.</param>
 /// <param name="callSettings">Call settings to apply to the RPC, if any.</param>
 /// <exception cref="AnnotateImageException">The RPC returns a response, but the response contains an error.</exception>
 /// <returns>A set of annotations.</returns>
 public virtual IReadOnlyList <EntityAnnotation> DetectLandmarks(Image image, ImageContext context = null, int maxResults = 0, CallSettings callSettings = null)
 => AnnotateSingleFeatureType(Feature.Types.Type.LandmarkDetection, r => r.LandmarkAnnotations, image, context, maxResults, callSettings);
Example #32
0
        public async Task Execute(PageAction pageAction, IEnumerable <ImageEntity> images, UserEntity user,
                                  SettingEntity settings, CancellationToken ct)
        {
            try
            {
                foreach (var image in images)
                {
                    try
                    {
                        OnStartExecuted.Invoke(image, pageAction);
                        image.ImageState = ImageState.InProcesses;
                        var pageContext = new ImageContext {
                            User = user, Settings = settings
                        };

                        foreach (var page in _pages.Where(a => a.Action == pageAction).OrderBy(a => a.Order))
                        {
                            if (ct.IsCancellationRequested)
                            {
                                break;
                            }

                            await page.ExecuteAsync(image, pageContext, ct);

                            if (page.GetImageState(image) == ImageState.Failed)
                            {
                                _logger.LogWarning(string.Format(LogTemplate, page.Order, page.Action));
                                break;
                            }

                            _logger.LogStep(page.Action.ToString(), image.ImagePath, page.Order.ToString());
                            OnStateChanged.Invoke(image.ImageState, image.Id);

                            await Task.Delay(TimeSpan.FromSeconds(2), ct); // to simulate user action
                        }

                        await _repository.AddOrUpdateAsync(image, ct);

                        OnExecute.Invoke(image, pageAction);

                        await Task.Delay(TimeSpan.FromSeconds(settings.WaitingBetweenUploadingImage), ct);
                    }
                    catch (TaskCanceledException)
                    {
                        break;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex.Message);
                        image.ImageState = ImageState.Failed;
                    }
                }

                if (images.Any(entity => entity.ImageState == ImageState.Failed) &&
                    _retryCount < settings.RetryCount)
                {
                    _retryCount++;
                    await Execute(pageAction, user.Images !.Where(entity => entity.ImageState == ImageState.Failed),
                                  user, settings, ct);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
                if (_retryCount > settings.RetryCount)
                {
                    throw;
                }
            }
        }
Example #33
0
        public void GetInterface()
        {
            IEnumerable _data = null;

            _data.GetType();
            NORTHWINDEntities db = new NORTHWINDEntities();
            var records = (from o in db.Orders
                           select o).AsEnumerable();

            ImageContext image = new ImageContext();
            for (int i = 0; i <= 100; i++) {
                image.Images.Add(new ImageModel() {
                    Id = int.MinValue
                });
            }

            IEnumerable<ImageModel> img = (from r in image.Images
                                           where r != null
                                           select r).AsEnumerable();
            Assert.IsNotNull(img);
        }
Example #34
0
 public ImageCrudRepository()
 {
     context = new ImageContext();
 }
Example #35
0
        protected virtual void DrawSpan(int length,
            float zStart,
            float zAdd,
            float uStart,
            float uAdd,
            float vStart,
            float vAdd,
            uint[] depthBuffer,
            int offset,
            int[] framebuffer,
            Image image,
            ImageContext imageContext)
        {
            for (var x = 0; x <= length; x++)
            {
                var bufferZ = (UInt32)((1.0f - zStart) * (float)UInt32.MaxValue);
                if (bufferZ > depthBuffer[offset] &&
                    zStart >= 0f &&
                    zStart < 1f
                    )
                {
                    var intu = ((int)uStart) & (image.Width - 1);
                    var intv = ((int)vStart) & (image.Height - 1);

                    var texel = ((intv << image.WidthBitCount) + intu);

                    framebuffer[offset] = imageContext.Pixels[texel];
                    depthBuffer[offset] = bufferZ;
                }

                offset++;
                zStart += zAdd;
                uStart += uAdd;
                vStart += vAdd;
            }
        }
Example #36
0
 public string GetContoursFullPath(ImageContext imageContext) => @$ "{imageContext.FolderPath}\Contours\{imageContext.FileName}_contours.png";