patterncsharpMinor
Creating and combining rectangles based on a result of an edge detection
Viewed 0 times
resultcombiningrectanglescreatingedgebaseddetectionand
Problem
Context
In an imageprocessing project of mine, I needed to do some edge detection and implemented the Theo Pavlidis algorithm which works quite well. A problem had been to get the next "good" position. Assuming an image like this (where the
011110
111111
111111
011110
this would result in the following edges found
011110
100001 1111
100001 1111
011110
because the algorithm is searching for values which hadn't been visited and have the desired value
So I was in the need to find the enclosed area to exclude it from the algorithms position search area.
The algorithm returns a
So, nothing fancy at all.
My idea was to first create an
The meat
The creation of the
```
private IEnumerable ToRectangles(IEnumerable positions)
{
foreach (Position position in positions.Distinct(new PositionComparerY()).OrderBy(p => p.Y))
{
IEnumerable positionsWithSameY = positions.Where(p => p.Y == position.Y);
int minX = positionsWithSameY.Min(x => x.X);
int maxX = positionsWithSameY.Max(x => x.X);
In an imageprocessing project of mine, I needed to do some edge detection and implemented the Theo Pavlidis algorithm which works quite well. A problem had been to get the next "good" position. Assuming an image like this (where the
1 represent the needed pixel value) 011110
111111
111111
011110
this would result in the following edges found
011110
100001 1111
100001 1111
011110
because the algorithm is searching for values which hadn't been visited and have the desired value
1 in it. So I was in the need to find the enclosed area to exclude it from the algorithms position search area.
The algorithm returns a
IEnumerable for each found value on the edge, where the Position struct looks like so public struct Position
{
public int X;
public int Y;
public Position(int x, int y)
{
X = x;
Y = y;
}
private static readonly Position empty = new Position(-1, -1);
public static Position Empty
{
get
{
return empty;
}
}
public static bool operator ==(Position p1, Position p2){
return (p1.X == p2.X) && (p1.Y == p2.Y);
}
public static bool operator !=(Position p1, Position p2)
{
return !(p1.X == p2.X) && (p1.Y == p2.Y);
}
}So, nothing fancy at all.
My idea was to first create an
IEnumerable out of the IEnumerable using the Min of Position.X of all positions with the same value of Position.Y to create the rectangles line by line form top to bottom. The meat
The creation of the
IEnumerable is done like so ```
private IEnumerable ToRectangles(IEnumerable positions)
{
foreach (Position position in positions.Distinct(new PositionComparerY()).OrderBy(p => p.Y))
{
IEnumerable positionsWithSameY = positions.Where(p => p.Y == position.Y);
int minX = positionsWithSameY.Min(x => x.X);
int maxX = positionsWithSameY.Max(x => x.X);
Solution
Life could be so easy if everything would work like expected. The shown code is good and work successful for the given array, but fails for e.g
000011110 without the
001001000 1 1
011110000 1111
011110000 1111
So we still need to find the enclosed area to exclude it from the algorithm.
For this problem a IMHO good approach is to use the
So I have created one extension methods like so
to check if a given
The
Which leads me also to the conclusion that it would be better to skip the
Update
Profiling my application resulted that the shown extension method
is a bottleneck. So I changed it to
which reduced the execution time to 1/15 .
000011110 without the
0 1111 001001000 1 1
011110000 1111
011110000 1111
So we still need to find the enclosed area to exclude it from the algorithm.
For this problem a IMHO good approach is to use the
PathGeometry class which has the FillContains() method to examine if a given point is inside the "path". So I have created one extension methods like so
public static bool Contains(this IEnumerable geometries, Position position)
{
Point point = new Point(position.X, position.Y);
return geometries.Any(g=> g.FillContains(point));
}to check if a given
Position is contained in an IEnumerable.The
ToPathGeometry() extension method allows me to create a PathGeometry object by providing a starting position and the found positions like so public static PathGeometry ToPathGeometry(this Position startPosition, IEnumerable foundPositions)
{
IList segements = new List();
foreach (Position p in foundPositions.Where(p => p != startPosition))
{
segements.Add(new LineSegment(new Point(p.X, p.Y), true));
}
PathFigure figure = new PathFigure(new Point(startPosition.X, startPosition.Y), segements, true);
IList figures = new List();
figures.Add(figure);
return new PathGeometry(figures);
}Which leads me also to the conclusion that it would be better to skip the
Position class and instead use the Point class.Update
Profiling my application resulted that the shown extension method
public static bool Contains(this IEnumerable geometries, Position position)
{
Point point = new Point(position.X, position.Y);
return geometries.Any(g=> g.FillContains(point));
}is a bottleneck. So I changed it to
public static bool Contains(this IEnumerable geometries, Position position)
{
Point point = new Point(position.X, position.Y);
return geometries.Any(g=> g.Bounds.Contains(point));
}which reduced the execution time to 1/15 .
Code Snippets
public static bool Contains(this IEnumerable<PathGeometry> geometries, Position position)
{
Point point = new Point(position.X, position.Y);
return geometries.Any(g=> g.FillContains(point));
}public static PathGeometry ToPathGeometry(this Position startPosition, IEnumerable<Position> foundPositions)
{
IList<LineSegment> segements = new List<LineSegment>();
foreach (Position p in foundPositions.Where(p => p != startPosition))
{
segements.Add(new LineSegment(new Point(p.X, p.Y), true));
}
PathFigure figure = new PathFigure(new Point(startPosition.X, startPosition.Y), segements, true);
IList<PathFigure> figures = new List<PathFigure>();
figures.Add(figure);
return new PathGeometry(figures);
}public static bool Contains(this IEnumerable<PathGeometry> geometries, Position position)
{
Point point = new Point(position.X, position.Y);
return geometries.Any(g=> g.FillContains(point));
}public static bool Contains(this IEnumerable<PathGeometry> geometries, Position position)
{
Point point = new Point(position.X, position.Y);
return geometries.Any(g=> g.Bounds.Contains(point));
}Context
StackExchange Code Review Q#93396, answer score: 3
Revisions (0)
No revisions yet.