Example #1
0
        /// <summary>
        /// Scans a line on the image for line segments using a hysteresis connected component algorithm.
        /// </summary>
        /// <param name="Input">Input data.</param>
        /// <param name="AnalyzeMask">Mask for marking visited pixels.</param>
        /// <param name="Height">Data height.</param>
        /// <param name="Width">Data width.</param>
        /// <param name="Rho">Distance from origin to line.</param>
        /// <param name="Theta">Line angle.</param>
        /// <param name="HighTh">Upper hysteresis threshold.</param>
        /// <param name="LowTh">Lower hysteresis threshold.</param>
        /// <param name="MaxIgnore">Maximum interblob distance.</param>
        /// <param name="ScanWidth">Width of the scanned area.</param>
        /// <param name="OX">Image data origin X coordinate.</param>
        /// <param name="OY">Image data origin Y coordinate.</param>
        /// <returns>A list of line segment detections.</returns>
        internal static List <LineDetection> AnalyzeLine(double[,] Input, bool[,] AnalyzeMask, int Height, int Width, double Rho, double Theta, double HighTh, double LowTh, int MaxIgnore, int ScanWidth, int OX, int OY)
        {
            /* Unit vector in the direction of the line */
            Vector LineVector = new Vector()
            {
                X = Cos(Theta), Y = Sin(Theta)
            };
            /* Origin of the line */
            Vector LineOrigin = new Vector()
            {
                X = -Rho *Sin(Theta), Y = Rho * Cos(Theta)
            };
            /* Unit vector perpendicular to the line */
            Vector LONormal = new Vector()
            {
                X = -Sin(Theta), Y = Cos(Theta)
            };

            /* Compute the intersections with the bounding box */
            Vector LeftIntersect;
            double LDist;

            if (!LineIntersection.IntersectLeft(LineOrigin, LineVector, Width, Height, out LeftIntersect, out LDist))
            {
                return(null);
            }

            Vector RightIntersect;
            double RDist;

            if (!LineIntersection.IntersectRight(LineOrigin, LineVector, Width, Height, out RightIntersect, out RDist))
            {
                return(null);
            }

            /* Sort the intersections */
            double Start = Min(LDist, RDist);
            double End = Max(LDist, RDist);
            Vector StVec, EVec;

            if (Start == LDist && End == RDist)
            {
                StVec = LeftIntersect; EVec = RightIntersect;
            }
            else if (Start == RDist && End == LDist)
            {
                StVec = RightIntersect; EVec = LeftIntersect;
            }
            else
            {
                throw new ApplicationException("Geometry error.");
            }

            /* Scan line for blobs */
            int    k;
            int    N  = (int)(End - Start);
            Vector pt = StVec;

            List <Vector>        LineIntervals = new List <Vector>();
            List <DetectionBlob> Blobs         = new List <DetectionBlob>();

            for (k = 0; k < N; k++, pt.Increment(LineVector))
            {
                int    l;
                Vector vl = pt;
                for (l = -ScanWidth; l < ScanWidth; l++, vl.Increment(LONormal))
                {
                    int X = (int)Round(vl.X);
                    int Y = (int)Round(vl.Y);
                    if (X < 0 || X >= Width)
                    {
                        continue;
                    }
                    if (Y < 0 || Y >= Height)
                    {
                        continue;
                    }
                    if (AnalyzeMask[Y, X])
                    {
                        continue;
                    }
                    double Val = Input[Y, X];

                    if (Val > HighTh)
                    {
                        DetectionBlob db = BitmapFill(Input, new IntPoint()
                        {
                            X = X, Y = Y
                        }, AnalyzeMask, LowTh, Theta);
                        LineIntervals.Add(new Vector()
                        {
                            X = db.LineStart, Y = db.LineEnd
                        });
                        Blobs.Add(db);
                    }
                }
            }

            /* Merge blobs into line segments */
            List <DetectionSegment> FoundSegments = new List <DetectionSegment>();
            DetectionSegment        cseg          = default(DetectionSegment); /* Current segment */

            for (k = 0; k < LineIntervals.Count; k++)
            {
                if (cseg.Blobs != null)
                {
                    /* If still within threshold of current segment */
                    if (Min(LineIntervals[k].X, LineIntervals[k].Y) < cseg.End + MaxIgnore)
                    {
                        cseg.Blobs.Add(Blobs[k]);
                        cseg.End = Max(cseg.End, Max(LineIntervals[k].Y, LineIntervals[k].X));
                        continue;
                    }
                    else
                    {
                        FoundSegments.Add(cseg); cseg = default(DetectionSegment);
                    }
                }
                /* Create new current segment */
                cseg.Blobs = new List <DetectionBlob>();
                cseg.Angle = Theta;
                cseg.Blobs.Add(Blobs[k]);
                cseg.Start = Min(LineIntervals[k].X, LineIntervals[k].Y);
                cseg.End   = Max(LineIntervals[k].Y, LineIntervals[k].X);
            }
            if (cseg.Blobs != null)
            {
                FoundSegments.Add(cseg);
            }
            List <LineDetection> Detections = FoundSegments.Select((x) => MergeBlobs(x, Input, OX, OY)).ToList();

            return(Detections);
        }
Example #2
0
        /// <summary>
        /// Gets the connected component starting from a point on an image.
        /// </summary>
        /// <param name="Input">Input Image.</param>
        /// <param name="StartPoint">Starting point.</param>
        /// <param name="Mask">Already processed components mask.</param>
        /// <param name="LowThreshold">Threshold for component discrimination.</param>
        /// <param name="Angle">Angle of the line; used for distance projections.</param>
        /// <returns>The connected component blob.</returns>
        static DetectionBlob BitmapFill(double[,] Input, IntPoint StartPoint, bool[,] Mask, double LowThreshold, double Angle)
        {
            Queue <IntPoint> PointQ = new Queue <IntPoint>();

            PointQ.Enqueue(StartPoint);
            List <IntPoint> DiscoveredPoints = new List <IntPoint>();

            double LineMin = double.MaxValue, LineMax = double.MinValue;

            while (PointQ.Count > 0)
            {
                IntPoint pt = PointQ.Dequeue();
                if (pt.X < 0 || pt.X >= Mask.GetLength(1))
                {
                    continue;
                }
                if (pt.Y < 0 || pt.Y >= Mask.GetLength(0))
                {
                    continue;
                }
                if (Mask[pt.Y, pt.X])
                {
                    continue;
                }
                double Val    = Input[pt.Y, pt.X];
                double MinMax = pt.X * Cos(Angle) + pt.Y * Sin(Angle);
                if (MinMax < LineMin)
                {
                    LineMin = MinMax;
                }
                if (MinMax > LineMax)
                {
                    LineMax = MinMax;
                }
                if (Val > LowThreshold)
                {
                    Mask[pt.Y, pt.X] = true;

                    DiscoveredPoints.Add(pt);
                    PointQ.Enqueue(new IntPoint()
                    {
                        X = pt.X - 1, Y = pt.Y
                    });
                    PointQ.Enqueue(new IntPoint()
                    {
                        X = pt.X + 1, Y = pt.Y
                    });
                    PointQ.Enqueue(new IntPoint()
                    {
                        X = pt.X, Y = pt.Y - 1
                    });
                    PointQ.Enqueue(new IntPoint()
                    {
                        X = pt.X, Y = pt.Y + 1
                    });
                }
            }
            DetectionBlob db = new DetectionBlob()
            {
                Points = DiscoveredPoints, LineStart = LineMin, LineEnd = LineMax
            };

            return(db);
        }