/// <summary> /// /// </summary> /// <param name="Graphic"></param> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> internal ImageSection Recognize(ref ImageSection Graphic, int x, int y) { if (mVisualReport != null && mVisDisplay != null) { Master.sInvokable.Invoke(new Action(mVisDisplay.Show)); mVisualReport.Start(); } //We've got something, so now scan to find adjacent pixels. //Step 1: diagonal, down-right to get a general square shape //Step 2: right from each of diag's to fill right side //Step 3: down from each of diag's to fill bottom //Step 4: around in circles around that, to pick up stragglers Func<Color, Point, bool> CheckAdd = (c, p) => { if (this.ValidPixel(c)) { this.AddPixel(p, c); return true; } return false; }; int DiagMove = 0; while (CheckAdd(Graphic.GetPixel(x + DiagMove, y + DiagMove), new Point(x + DiagMove, y + DiagMove))) DiagMove++; //This should work on the first pixel, but change to do{}while if it doesn't int SubY, SubX; for (SubY = 0; SubY <= DiagMove; SubY++) //See the comment on the next line for (SubX = SubY + 1; SubX <= DiagMove - SubY && CheckAdd(Graphic.GetPixel(x + SubX, y + SubY), new Point(x + SubX, y + SubY)); SubX++) ; //Note the semicolon: the logical check does all the needed activity //This is just a perpendicular copy of above for (SubX = 0; SubX <= DiagMove; SubX++) for (SubY = SubX + 1; SubY <= DiagMove - SubX && CheckAdd(Graphic.GetPixel(x + SubX, y + SubY), new Point(x + SubX, y + SubY)); SubY++) ; //Note the semicolon: the logical check does all the needed activity //Now the tricky part, the round about //I'm going to ignore diagonals //For each pixel that's been added so far, check all adjacent pixels not checked yet and checkadd them //Add the successes to another list and foreach through that one as well. Repeat. { //These parenthesis are just to keep these large array variables from lingering too long List<Point> LatestAdds = new List<Point>(), AllTested = new List<Point>(), Failed = new List<Point>(); ; LatestAdds.AddRange(this.SelectedPixels()); Point[] CurrentTesting; do { AllTested.AddRange(LatestAdds); CurrentTesting = LatestAdds.ToArray(); LatestAdds = new List<Point>(); Point Temp; foreach (Point p in CurrentTesting) { Temp = new Point(p.X - 1, p.Y); if (Temp.X >= 0 && !LatestAdds.Contains(Temp) && !Failed.Contains(Temp) && !AllTested.Contains(Temp)) { if (CheckAdd(Graphic.GetPixel(Temp.X, Temp.Y), Temp)) LatestAdds.Add(Temp); else Failed.Add(Temp); } Temp = new Point(p.X, p.Y - 1); if (Temp.Y >= 0 && !LatestAdds.Contains(Temp) && !Failed.Contains(Temp) && !AllTested.Contains(Temp)) { if (CheckAdd(Graphic.GetPixel(Temp.X, Temp.Y), Temp)) LatestAdds.Add(Temp); else Failed.Add(Temp); } Temp = new Point(p.X + 1, p.Y); if (Temp.X < Graphic.Size.Width && !LatestAdds.Contains(Temp) && !Failed.Contains(Temp) && !AllTested.Contains(Temp)) { if (CheckAdd(Graphic.GetPixel(Temp.X, Temp.Y), Temp)) LatestAdds.Add(Temp); else Failed.Add(Temp); } Temp = new Point(p.X, p.Y + 1); if (Temp.Y < Graphic.Size.Height && !LatestAdds.Contains(Temp) && !Failed.Contains(Temp) && !AllTested.Contains(Temp)) { if (CheckAdd(Graphic.GetPixel(Temp.X, Temp.Y), Temp)) LatestAdds.Add(Temp); else Failed.Add(Temp); } } } while (LatestAdds.Count > 0); } // //Almost done // if (mVisualReport != null && mVisDisplay != null) { mVisualReport.Stop(); Master.sInvokable.Invoke(new Action(mVisDisplay.CloseSafe)); } if (this.mAddedPixels.Count <= Master.sMaster.MinMargin) return null; this.SubtractFrom(ref Graphic); #if OUTPUTEACH System.IO.FileStream fs = Master.sMaster.GenerateFile("ImgSec " + this.mSize.X + " " + this.mSize.Y + " " + DateTime.Now.ToFileTime() + ".bmp"); Master.sMaster.OriginalPixels(mAddedPixels.ToArray()).Save(fs, System.Drawing.Imaging.ImageFormat.Bmp); fs.Flush(); fs.Close(); fs.Dispose(); #endif return this.Generate(); // // ALL DONE! One ImageSection down // }
/// <summary> /// /// </summary> /// <param name="ImgSec"></param> /// <param name="ColorForgive"></param> /// <param name="ColorDetail"></param> /// <param name="MinMargin"></param> /// <returns></returns> internal static Child[] ScanImageSection(ImageSection ImgSec, int ColorForgive, int ColorDetail, int MinMargin, Child Parent = null) { #if GUIOUTPUT mScannedPx = 0; int MaxSize = ImgSec.Width * ImgSec.Height; frmImgSecDisplay DisplayOut = null; //DisplayOut.Show(); //Master.sInvokable.Invoke(Master.sAddable, null => {return new frmImgSecDisplay();}, DisplayOut); MakeForm NewDisp = delegate() { return new frmImgSecDisplay(); }; AssignForm AssDisp = delegate(System.Windows.Forms.Form ToAssign) { DisplayOut = (frmImgSecDisplay)ToAssign; }; Master.sInvokable.Invoke(Master.sAddable, new object[] { NewDisp, AssDisp }); #endif //Break the image into ImageSections List<ImageSection> Sections = new List<ImageSection>(); ImageSectionFactory Factory; for (int y = 0; y < ImgSec.Height; y++) { for (int x = 0; x < ImgSec.Width; x++) { if (ImgSec.GetPixel(x, y).A == byte.MaxValue) { Factory = new ImageSectionFactory(new Point(x, y), ColorForgive, ColorDetail #if GUIOUTPUT ,DisplayOut #endif ); Sections.Add(Factory.Recognize(ref ImgSec, x, y)); #if GUIOUTPUT UpdateDisplay((mScannedPx += Factory.SelectedPixels().Count()), MaxSize, 0); #endif } } } Sections.RemoveAll(imsec => imsec == null); //Figure out if it just selected the whole thing. If so, cancel the scan if (Sections.Count == 1 && Sections[0].Size == ImgSec.Size) return new Child[0]; //Figure out which ones of those are too small and should be discounted for (int remove = 0; remove < Sections.Count; remove++) { if (Sections[remove].PixelsUsed().Length <= MinMargin) Sections.RemoveAt(remove); } Sections.TrimExcess(); // Once that's done, turn the remaining Image Sections into Children Child[] Children = new Child[Sections.Count]; #if MULTITHREAD Task<Child>[] Tasks = new Task<Child>[Sections.Count]; #endif for (int i = 0; i < Sections.Count; i++) { #if MULTITHREAD Tasks[i] = new Task<Child>(s => Child.FromSection((Child)((object[])s)[0], (ImageSection)((object[])s)[1]), new object[]{Parent, Sections[i]}); Tasks[i].Start(); #else Children[i] = Child.FromSection(Parent, Sections[i]); #endif #if GUIOUTPUT UpdateDisplay(MaxSize, MaxSize, 1); #endif } #if MULTITHREAD try { while (Tasks.Any(t => !t.IsCompleted)) Tasks.First(t => !t.IsCompleted).Wait(); } catch (NullReferenceException) { } for (int i = 0; i < Tasks.Length; i++) { Children[i] = Tasks[i].Result; } #endif return Children; }