Skip to content

Commit

Permalink
Merge pull request #16 from iharwell/LineDetectorDocumentation
Browse files Browse the repository at this point in the history
Line detector documentation
  • Loading branch information
ycshu086 authored Jun 2, 2021
2 parents a2c00d4 + 2320a1d commit 3a1f12f
Show file tree
Hide file tree
Showing 10 changed files with 390 additions and 6 deletions.
40 changes: 40 additions & 0 deletions src/VAP/LineDetector/CascadedLinesDetector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

namespace LineDetector
{
/// <summary>
/// Detector that uses a series of lines to detect the approach of items and fires when the items cross the final line.
/// </summary>
class CascadedLinesDetector : ILineBasedDetector
{
List<ISingleLineCrossingDetector> lineCrossingDetectors;
Expand All @@ -19,6 +22,9 @@ class CascadedLinesDetector : ILineBasedDetector
List<int> lastEventFrame;
bool debug = false;

/// <summary>
/// Activates debug logging.
/// </summary>
public void setDebug()
{
debug = true;
Expand All @@ -28,6 +34,9 @@ public void setDebug()
}
}

/// <summary>
/// Provides a history of the occupancy of this line detector, with each entry containing a list of occupancy values for each line considered by this detector.
/// </summary>
public List<List<double>> getOccupancyHistory()
{
List<List<double>> ret = new List<List<double>>();
Expand All @@ -45,6 +54,12 @@ public List<List<double>> getOccupancyHistory()
}
}

/// <summary>
/// Creates a <see cref="CascadedLinesDetector"/> using the provided detectors,
/// </summary>
/// <param name="l_lineDetectors">A list of <see cref="ISingleLineCrossingDetector"/> objects to use in this detector.</param>
/// <param name="l_minLags">The minimum number of events to store in the internal buffer.</param>
/// <param name="l_maxLags">The maximum number of events to store in the internal buffer.</param>
public CascadedLinesDetector(List<ISingleLineCrossingDetector> l_lineDetectors, List<int> l_minLags, List<int> l_maxLags)
{
lineCrossingDetectors = l_lineDetectors;
Expand Down Expand Up @@ -138,6 +153,7 @@ void NotifyCrossingEvent(int frameNo, int lineNo)
}
}

/// <inheritdoc/>
public void notifyFrameArrival(int frameNo, List<Box> boxes, Bitmap mask)
{
for (int i = 0; i < noLines; i++)
Expand All @@ -151,6 +167,7 @@ public void notifyFrameArrival(int frameNo, List<Box> boxes, Bitmap mask)
}
}

/// <inheritdoc/>
public void notifyFrameArrival(int frameNo, Bitmap mask)
{
for (int i = 0; i < noLines; i++)
Expand All @@ -163,16 +180,25 @@ public void notifyFrameArrival(int frameNo, Bitmap mask)
}
}

/// <summary>
/// Gets the number of times that this detector has been triggered.
/// </summary>
public int getCount()
{
return Count;
}

/// <summary>
/// Gets the bounding box of the line used by this detector.
/// </summary>
public Box getBbox()
{
return Bbox;
}

/// <summary>
/// Sets the count of this detector.
/// </summary>
public void setCount(int value)
{
Count = value;
Expand All @@ -184,6 +210,10 @@ int getPendingNow(int frameNo, int lineNo)
return CrossingEventTimeStampBuffers[lineNo].Count;
}

/// <summary>
/// Gets a <see cref="Dictionary{TKey, TValue}"/> of the parameters used by this detector, stored by name.
/// </summary>
/// <returns></returns>
public Dictionary<string, Object> getParameters()
{
Dictionary<string, Object> ret = new Dictionary<string, object>();
Expand All @@ -193,11 +223,18 @@ public Dictionary<string, Object> getParameters()
return ret;
}

/// <summary>
/// Gets the current occupancy state of this detector. This updates when the detector is notified of a frame arrival.
/// </summary>
/// <returns><see langword="true"/> if the line is occupied; otherwise, <see langword="false"/>.</returns>
public bool getOccupancy()
{
return lineCrossingDetectors[0].getOccupancy();
}

