Example #1
0
        internal static new double ApproxFit(ImageSection ImgSec)
        {
            //double Fit = 0d;
            //return Fit;

            //Just return circle from top to bottom, left to right

            return ImgSec.PixelsUsed().Length / (ImgSec.Width / 2 * ImgSec.Height / 2 * Math.PI);
        }
Example #2
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ImgSec"></param>
        /// <param name="Vertices"></param>
        /// <returns></returns>
        internal Point[] HardFit(ImageSection ImgSec)
        {
            List<Point> Corners = GenerateCorners(ImgSec);

            //Find the Centroid
            //Func<Point, Point, Point, double> GetAngle = (a, b, c) => { };
            //http://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
            //Point Centroid;
            //{
            //    int ASigma = 0, XSigma = 0, YSigma = 0, ASigAdd;
            //    for (int i = 0; i < Outsides.Count - 1; i++)
            //    {
            //        ASigAdd = Outsides[i].X * Outsides[i + 1].Y - Outsides[i + 1].X * Outsides[i].Y;
            //        ASigma += ASigAdd;
            //        XSigma += (Outsides[i].X + Outsides[i + 1].X) * ASigAdd;
            //        YSigma += (Outsides[i].Y + Outsides[i + 1].Y) * ASigAdd;
            //    }
            //    double A = 1d / 2d * ASigma;
            //    double
            //        X = 1d / (6d * A) * XSigma,
            //        Y = 1d / (6d * A) * YSigma;
            //    Centroid = new Point((int)X, (int)Y);
            //}

            //Ensure that the whole thing is convex
            //{
            //    Func<Point, Point, Point, bool> IsConcave = (a, b, c) => GetAngle(a, b, Centroid) + GetAngle(Centroid, b, c) > 180d;

            //    for (int k = 0; k < Corners.Count; k++)
            //        if (IsConcave(Corners[k], Corners[(k + 1) % Corners.Count], Corners[(k + 2) % Corners.Count]))
            //        { Corners.RemoveAt((k + 1) % Corners.Count); k--; }
            //}
            while (Corners.Count < mVerticeCount && mVerticeCount != -1)
                Corners.Insert(0, Corners[0]);

            if (Corners.Count > mVerticeCount && mVerticeCount != -1)
            {
                //Insert points as new Point[]{Base1, Base2, Extender2, Extender1}
                List<Point[]> TrianglePossibilities;
                List<double> TriangleScores;

                //Figure out, based on ASA, the area of a triangle; note that the angles are in radians
                //in<Angle1, Side,   Angle2, output>
                Func<double, double, double, double> AreaOfTriangle = (a1, s, a2) => s * s * Math.Sin(a1) * Math.Sin(a2) / Math.Sin(Math.PI - (a1 + a2));
                //a = s*sin(A)/sin(180-(A+B))
                //area = a*s*sin(B)

                //Func<Point, Point, double> Hyp = (p1,p2) => Math.Sqrt(Math.Pow(p1.X - p2.X,2) + Math.Pow(p1.Y - p2.Y,2));
                //Func<Point, Point, Point, double> GetAngle =
                //    (r1, v, r2) =>
                //        Math.Acos((Math.Pow(Hyp(v, r1), 2) + Math.Pow(Hyp(v, r2), 2) + Math.Pow(Hyp(r1, r2), 2)) / (2 * Hyp(v, r1) * Hyp(v, r2)));

                double TempArea, TempBase;
                //while (Corners.Count > Vertices)
                {
                    TrianglePossibilities = new List<Point[]>();
                    TriangleScores = new List<double>();
                    //int b1, b2, e1, e2;
                    for (int i = 0; i < Corners.Count; i++)
                    {
                        //Compare using 1&2, repetition ensures that all possibilities get considered
                        TrianglePossibilities.Add(new Point[] { Corners[(i + 3) % Corners.Count], Corners[i], Corners[(i + 1) % Corners.Count], Corners[(i + 2) % Corners.Count] });
                        //You have to use this formula for area of the triangle, because the peak of the triangle is an unknown point beyond the polygon
                        //Save the efficiency of doing each of these by taking the area * altitude of the full triangle and subtracting the area of the quadrilateral
                        TriangleScores.Add(
                            (TempArea = AreaOfTriangle(
                                GetAngle(Corners[i], Corners[(i + 3) % Corners.Count], Corners[(i + 2) % Corners.Count]),
                                TempBase = Hyp(Corners[(i + 3) % Corners.Count], Corners[i]),
                                GetAngle(Corners[(i + 3) % Corners.Count], Corners[i], Corners[(i + 1) % Corners.Count])))
                                * GetAltitude(TempBase, TempArea)
                                - Area(Corners[i], Corners[(i + 1) % Corners.Count], Corners[(i + 2) % Corners.Count], Corners[(i + 3) % Corners.Count]));
                        //Apologies for the complexity. Note the repetition of Corners[(i + k) % Corners.Count]
                        //k=1=e1, k=2=e2, k=3=b1, k=0=b2
                        //This has to be this way to prevent impossible triangles
                        //I've already checked that the shape is convex, so \_/ is only guaranteed to work as \/
                    }

                    //Based off of y-y2=m(x-x2)
                    //a=b1=p[3], b=b2=p[0], c=e1=p[2], d=e2=p[1], e=a.y, f=b.y, g=c.y, h=d.y
                    //using wolframalpha to solve
                    //x = -(-(c*(e-g))/(a-c)+(d*(f-h))/(b-d)+g-h)/((e-g)/(a-c)-(f-h)/(b-d))
                    //y = -(-a*f*g+a*g*h+b*e*h-b*g*h+c*e*f-c*e*h-d*e*f+d*f*g)/(a*f-a*h-b*e+b*g-c*f+c*h+d*e-d*g)
                    Func<Point[], Point> CalcThirdPoint = p => new Point(
                        -(-(p[2].X * (p[3].Y - p[2].Y)) / (p[3].X - p[2].X) + (p[1].X * (p[0].Y - p[1].Y)) / (p[0].X - p[1].X) + p[2].Y - p[1].Y) / ((p[3].Y - p[2].Y) / (p[3].X - p[2].X) - (p[0].Y - p[1].Y) / (p[0].X - p[1].X)),
                        -(-p[3].X * p[0].Y * p[2].Y + p[3].X * p[2].Y * p[1].Y + p[0].X * p[3].Y * p[1].Y - p[0].X * p[2].Y * p[1].Y + p[2].X * p[3].Y * p[0].Y - p[2].X * p[3].Y * p[1].Y - p[1].X * p[3].Y * p[0].Y + p[1].X * p[0].Y * p[2].Y) / (p[3].X * p[0].Y - p[3].X * p[1].Y - p[0].X * p[3].Y + p[0].X * p[2].Y - p[2].X * p[0].Y + p[2].X * p[1].Y + p[1].X * p[3].Y - p[1].X * p[2].Y));
                    List<int> indices = new List<int>();
                    int index;
                    while (Corners.Count > mVerticeCount)
                    {
                        index = TriangleScores.IndexOf(TriangleScores.Min());
                        Corners.Insert(Corners.IndexOf(TrianglePossibilities[index][2]), CalcThirdPoint(TrianglePossibilities[index]));
                        Corners.Remove(TrianglePossibilities[index][2]);
                        Corners.Remove(TrianglePossibilities[index][3]);
                        TrianglePossibilities.RemoveAt(index);
                        TriangleScores.RemoveAt(index);
                        //Also remove 2 surrounding possibilities, since their estimates and required points no longer exist
                        if (index - 1 >= 0)
                        {
                            TrianglePossibilities.RemoveAt(index - 1);
                            TriangleScores.RemoveAt(index - 1);
                        }
                        if (index + 1 < TrianglePossibilities.Count)
                        {
                            TrianglePossibilities.RemoveAt(index + 1);
                            TriangleScores.RemoveAt(index + 1);
                        }
                    }
                }
            }
            return Corners.ToArray();

            throw new NotImplementedException();
        }
