Get a Single Line Representation for Multiple Close by Lines Clustered Together in Opencv

How to fuse several linear lines that are close together into one?

To apply any clustering algorithm you need to define some distance measure on the objects you want to cluster. For line segments, the most obvious distance I can think of is the minimum distance between any pair of points from the two segments, i.e.:

def line_distance(line1, line2):
return min( point_distance(point1, point2) for point1 in line1 for point2 in line2 )

You can then apply hierarchical clustering on the set of lines you get, using this distance measure and some threshold distance d to merge two lines.

However, I feel it's better to binarize the image before passing it to edge detector since the panel and its border has quite contrasting colors and that alone might reduce many spurious lines.

How to merge multiple vectors if containing duplicate elements?

Set up is important in this problem. I'm assuming the vec4i is a pair of points describing a straight line segment (e.g. (a, b, c, d) => (x1, y1) -> (x2, y2))

Construct your vec4i such that (x1 < x2) || (x1 == x2 && y1 < y2).

This allows you to make a single left-to-right pass over all lines segments.
Create a new construct, call it a Line:

struct Line {
std::vector<vec4i> segs;
const vec2i &getEnd() const { *segs.rbegin(); }
};

Define some new function that can determine if two endpoints are "close enough" that they are connected. Create a list of Lines.

General algorithm pseudocode (where seg[0] or seg[1] is a segment endpoint):

for (seg : Segments) {
for (line : Lines) {
if (close(line.getEnd()[1], seg[0])) {
line.addSegment(seg)
// break to next *segment*, a segment can only be added to one line.
}
}
// reaching here means we didn't make attach the segment; start a new line.
Lines.add(Line(seg))
}

This joins all left-to right segments. You'll need a second pass that joins lines that is aware of both ends of the line if there's more complicated lines like this:

      \
\
--------

(horizontal, diagonal) or a back curve like at the end of your diagram

   \
\
|
/
/

(curve down, curve up) that you want joined into one line rather than two.

Why different lines drawn using cv::line function has different transparency (alpha) levels?

The CV_AA flag tell cv::line() to draw an Anti-Aliased line. This is the source of your transparent line border pixels.

If you remove the CV_AA flag, the line will be drawn jagged, but without transparencies (Bresenham).

Looking more closely at the image there are visible JPG artifacts inside the colored area (sporadic darker spots). These artifacts to not exist in the image in memory but will appear in a JPG saved file. Try saving your image as PNG.



Related Topics



Leave a reply



Submit