/// <summary>
/// Gets the line segments used by this detector.
/// </summary>
public List<(Point p1, Point p2)> getLineCoor()
{
List<(Point p1, Point p2)> coors = new List<(Point p1, Point p2)>();
Expand All @@ -209,6 +246,9 @@ public bool getOccupancy()
return coors;
}

/// <summary>
/// Gets the <see cref="DetectionLine"/> used by this detector.
/// </summary>
public DetectionLine getDetectionLine()
{
return lineCrossingDetectors[0].getDetectionLine();
Expand Down
69 changes: 66 additions & 3 deletions src/VAP/LineDetector/DetectionLine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,27 @@ public class DetectionLine

public static double DEFAULT_OCCUPANCY_THRESHOLD = 0.9; // default threhsold

/// <summary>
/// The first point of the line.
/// </summary>
public Point p1;

/// <summary>
/// The second point of the line.
/// </summary>
public Point p2;

/// <summary>
/// The step size used to determine occupancy.
/// </summary>
public double increment;

/// <summary>
/// The overlap threshold used to determine occupancy.
/// </summary>
public double overlapFractionThreshold = DEFAULT_OCCUPANCY_THRESHOLD;

/// <inheritdoc cref="DetectionLine(int, int, int, int, double)"/>
public DetectionLine(int a, int b, int c, int d)
{
p1 = new Point(a, b);
Expand All @@ -28,6 +44,14 @@ public DetectionLine(int a, int b, int c, int d)
increment = 1 / (2 * length);
}

/// <summary>
/// Creates a <see cref="DetectionLine"/> using the given coordinates.
/// </summary>
/// <param name="a">The X coordinate of the first point of the line.</param>
/// <param name="b">The Y coordinate of the first point of the line.</param>
/// <param name="c">The X coordinate of the second point of the line.</param>
/// <param name="d">The Y coordinate of the second point of the line.</param>
/// <param name="l_threshold">The overlap acceptance threshold used for a positive detection.</param>
public DetectionLine(int a, int b, int c, int d, double l_threshold)
{
p1 = new Point(a, b);
Expand All @@ -37,7 +61,16 @@ public DetectionLine(int a, int b, int c, int d, double l_threshold)
overlapFractionThreshold = l_threshold;
}


/// <summary>
/// Calculates the fraction of the <see cref="DetectionLine"/> that overlaps the given mask AND the given box.
/// </summary>
/// <param name="b">The bounding box of the area of interest in the mask.</param>
/// <param name="mask">A mask detailing the precise layout of items in the frame using black to indicate vacant space, and white to indicate occupied space.</param>
/// <returns>
/// Returns the fraction of this DetectionLine that overlaps
/// the given mask, from 0 indicating no overlap to 1 indicating
/// complete overlap.
/// </returns>
public double getFractionContainedInBox(Box b, Bitmap mask)
{
double eta = 0;
Expand All @@ -56,7 +89,7 @@ public double getFractionContainedInBox(Box b, Bitmap mask)

bool isInside = b.IsPointInterior((int)currentX, (int)currentY);

if (mask.GetPixel((int)currentX, (int)currentY).ToString() == "Color [A=255, R=255, G=255, B=255]")
if (mask.GetPixel((int)currentX, (int)currentY).ToString() == "Color [A=255, R=255, G=255, B=255]" )
{
overlapCount++;
}
Expand All @@ -71,6 +104,15 @@ public double getFractionContainedInBox(Box b, Bitmap mask)
return fraction;
}

/// <summary>
/// Calculates the fraction of the <see cref="DetectionLine"/> which overlaps the given mask.
/// </summary>
/// <param name="mask">A mask detailing the precise layout of items in the frame using black to indicate vacant space, and white to indicate occupied space.</param>
/// <returns>
/// Returns the fraction of this DetectionLine that overlaps
/// the given mask, from 0 indicating no overlap to 1 indicating
/// complete overlap.
/// </returns>
public double getFractionInForeground(Bitmap mask)
{
double eta = 0;
Expand All @@ -87,7 +129,7 @@ public double getFractionInForeground(Bitmap mask)

totalPixelCount++;

if (mask.GetPixel((int)currentX, (int)currentY).ToString() == "Color [A=255, R=255, G=255, B=255]")
if ( mask.GetPixel( (int)currentX, (int)currentY ).ToString() == "Color [A=255, R=255, G=255, B=255]" )
{
overlapCount++;
}
Expand All @@ -103,6 +145,12 @@ public double getFractionInForeground(Bitmap mask)
}


/// <summary>
/// Finds the box with the maximum overlap fraction with this <see cref="DetectionLine"/>.
/// </summary>
/// <param name="boxes">The list of <see cref="Box"/> objects to check, representing the bounding boxes of items in frame.</param>
/// <param name="mask">A mask detailing the precise layout of items in the frame using black to indicate vacant space, and white to indicate occupied space.</param>
/// <returns>Returns a tuple containing both the maximum overlap fraction found, and the <see cref="Box"/> associated with that overlap.</returns>
public (double frac, Box b) getMaximumFractionContainedInAnyBox(List<Box> boxes, Bitmap mask)
{
double maxOverlapFraction = 0;
Expand All @@ -121,6 +169,16 @@ public double getFractionInForeground(Bitmap mask)
return (maxOverlapFraction, maxB);
}

/// <summary>
/// Determines if this line is occupied.
/// </summary>
/// <param name="boxes">The bounding boxes of items in the frame.</param>
/// <param name="mask">A mask detailing the precise layout of items in the frame using black to indicate vacant space, and white to indicate occupied space.</param>
/// <returns>
/// Returns a tuple containing a boolean indicating whether this line is
/// occupied, and the bounding box of the occupying item if so. If this line is
/// unoccupied, the bounding box will be null.
/// </returns>
public (bool occupied, Box box) isOccupied(List<Box> boxes, Bitmap mask)
{
(double frac, Box b) = getMaximumFractionContainedInAnyBox(boxes, mask);
Expand All @@ -134,6 +192,11 @@ public double getFractionInForeground(Bitmap mask)
}
}