Example #3
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="ImgSec"></param>
 /// <returns></returns>
 internal static new double ApproxFit(ImageSection ImgSec)
 {
     return ImgSec.PixelsUsed().Length / Area(GenerateCorners(ImgSec).ToArray());
 }
Example #4
0
 protected Polygon(Child Parent, ImageSection ImgSec, int VertexCount)
     : base(Parent, ImgSec)
 {
     if (VertexCount <= 2) throw new InvalidOperationException("Vertices count must be greater than 2");
     mVerticeCount = VertexCount;
 }
Example #5
0
 public Rectangle(Child Parent, ImageSection ImgSec)
     : base(Parent, ImgSec, 4)
 {
 }
Example #6
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ImgSec"></param>
        /// <returns></returns>
        private static List<Point> GenerateCorners(ImageSection ImgSec)
        {
            //Find all points that are clear on at least two sides of any other selected pixels
            List<Point> Outsides;
            {
                Point[] Pts = ImgSec.PixelsUsed();
                Outsides = new List<Point>();
                foreach (Point p in Pts)
                {
                    int Bordering = 0;
                    foreach (Point q in Pts)
                    {
                        //It only counts as bordering if they are adjacent, not diagonal
                        if (Math.Abs(p.X - q.X) == 1 ^ Math.Abs(p.Y - q.Y) == 1) Bordering++;
                        if (Bordering > 3) break;
                    }
                    if (Bordering <= 3) Outsides.Add(p);
                }
            }

            List<Point> Corners = new List<Point>();

            //Order points around the shape in a roughly circular shape
            //This solution also ensure that the resulting shape is convex
            //I'll take a scan approach
            //Pick a point that you know is on the outside, so any one with min or max x or y
            //I'm going to find min y, then min x for that
            //Then do a scan using that and (-1,-1) to find the point with the SMALLEST angle
            //Guaranteed, those two points are part of the convex containing polygon
            //Using those two points, scan around
            //Scan every other point and its angle with the current two
            //The point with the greatest angle is the next convex vertex
            //Continue until you reach the original point
            {
                Point a, b = new Point(-1, -1), c = new Point(-1, -1);
                double angle = Math.PI, temp;
                //int MinY = Outsides.Min(p => p.Y);
                //MinY = 0;
                a = new Point(Outsides.Min(p => (p.Y == 0 ? p.X : ImgSec.Width)), 0);
                foreach (Point p in Outsides)
                {
                    if (!p.Equals(a))
                        if ((temp = GetAngle(new Point(-1, -1), a, p)) < angle)
                        {
                            b = p;
                            angle = temp;
                        }
                }
                Corners.Add(a);
                Corners.Add(b);
                do
                {
                    angle = 0d;
                    foreach (Point q in Outsides)
                        if (!Corners.Contains(q))
                            if ((temp = GetAngle(Corners[Corners.Count - 2], Corners[Corners.Count - 1], q)) > angle)
                            {
                                c = q;
                                angle = temp;
                            }
                    if (Corners.Contains(c)) break;
                    else Corners.Add(c);
                } while (Corners.Count < Outsides.Count);
            }

            return Corners;
        }
