Zaher Joukhadar
Zaher Joukhadar

Reputation: 1026

How to draw line not line segment OpenCV 2.4.2

Well the question says it all,

I know the function Line(), which draws line segment between two points.

I need to draw line NOT a line segment, also using the two points of the line segment.


[EN: Edit from what was previously posted as an answer for the question]

I used your solution and it performed good results in horizontal lines, but I still got problems in vertical lines.

For example, follows below an example using the points [306,411] and [304,8] (purple) and the draw line (red), on a image with 600x600 pixels. Do you have some tip?

enter image description here

Upvotes: 11

Views: 9481

Answers (4)

dbcesar
dbcesar

Reputation: 81

I had the same problem and found out that there it is a known bug on 2.4.X OpenCV, fixed already for newer versions.

For the 2.4.X versions, the solution is to clip the line before plot it using cv::clipLine()

Here there is a function I did to myself that works fine on the 2.4.13 OpenCV

void Detector::drawFullImageLine(cv::Mat& img, const std::pair<cv::Point, cv::Point>& points, cv::Scalar color)
{
    //points of line segment
    cv::Point p1 = points.first;
    cv::Point p2 = points.second;

    //points of line segment which extend the segment P1-P2 to 
    //the image borders.
    cv::Point p,q;

    //test if line is vertical, otherwise computes line equation
    //y = ax + b
    if (p2.x == p1.x)
    {
        p = cv::Point(p1.x, 0); 
        q = cv::Point(p1.x, img.rows); 
    }
    else
    {
        double a = (double)(p2.y - p1.y) / (double) (p2.x - p1.x);
        double b =  p1.y - a*p1.x;

        p = cv::Point(0, b);
        q = cv::Point(img.rows, a*img.rows + b);

        //clipline to the image borders. It prevents a known bug on OpenCV
        //versions 2.4.X when drawing 
        cv::clipLine(cv::Size(img.rows, img.cols), p, q);
    }

    cv::line(img, p, q, color, 2);
}

Upvotes: 5

Ahmed Hegazy
Ahmed Hegazy

Reputation: 12605

This answer is forked from pajus_cz answer but a little improved.

We have two points and we need to get the line equation y = mx + b to be able to draw the straight line.

There are two variables we need to get

1- Slope(m)

Slope equation

2- b which can be retrieved through the line equation using any given point from the two we have already after calculating the slope b = y - mx .

void drawStraightLine(cv::Mat *img, cv::Point2f p1, cv::Point2f p2, cv::Scalar color)
{
        Point2f p, q;
        // Check if the line is a vertical line because vertical lines don't have slope
        if (p1.x != p2.x)
        {
                p.x = 0;
                q.x = img->cols;
                // Slope equation (y1 - y2) / (x1 - x2)
                float m = (p1.y - p2.y) / (p1.x - p2.x);
                // Line equation:  y = mx + b
                float 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::line(*img, p, q, color, 1);
}

Upvotes: 2

pajus_cz
pajus_cz

Reputation: 1321

I see this is pretty much old question. I had exactly the same problem and I used this simple code:

double Slope(int x0, int y0, int x1, int y1){
     return (double)(y1-y0)/(x1-x0);
}

void fullLine(cv::Mat *img, cv::Point a, cv::Point b, cv::Scalar color){
     double slope = Slope(a.x, a.y, b.x, b.y);

     Point p(0,0), q(img->cols,img->rows);

     p.y = -(a.x - p.x) * slope + a.y;
     q.y = -(b.x - q.x) * slope + b.y;

     line(*img,p,q,color,1,8,0);
}

First I calculate a slope of the line segment and then I "extend" the line segment into image's borders. I calculate new points of the line which lies in x = 0 and x = image.width. The point itself can be outside the Image, which is a kind of nasty trick, but the solution is very simple.

Upvotes: 10

Hammer
Hammer

Reputation: 10329

You will need to write a function to do that for yourself. I suggest you put your line in ax+by+c=0 form and then intersect it with the 4 edges of your image. Remember if you have a line in the form [a b c] finding its intersection with another line is simply the cross product of the two. The edges of your image would be

top_horizontal =    [0 1 0];
left_vertical   =   [1 0 0];
bottom_horizontal = [0 1 -image.rows];
right_vertical =    [1 0 -image.cols];

Also, if you know something about the distance between your points you could also just pick points very far along the line in each direction, I don't think the points handed to Line() need to be on the image.

Upvotes: 6

Related Questions