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.