Example #7
0
        /// <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
            //
        }
Example #8
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="Source"></param>
 internal void SubtractFrom(ref ImageSection Source)
 {
     System.Drawing.Rectangle SourceFill = new System.Drawing.Rectangle(Source.Location, Source.Size);
     foreach (Point p in mAddedPixels)
         if (SourceFill.Contains(p))
             Source.Alpha.SetPixel(p.X - Source.Location.X, p.Y - Source.Location.Y, Constants.ALPHA_EMPTY);
 }
Example #9
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="Base"></param>
 /// <returns></returns>
 internal ImageSection OriginalPixels(ImageSection Base)
 {
     Bitmap Clip = new Bitmap(Base.Size.Width, Base.Size.Height);
     Graphics.FromImage(Clip).DrawImageUnscaledAndClipped(mBaseImage, new System.Drawing.Rectangle(Base.Location, Base.Size));
     return new ImageSection(Base.Location, Clip, Base.Alpha, Color.Empty);
 }
Example #10
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="Count"></param>
        public void GenerateChildren()
        {
            //int Count = 0;
            #if GUIOUTPUT
            double Prog = 0d;
            ProgressDisplay Disp = new ProgressDisplay();
            System.Threading.Tasks.Task t = new System.Threading.Tasks.Task(new Action(Disp.Show));
            t.Start();
            #endif
            //Reduce the image into simplicity
            mLeftover = (Bitmap)mBaseImage.Clone();
            ImgManip Man = new ImgManip(ref mLeftover);
            Man.ReduceColors(mColorDetail);
            mScale = Man.ReduceGrid(mResDetail);
            mLeftover = Man.GetImage;
            Bitmap Clear = new Bitmap(mLeftover.Width, mLeftover.Height);
            Graphics.FromImage(Clear).Clear(Constants.ALPHA_FULL);
            ImageSection Img = new ImageSection(new Point(0, 0), mLeftover, Clear, Color.Empty);

            mChildren = Child.ScanImageSection(Img, mColorForgive, mColorDetail, mMinMargin);
            #if GUIOUTPUT
            Prog = 0.5d;
            #endif
            //Count += mChildren.Length;
            double Scale;
            foreach (Child c in mChildren)
            {
                Scale = Constants.GetScale(((ImageSection)c).Size, this.Size);
                c.GenerateSubChildren((int)(Scale * mColorForgive), (int)(Scale * mColorDetail), mMinMargin);
            #if GUIOUTPUT
                Prog += 1d / (double)mChildren.Count() * 0.5d;
            #endif
            }
            #if GUIOUTPUT
            Disp.Close();
            Disp.Dispose();
            t.Dispose();
            #endif
        }
