/// <inheritdoc /> public void Apply(ImageContext context) { this.ApplyConvolution(this.Kernel, _kernelWidth, _kernelHeight, context); }
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(); }
/// <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); }
/// <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); } }
public string GetPotentialLicensePlateFullPath(ImageContext imageContext, int number) => @$ "{imageContext.FolderPath}\Potential\{imageContext.FileName}\{number}.png";
/// <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); }
/// <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);
public ImageService(ImageContext imageContext, IYandexDiskService yandexDiskService) { _imageContext = imageContext; _yandexDiskService = yandexDiskService; }
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);
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);
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);
/// <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);
/// <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);
/// <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()); } }
/// <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);
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; } } }
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); }
public ImageCrudRepository() { context = new ImageContext(); }
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; } }
public string GetContoursFullPath(ImageContext imageContext) => @$ "{imageContext.FolderPath}\Contours\{imageContext.FileName}_contours.png";