/// <summary>
/// Determines if this line is occupied.
/// </summary>
/// <param name="mask">A mask detailing the precise layout of items in the frame using black to indicate vacant space, and white to indicate occupied space.</param>
/// <returns>Returns true if the line is occupied, and false otherwise.</returns>
public bool isOccupied(Bitmap mask)
{
double frac = getFractionInForeground(mask);
Expand Down
27 changes: 25 additions & 2 deletions src/VAP/LineDetector/Detector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ public class Detector
{
bool DISPLAY_BGS;

public int START_DELAY = 120; //this is an initial delay we put in for the background subtractor to kick in, N_FRAMES_TO_LEARN in MOG2.cs
/// <summary>
/// The initial delay to allow for the background subtractor to kick in, N_FRAMES_TO_LEARN in MOG2.cs
/// </summary>
public int START_DELAY = 120;


public MultiLaneDetector multiLaneDetector;

Expand All @@ -24,6 +28,13 @@ public class Detector
Dictionary<string, bool> occupancy = new Dictionary<string, bool>();
Dictionary<string, bool> occupancy_prev = new Dictionary<string, bool>();

/// <summary>
/// Constructs a <see cref="Detector"/> object with the provided
/// </summary>
/// <param name="sFactor">Sampling rate scaling factor.</param>
/// <param name="rFactor">Resolution scaling factor.</param>
/// <param name="linesFile">A file specifying the lines used for the line-crossing algorithm.</param>
/// <param name="displayBGS">True to display a separate image each frame with the current frame number, the lines used, and the changes from the previous frame.</param>
public Detector(int sFactor, double rFactor, string linesFile, bool displayBGS)
{
Dictionary<string, ILineBasedDetector> lineBasedDetectors = LineSets.readLineSet_LineDetector_FromTxtFile(linesFile, sFactor, rFactor);
Expand All @@ -34,6 +45,18 @@ public Detector(int sFactor, double rFactor, string linesFile, bool displayBGS)
Console.WriteLine(linesFile);
}

/// <summary>
/// Checks for items crossing the provided LineSet.
/// </summary>
/// <param name="frame">The frame to check.</param>
/// <param name="frameIndex">The index of the frame given.</param>
/// <param name="fgmask">The foreground mask of the frame.</param>
/// <param name="boxes">A list of bounding boxes of items in the frame which deviate from the background.</param>
/// <returns>
/// <para>Returns a tuple with two <see cref="Dictionary{TKey, TValue}">Dictionaries</see>.</para>
/// <para>The first dictionary contains the number of items which cross the lines of interest, indexed by line name.</para>
/// <para>The second dictionary contains a boolean for each line indicating whether or not an item is present at that line.</para>
/// </returns>
public (Dictionary<string, int>, Dictionary<string, bool>) updateLineResults(Mat frame, int frameIndex, Mat fgmask, List<Box> boxes)
{
if (frameIndex > START_DELAY)
Expand All @@ -53,7 +76,7 @@ public Detector(int sFactor, double rFactor, string linesFile, bool displayBGS)
Cv2.Line(fgmask, p1.X, p1.Y, p2.X, p2.Y, new Scalar(255, 0, 255, 255), 5);
}
Cv2.ImShow("BGS Output", fgmask);
Cv2.WaitKey(1);
//Cv2.WaitKey(1);
}
}
counts = multiLaneDetector.getCounts();
Expand Down
26 changes: 26 additions & 0 deletions src/VAP/LineDetector/FallingEdgeCrossingDetector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

