I stuck at one point in my code. Firstly a short clarification what I'm doing: As an input there's a image of a floor. With the Canny and HoughLinesP algorithm I want to segment the whole wall in many "small" parts, as you could see here, which is at the same time the ideal output (here without canny), I would like to get - a segment is between two red lines.
Alright, since I get actually this outout here
I wonder how to merge lines, which are too cloose to each other. For example the lines 2,4,3,5,6 should be one line and also count as one. Than line 7 till 15 should be also one, which will be the second line.
Of course, I did some research and tried this:
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <experimental/filesystem>
using namespace cv;
using namespace std;
Mat srcReal = //here's this image http://imgur.com/a/Kcjp6
Mat src, dst, cdst;
vector<Vec4i> lines;
void wallMapping(Mat src) {
Scalar mu, sigma;
meanStdDev(src, mu, sigma);
Canny(src, dst, mu.val[0] - sigma.val[0], mu.val[0] + sigma.val[0], 3, false);
cvtColor(dst, cdst, CV_GRAY2BGR);
HoughLinesP(dst, lines, 1, CV_PI / 2, 50, 50, 200);
sort(lines.begin(), lines.end(), vec4iSortByX()); ///sort all lines by number
for (size_t i = 1; i < lines.size(); i++) {
Vec4i current = lines[i]; ///set current lines
Point pt1 = Point(current[0], current[1]);
Point pt2 = Point(current[2], current[3]);
Vec4i previous = lines[i - 1]; ///set previous lines
Point ppt1 = Point(previous[0], previous[1]);
Point ppt2 = Point(previous[2], previous[3]);
int gradient1, gradient2;
if (pt1.x - pt2.x != 0) {
gradient1 = (pt1.y - pt2.y) / (pt1.x - pt2.x);
gradient2 = (ppt1.y - ppt2.y) / (ppt1.x - ppt2.x);
}
Point avrgpt1, avrgpt2;
if (gradient1 == gradient2) {
avrgpt1.x = (pt1.x + ppt1.x) / 2;
avrgpt2.x = (pt2.x + ppt2.x) / 2;
avrgpt1.y = (pt1.y + ppt1.y) / 2;
avrgpt2.y = (pt2.y + ppt2.y) / 2;
}
double angle = atan2(ppt2.y - ppt1.y, ppt2.x - ppt1.x) * 180.0 / CV_PI; ///draw only vertical lines (90 degree)
if (angle) {
std::vector<int> lineLabel;
int numLines = cv::partition(lines, lineLabel, isEqual);
line(cdst, avrgpt1, avrgpt2, Scalar(0, 0, 255), 2, CV_AA);
}
cv::putText(cdst, to_string(i+1), pt2 + Point(0, 10), 4, 1, Scalar(0, 255, 0), 1, 8, false);
//some other stuff
}
//main
int main(int argc, char *argv[]) {
wallMapping(srcReal);
waitKey(0);
return 0;
}
But as you look at the picture above, you could see that my merging idea in the code doesn't work. So I'd be glad about idea, approaches or corrections of my code! Thanks!
Draw the lines in a separate binary image, perfom morphological closing on them so that the ones that are close to each other merge, and then erode the image with some small kernel, e.g. 3x3 to leave thin lines.
After that, get non-zero coordinates from the binary image you've just created and draw these coordinates in the desired image.
In order to get these new lines back into the vector, you may find contours within the binary image with
findContours()
and then just find 2 extreme points (points of extreme x or y values) of each contour - these are the points describing the line.