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 Line
s.
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
How to Use Sendinput Function C++
Is Opencv Matrix Data Guaranteed to Be Continuous
Why Can't I Store References in a 'Std::Map' in C++
How to Initialize Static Members in the Header
Why Use ++I Instead of I++ in Cases Where the Value Is Not Used Anywhere Else in the Statement
Set Local Environment Variables in C++
How to Install/Configure Opencv3.2.0 with C++, Visual Studio 2017
Detect Operator Support with Decltype/Sfinae
Templates: Template Function Not Playing Well with Class's Template Member Function
How to Pass a C++ Lambda to a C-Callback That Expects a Function Pointer and a Context
What Does _T Stands for in a Cstring
How to Copy One Map into Another Using Std::Copy
Visual Studio: Link:Fatal Error Lnk1181: Cannot Open Input File
What Does 'Using Std::Swap' Inside the Body of a Class Method Implementation Mean
C++11 Range-Based For-Loop Efficiency "Const Auto &I" Versus "Auto I"