namespace LineDetector
{
/// <summary>
/// A line crossing detector that fires when an item leaves the line area.
/// </summary>
class FallingEdgeCrossingDetector : ICrossingDetector
{
List<int> FrameNoList = new List<int>();
Expand All @@ -14,12 +17,21 @@ class FallingEdgeCrossingDetector : ICrossingDetector
bool debug = false;
public List<double> debug_occupancySequence;

/// <summary>
/// Enables debug mode. Within <see cref="FallingEdgeCrossingDetector"/>, this enables logging occupancy values.
/// </summary>
/// <remarks>
/// The occupancy log may be accessed with <see cref="getLineOccupancyHistory"/>.</remarks>
public void setDebug()
{
debug = true;
debug_occupancySequence = new List<double>();
}

/// <summary>
/// Creates a <see cref="FallingEdgeCrossingDetector"/> with the provided frame rate sampling factor.
/// </summary>
/// <param name="sFactor">The frame rate sampling factor. Note that particularly large values could behave unexpectedly.</param>
public FallingEdgeCrossingDetector(int sFactor)
{
UP_STATE_TRANSITION_LENGTH = (int)Math.Ceiling((double)UP_STATE_TRANSITION_LENGTH / sFactor);
Expand Down Expand Up @@ -61,6 +73,12 @@ private bool CheckForStateTransision()


//return true if there was a line crossing event
/// <summary>
/// Notifies the detector of a new occupancy state at a given frame.
/// </summary>
/// <param name="frameNo">The index of the frame of interest.</param>
/// <param name="occupancy">The occupancy state at that frame.</param>
/// <returns>Returns true if an event was detected, and false otherwise.</returns>
public bool notifyOccupancy(int frameNo, bool occupancy)
{
while (FrameNoList.Count > 0)
Expand Down Expand Up @@ -116,11 +134,19 @@ public bool notifyOccupancy(int frameNo, bool occupancy)
return CheckForStateTransision();
}

/// <summary>
/// Gets the occupancy state of the detector as of the latest frame.
/// </summary>
/// <returns></returns>
public OCCUPANCY_STATE getState()
{
return curState;
}

/// <summary>
/// Gets a list of all occupancy values observed by the detector while debugging has been enabled. No frame indices are included.
/// </summary>
/// <returns></returns>
public List<double> getLineOccupancyHistory()
{
return debug_occupancySequence;
Expand Down
Loading

0 comments on commit 3a1f12f

Please sign in to comment.