Rômulo Cerqueira
Rômulo Cerqueira

Reputation: 189

Draw Straight line between two points in vertical orientation using Opencv and C++

I have tried to draw a straight line using two reference points and I got some problems on vertical orientation.

That's the current source code:

cv::Mat img = cv::Mat::zeros(600,600,CV_8UC3);
cv::Point p1(306,41);
cv::Point p2(304,8);

cv::Point p(0,0), q(img.cols, img.rows);
if (p1.x != p2.x) {
    double m = (double) (p1.y - p2.y) / (double) (p1.x - p2.x);
    double b = p1.y - (m * p1.x);
    p.y = m * p.x + b;
    q.y = m * q.x + b;
} else {
    p.x = q.x = p2.x;
    p.y = 0;
    q.y = img.rows;
}

cv::circle(img, p1, 4, cv::Scalar(255,0,255), -1);
cv::circle(img, p2, 4, cv::Scalar(255,0,255), -1);
cv::line(img, p, q, cv::Scalar(0,0,255), 2);

This is the following output: enter image description here

What am I doing wrong?

Upvotes: 0

Views: 3890

Answers (3)

Miki
Miki

Reputation: 41765

This is a known bug, now fixed.

So update to the latest version of OpenCV (version 3.2) or use cv::clipLine(img.size(), p, q); before drawing line.


All credits to @sturkmen

Upvotes: 1

dbcesar
dbcesar

Reputation: 81

I had the same problem of you running on the 2.4.9 version. Given the Miki anwser it might have been fixed on newer versions.

The problem seems to happen when the line slope is too high and therefore the intersection with the y axis it is far away from the origin.

I tested the cited point,as well many others and the following function handled that problem. It basically computes the intersection of the computed line with the image borders and return collinear points in the image borders.

void getLinePointinImageBorder(const cv::Point& p1_in, const cv::Point& p2_in,
                               cv::Point& p1_out, cv::Point& p2_out, 
                               int rows, int cols)
{
    double m = (double) (p1_in.y - p2_in.y) / (double) (p1_in.x - p2_in.x + std::numeric_limits<double>::epsilon());
    double b = p1_in.y - (m * p1_in.x);

    std::vector<cv::Point> border_point;
    double x,y;
    //test for the line y = 0
    y = 0;
    x = (y-b)/m;
    if(x > 0 && x < cols)
        border_point.push_back(cv::Point(x,y));

    //test for the line y = img.rows
    y = rows;
    x = (y-b)/m;
    if(x > 0 && x < cols)
        border_point.push_back(cv::Point(x,y));

    //check intersection with horizontal lines x = 0
    x = 0;
    y = m * x + b;
    if(y > 0 && y < rows)
        border_point.push_back(cv::Point(x,y));

    x = cols;
    y = m * x + b;
    if(y > 0 && y < rows)
        border_point.push_back(cv::Point(x,y));

    p1_out = border_point[0];
    p2_out = border_point[1];
}

Upvotes: 3

Miki
Miki

Reputation: 41765

I'm not able to reproduce the error with your code. This code (copied & pasted from yours) works well:

#include <opencv2\opencv.hpp>

using namespace std;
using namespace cv;

int main() {

    cv::Mat img = cv::Mat::zeros(600,600,CV_8UC3);
    cv::Point p1(301,49);
    cv::Point p2(303,460);

    cv::Point p(0,0), q(img.cols, img.rows);
    if (p1.x != p2.x) {
        double m = (double) (p1.y - p2.y) / (double) (p1.x - p2.x);
        double b = p1.y - (m * p1.x);
        p.y = m * p.x + b;
        q.y = m * q.x + b;
    } else {
        p.x = q.x = p2.x;
        p.y = 0;
        q.y = img.rows;
    }

    cv::circle(img, p1, 4, cv::Scalar(255,0,255), -1);
    cv::circle(img, p2, 4, cv::Scalar(255,0,255), -1);
    cv::line(img, p, q, cv::Scalar(0,0,255), 2);

    imshow("Result", img);
    waitKey();

    return 0;
}

enter image description here

Upvotes: 1

Related Questions