/// <summary> /// Reserves a rectangular area for the given image in this.Maze. /// The chosen location is remembered in this.imageLocations. /// Returns true if the reservation was successful. /// </summary> /// <param name="contourImage"></param> /// <returns></returns> private bool AddImage(ContourImage contourImage) { Image img = contourImage.DisplayedImage; int padding = MazePainter.ApplyScaleFactor(8) + this.wallWidth; int sqW = (img.Width + padding) / this.gridWidth + 1; int sqH = (img.Height + padding) / this.gridWidth + 1; int xOffsetImg = (sqW * gridWidth - img.Width) / 2; int yOffsetImg = (sqH * gridWidth - img.Height) / 2; OutlineShape shape = (ContourImage.DisplayProcessedImage ? contourImage.GetCoveredShape(gridWidth, wallWidth, xOffsetImg, yOffsetImg) : null); Rectangle rect; if (Maze.ReserveRectangle(sqW, sqH, 2, shape, out rect)) { // Remember the image data and location. It will be painted in PaintMaze(). int x = rect.X * gridWidth + xOffset + xOffsetImg; int y = rect.Y * gridWidth + yOffset + yOffsetImg; imageLocations.Add(new Rectangle(x, y, img.Width, img.Height)); return(true); } else { return(false); } }
private void showContourButton_Click(object sender, EventArgs e) { if (this.imageButton.Image == null) { return; } if (template == null) { template = this.imageButton.Image; } DateTime start = DateTime.Now; ContourImage ci = new ContourImage(template, null); ci.ProcessImage(); processed = ci.ProcessedImage; TimeSpan t = DateTime.Now - start; int ms = (int)t.TotalMilliseconds; this.timeLabel.Text = ms.ToString(); this.imageButton.Image = processed; }
/// <summary> /// Returns an image loaded from the given path and scaled to the known size range. /// </summary> /// <param name="imagePath"></param> /// <param name="r"></param> /// <returns></returns> private ContourImage LoadImage(string imagePath, Random r) { try { //Log.WriteLine("{ " + string.Format("LoadImage({0})", imagePath)); Image img = new Bitmap(imagePath); //Log.WriteLine("- LoadImage() scale image"); #region Scale img so that its larger dimension is between the desired min and max size. bool resize = false; if (img.Width > maxSize || img.Height > maxSize) { resize = true; } if (minSizeRequired && img.Width < minSize && img.Height < minSize) { resize = true; } if (resize) { int d = r.Next(minSize, maxSize); int h = img.Height, w = img.Width; if (h > w) { w = d * w / h; h = d; } else { h = d * h / w; w = d; } Bitmap tmpImg = new Bitmap(img, new Size(w, h)); img.Dispose(); // closes and unlocks the image file img = tmpImg; } #endregion //Log.WriteLine("- LoadImage() create contour image"); ContourImage result = new ContourImage(img, imagePath); //Log.WriteLine("} LoadImage()"); return(result); } catch (Exception ex) { string msg = string.Format("cannot load image [{0}]: {1}", imagePath, ex.Message); Log.WriteLine(msg, true); badImages[imagePath] = true; return(null); } }
/// <summary> /// Processes and enqueues the given image. /// </summary> /// <param name="img"></param> private void Enqueue(ContourImage img) { //Log.WriteLine("{ " + string.Format("Enqueue({0})", img.ToString())); // Wait while the queue contains enough items. queueFullSemaphore.WaitOne(); if (img != null) { img.ProcessImage(); } // Enqueue the processed image. //Log.WriteLine("- Enqueue() Enqueue"); queue.Enqueue(img); #region Add the image path to a separate list; save that list to the Registry if (queuedImagePaths != null) { lock (queuedImagePaths) { if (img.HasContour) { // True contour images should be loaded last. queuedImagePaths.Add(img.Path); } else { // Images without a contour should be loaded first. queuedImagePaths.Insert(0, img.Path); } if (queuedImagePaths.Count >= queueLength) { SaveImagePaths(); } } } #endregion queueEmptySemaphore.Release(); #if true /* Continue at the lower thread priority as soon as the first image has been loaded. * This assumes that a) we need only one image or b) we can easily load more images on demand. * This works fine if enough images can be loaded from the saved images list. * See LoadImagePaths(). */ ReduceThreadPriority(); #endif //Log.WriteLine("} Enqueue()"); }
/// <summary> /// Puts the given number of images into the this.images list. /// </summary> /// <param name="count"></param> public void PrepareImages(int count) { //Log.WriteLine("{ PrepareImages()"); images.Clear(); imageLocations.Clear(); bool haveBackgroundImage = this.MazePainter.PrepareBackgroundImage(); #region Determine number of images to be placed into reserved areas. Random r = Maze.Random; int n, nMin, nMax = count; if (haveBackgroundImage && r.Next(100) < 25) { nMax = 0; } if (nMax <= 2) { nMin = nMax; } else { nMin = nMax * 2 / 3; } if (nMax > 0) { n = r.Next(nMin, nMax + 1); } else { n = 0; } #endregion for (int i = 0; i < n; i++) { ContourImage img = imageLoader.GetNext(r); if (img != null) { images.Add(img); } } this.hasPreparedImages = true; // even if images.Count = 0 //Log.WriteLine("} PrepareImages()"); }
/// <summary> /// Background thread: /// Fills the queue with images. /// </summary> private void LoadImages() { Random r = RandomFactory.CreateRandom(); #region Start with a few images, preferably without a contour. // The saved image paths are already ordered (see SaveImagePaths()). LoadAndEnqueue(r, true, LoadImagePaths()); if (queue.Count >= queueLength) { ReduceThreadPriority(); } else { LoadAndEnqueue(r, false, FindImages(imageFolder, queueLength + 1, true, r)); } #endregion #region Continuously load more images, keeping the queue full. while (true) { int loadedImagesCount = 0; foreach (string imagePath in FindImages(imageFolder, 100, false, r)) { ContourImage img = LoadImage(imagePath, r); if (img == null) { continue; } Enqueue(img); ++loadedImagesCount; } // If no image was loaded successfully, enqueue a null value. if (loadedImagesCount == 0) { Enqueue(null); } } #endregion }
/// <summary> /// Reserves an area for each of the prepared images (as found in this.images). /// If no free area is found for an image, it is discarded. /// </summary> public void ReserveAreaForImages() { if (this.HasPreparedImages) { for (int i = 0; i < images.Count; i++) { ContourImage img = images[i]; if (!AddImage(img)) { images.RemoveAt(i); i--; } } } this.hasPreparedImages = false; }
public void IL_GetNextTest_01() { string testObject = "GetNext"; int minSize = 300; int maxSize = 500; string imageFolder = RegisteredOptions.GetStringSetting(RegisteredOptions.OPT_IMAGE_FOLDER); int queueLength = 4; ImageLoader target = new ImageLoader(minSize, maxSize, false, imageFolder, queueLength, "TEST"); for (int i = 0; i < 20; i++) { ContourImage img = target.GetNext(null); Assert.AreNotEqual(null, img, testObject + "returned null"); } }
private ContourImage Dequeue() { //Log.WriteLine("{ Dequeue()"); queueEmptySemaphore.WaitOne(); //Log.WriteLine("- Dequeue() Dequeue"); ContourImage result = queue.Dequeue() as ContourImage; if (queuedImagePaths != null) { lock (queuedImagePaths) { queuedImagePaths.Remove(result.Path); } } queueFullSemaphore.Release(); //Log.WriteLine("} Dequeue()"); return(result); }
public Mat DrawAllCellContourBoundingBoxes() { var matToReturn = ContourImage.CreateNewMatLikeThis(); var boxVecOfVectorPoint = new VectorOfVectorOfPointF(); foreach (var contour in Contours.ToArrayOfArray()) { var tempVector = new VectorOfPoint(contour); var tempRect = CvInvoke.MinAreaRect(tempVector); var box = CvInvoke.BoxPoints(tempRect); var boxVec = new VectorOfPointF(box); boxVecOfVectorPoint.Push(boxVec); } var convertedVectorOfVectorPoint = boxVecOfVectorPoint.ConvertToVectorOfPoint(); CvInvoke.DrawContours(matToReturn, convertedVectorOfVectorPoint, -1, new MCvScalar(0, 255, 0, 255), 2); return(matToReturn); }
//saját public void Process() { //TODO ezeknek a refeknek az elhagyása ProcessedImage = null; ContourImage = null; Contours.Clear(); ImgProcessor.Process(); OgImage = ImgProcessor.OgImageMat; ProcessedImage = ImgProcessor.ImageMat; ContourImage = ImgProcessor.ContourImageMat; Contours.Push(ImgProcessor.ContoursToReturn); Boxes.Push(ImgProcessor.AngledBoundingBoxesToReturn); DetectedCellCount = Contours.Size; MainWindow.ImageProcessorExaminer.AddImage(OgImage.CreateNewHardCopyFromMat(), "ImageHandler_OgImage"); MainWindow.ImageProcessorExaminer.AddImage(Image.CreateNewHardCopyFromMat(), "ImageHandler_Image"); MainWindow.ImageProcessorExaminer.AddImage(ProcessedImage.CreateNewHardCopyFromMat(), "ImageHandler_ProcessedImage"); MainWindow.ImageProcessorExaminer.AddImage(ContourImage.CreateNewHardCopyFromMat(), "ImageHandler_ContourImage"); ProcessOverlays(); }
/// <summary> /// Compares the given image's dimensions to the desired limits. /// Returns true if the image should be discarded. /// </summary> /// <param name="img">Image.</param> /// <param name="testMinSize">May be this.minSizeRequired</param> private bool ImageHasImproperSize(ContourImage img, bool testMinSize) { if (img == null) { return(false); } int h = img.DisplayedImage.Height; int w = img.DisplayedImage.Width; if (h > maxSize || w > maxSize) { return(true); } if (testMinSize && (h < minSize || w < minSize)) { return(true); } return(false); }
/// <summary> /// Paints the images into their reserved areas. /// </summary> /// <param name="g"></param> private void PaintImages(Graphics g) { Region clip = g.Clip; for (int i = 0; i < images.Count; i++) { ContourImage img = images[i]; if (img.HasContour) { // Set a clipping region around the image. Region r = img.BorderRegion.Clone(); r.Translate(imageLocations[i].X, imageLocations[i].Y); g.Clip = r; } else { // Paint a black border around the image, covering any background images. Rectangle border = imageLocations[i]; border.Inflate(2, 2); g.Clip = clip; g.FillRectangle(Brushes.Black, border); } g.DrawImage(img.DisplayedImage, imageLocations[i]); } // Restore previous clip region (infinite). g.Clip = clip; for (int i = 0; i < controlLocations.Count; i++) { // Paint a black border around the control, covering any background images. Rectangle border = controlLocations[i]; border.Inflate(2, 2); g.FillRectangle(Brushes.Black, border); } }
/// <summary> /// Loads and enqueues all images of the given list. /// </summary> /// <param name="imagePaths"></param> /// <param name="preserveOrder">When false, the list is reordered so that images without a contour that need not be processed come first.</param> /// <param name="r"></param> private void LoadAndEnqueue(Random r, bool preserveOrder, IEnumerable <string> imagePaths) { //Log.WriteLine("{ " + string.Format("LoadAndEnqueue({0})", imagePaths.GetType().ToString())); List <ContourImage> unprocessedImages = new List <ContourImage>(queueLength + 1); IEnumerator <string> e = imagePaths.GetEnumerator(); while (e.MoveNext()) { string imagePath = e.Current; ContourImage img = null; if (imagePath != null) { img = LoadImage(imagePath, r); } if (img == null) { continue; } else if (!preserveOrder && img.HasContour) { //Log.WriteLine("- LoadAndEnqueue() save contour image: " + img.ToString()); unprocessedImages.Add(img); } else { Enqueue(img); } } foreach (ContourImage img in unprocessedImages) { Enqueue(img); } //Log.WriteLine("} LoadAndEnqueue()"); }
public void CI_InsertPairTest_08_ThickLines() { string testObject = "ContourImage.ScanObject"; Color backgroundColor = Color.White; Color foregroundColor = Color.Black; Brush fgBrush = new SolidBrush(foregroundColor); Pen fgPen = new Pen(fgBrush, 8); fgPen.StartCap = fgPen.EndCap = System.Drawing.Drawing2D.LineCap.Round; // When painting into the image, leave an outer frame of 16 pixels free. // Only use the range 50..250. int width = 300, height = 300; Bitmap image = new Bitmap(width, height); Graphics g = Graphics.FromImage(image); int contourDist = SWA_Ariadne_Gui_Mazes_ContourImageAccessor.ContourDistance; int blurDist = SWA_Ariadne_Gui_Mazes_ContourImageAccessor.BlurDistanceMax; SWA_Ariadne_Gui_Mazes_ContourImageAccessor.PrepareInfluenceRegions(contourDist + blurDist); int[,] alpha = new int[width, height]; List <int>[] objectXs, contourXs, borderXs; SWA_Ariadne_Gui_Mazes_ContourImageAccessor.InitializeScanLines(width, height, out objectXs, out contourXs, out borderXs); #region Create a complicated pattern of border scan lines. Point[] points = { new Point(50, 50), new Point(250, 250), new Point(200, 100), new Point(100, 200), }; g.FillRectangle(new SolidBrush(backgroundColor), 0, 0, image.Width, image.Height); for (int i = 0, j = i + 1; j < points.Length; i++, j++) { g.DrawLine(fgPen, points[i], points[j]); } #endregion ContourImage target = new ContourImage(image); SWA_Ariadne_Gui_Mazes_ContourImageAccessor accessor = new SWA_Ariadne_Gui_Mazes_ContourImageAccessor(target); accessor.image = image; int y0 = image.Height / 2; #region Find the leftmost object pixel on the scan line at y0. int x0 = 0; int fuzziness = (int)(0.1F * SWA_Ariadne_Gui_Mazes_ContourImageAccessor.MaxColorDistance); while (accessor.ColorDistance(image.GetPixel(x0, y0)) <= fuzziness) { x0++; } #endregion accessor.ScanObject(x0, y0, fuzziness, alpha, objectXs, contourXs, borderXs); TestBorderScanlines(testObject, borderXs); }
private static void TestScan(string testObject, Bitmap image, Color backgroundColor, int y0, int maxContourScanRegions) { testObject += " @ " + y0.ToString(); int fuzziness = (int)(0.1F * SWA_Ariadne_Gui_Mazes_ContourImageAccessor.MaxColorDistance); int frameWidth = SWA_Ariadne_Gui_Mazes_ContourImageAccessor.ContourDistance; SWA_Ariadne_Gui_Mazes_ContourImageAccessor.PrepareInfluenceRegions(frameWidth); ContourImage target = new ContourImage(image); SWA_Ariadne_Gui_Mazes_ContourImageAccessor accessor = new SWA_Ariadne_Gui_Mazes_ContourImageAccessor(target); accessor.image = image; #region Find the leftmost object pixel on the scan line at y0. int x0 = 0; while (accessor.ColorDistance(image.GetPixel(x0, y0)) <= fuzziness) { x0++; if (x0 >= image.Width) { return; } } #endregion #region Prepare required data structures. int width = image.Width, height = image.Height; int[,] alpha = new int[width, height]; List <int>[] objectXs, contourXs, borderXs; SWA_Ariadne_Gui_Mazes_ContourImageAccessor.InitializeScanLines(width, height, out objectXs, out contourXs, out borderXs); #endregion accessor.ScanObject(x0, y0, fuzziness, alpha, objectXs, contourXs, borderXs); #region Test if the object map is well formed. for (int i = 0; i < height; i++) { int nEntries = objectXs[i].Count; int m = nEntries % 2; Assert.AreEqual(1, m, testObject + string.Format(" - objectXs[{0}] must be an odd number: {1}", i, nEntries)); int nRegions = (nEntries - 1) / 2; Assert.IsTrue(nRegions <= maxContourScanRegions, testObject + string.Format(" - objectXs[{0}] regions = {1} must be less than {2}", i, nRegions, maxContourScanRegions)); } #endregion #region Test if the object map is complete. int imageArea = ImageArea(image, backgroundColor, (float)fuzziness / SWA_Ariadne_Gui_Mazes_ContourImageAccessor.MaxColorDistance); int objectArea = ObjectArea(objectXs); Assert.AreEqual(imageArea, objectArea, testObject + string.Format(" - object area and image area must be equal")); #endregion // Test if the contour map is well formed. TestBorderScanlines(testObject + " - contourXs", contourXs); // Test if the border map is well formed. TestBorderScanlines(testObject + " - borderXs", borderXs); }