Reputation: 129
I'm trying to come up with a filter that would show ONLY the lines pointing in one direction.
Say we have our Original Image like so:
What filter do I need to apply to select only the vertical lines. Like the ones highlighted in red here.
Can this filter be generic to allow me to select other directions? Diagonal from bottom left to top right, for example.
Upvotes: 2
Views: 1089
Reputation: 434
The most straightforward (although not the fastest) solution would be to use Hough transform to detect lines and then measure the slope of the lines and leave only the vertical ones.
Please take a look at this tutorial first https://docs.opencv.org/2.4/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.html.
Here's a code sample that solves your problem more or less. You might want to adjust some parameters to get better results:
std::vector<cv::Vec4i> extractVerticalLines(const std::vector<cv::Vec4i>& lines, int tollerance)
{
std::vector<cv::Vec4i> output;
for(const auto& line : lines)
{
// subtract x0 and x1 component (horizontal beginning and horizontal end)
if(std::abs(line[0] - line[2]) <= tollerance)
{
output.push_back(line);
}
}
return output;
}
void drawLines(cv::Mat& inputImage, const std::vector<cv::Vec4i>& lines, const cv::Scalar& color, int thickness)
{
for(const auto& line : lines)
{
cv::line(inputImage, cv::Point2i(line[0], line[1]), cv::Point2i(line[2], line[3]), color, thickness);
}
}
std::vector<cv::Vec4i> extractAllLines(const cv::Mat& image, int threshold, double minLength = 100)
{
std::vector<cv::Vec4i> lines;
cv::HoughLinesP(image, lines, 1, CV_PI / 180, threshold, minLength);
return lines;
}
int main()
{
auto image = cv::imread("lines.png", cv::IMREAD_GRAYSCALE);
auto output = cv::Mat(image.size(), image.type(), cv::Scalar::all(0));
image = ~image; // invert colors because background should be black and lines white
auto lines = extractAllLines(image, 50);
auto verticalLines = extractVerticalLines(lines, 5);
drawLines(output, verticalLines, cv::Scalar::all(255), 1);
cv::imshow("Result", output);
cv::waitKey(0);
}
This yields the following result:
Keep in mind that there are multiple lines that merge together in the output. If you want there to be exactly one line vertically, you'd have to skeletonize the image first so that everything is 1px thick or try some smart filtering of the results.
Upvotes: 1