Example #11
0
 public Triangle(Child Parent, ImageSection ImgSec)
     : base(Parent, ImgSec, 3)
 {
 }
Example #12
0
 public Ellipse(Child Parent, ImageSection ImgSec)
     : base(Parent, ImgSec)
 {
     this.HardFit();
 }
Example #13
0
        { return 0d; } //NEEDS OVERRIDE using new keyword

        internal Child(Child Parent, ImageSection Img)
        {
            mImgSec = Img;
            mParent = Parent;
        }
Example #14
0
 /// <summary>
 /// 0 means absolutely no selected pixels can fit into this shape, 1 means all and only selected pixels can fit into this shape. Selection is calculated by Constants.CalcFit(Selected, Unselected)
 /// </summary>
 /// <param name="Img"></param>
 /// <returns></returns>
 protected static double ApproxFit(ImageSection Img)
 { return 0d; } //NEEDS OVERRIDE using new keyword
Example #15
0
        /// <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;
        }
Example #16
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="Parent"></param>
        /// <param name="ImgSec"></param>
        /// <returns></returns>
        internal static Child FromSection(Child Parent, ImageSection ImgSec)
        {
            Func<ImageSection, double> BestFitter = null;
            double BestFit = 0d;
            double temp;
            sRegisteredChecks.ForEach(f => { if (BestFit < (temp = f(ImgSec))) { BestFitter = f; BestFit = temp; } });

            if (BestFit == 0d) throw new InvalidOperationException("No shapes are registered, or they are not matching any pixels.");

            return sRegisteredConstructs[sRegisteredChecks.IndexOf(BestFitter)](Parent, ImgSec);
        }