绘制拟合线(OpenCV)

时间:2010-05-01 17:23:03

标签: math geometry opencv

我正在使用OpenCV来使用cvFitLine()

来拟合一组点中的一条线

cvFitLine()返回一个归一化向量,该向量与行和行上的点共线。 详情请见here

使用此信息如何获取线的等式以便我可以绘制线?

6 个答案:

答案 0 :(得分:9)

如果cvFitLine()返回标准化向量(vx,vy)和点(x0,y0),那么该行的等式为

(x,y)=(x0,y0)+ t *(vx,vy)

其中t从-∞到+∞。

这是你要求的,但可能不会立即有助于画线。您可能希望将其剪切到屏幕边界,或者可能是原始点集的边界框。要将线条剪切为矩形,只需求解线条穿过矩形边界的t值。

答案 1 :(得分:9)

只需绘制一条大线而不是解决边界问题。例如:

cv.Line(img, (x0-m*vx[0], y0-m*vy[0]), (x0+m*vx[0], y0+m*vy[0]), (0,0,0))

将以例如..为m足够大:))

答案 2 :(得分:4)

我在那里使用了类似于Karpathy的策略但使用了额外的功能。正如您所看到的,我正在使用cvClipLine将线条修剪为图像的大小,这是不必要的,但确实增加了一点好处。

此处的乘数也被定义为theMult = max(img-> height,img-> width)所以我们不会得到可能有一天溢出的数字。

void drawLine(IplImage * img, float line[4], int thickness,CvScalar color)
{
    double theMult = max(img->height,img->width);
    // calculate start point
    CvPoint startPoint;
    startPoint.x = line[2]- theMult*line[0];// x0
    startPoint.y = line[3] - theMult*line[1];// y0
    // calculate end point
    CvPoint endPoint;
    endPoint.x = line[2]+ theMult*line[0];//x[1]
    endPoint.y = line[3] + theMult*line[1];//y[1]

    // draw overlay of bottom lines on image
    cvClipLine(cvGetSize(img), &startPoint, &endPoint);
    cvLine(img, startPoint, endPoint, color, thickness, 8, 0);
}

答案 3 :(得分:3)

对于任何路人,这只会在python中阐明@brainjam的答案。

使用单位向量(vx, vy)和行(x0, y0)上某点的直线的公式为:

(x, y) = (x0, y0) + t*(vx, vy)

cv2.fitLine()的回报是:

np.array([vx, vy, x0, y0])

在示例情况下,我有一条线跨越图像的高度,因此我想找到与t0t1相交的y=0y=img.shape[0] (顶部/底部边界)。

# get the fitLine for your set of points in the array, `line`
fit_line = cv2.fitLine(line, cv2.DIST_L2, 0, 0.01, 0.01)

# compute t0 for y=0 and t1 for y=img.shape[0]: (y-y0)/vy
t0 = (0-fit_line[3])/fit_line[1]
t1 = (img.shape[0]-fit_line[3])/fit_line[1]

# plug into the line formula to find the two endpoints, p0 and p1
# to plot, we need pixel locations so convert to int
p0 = (fit_line[2:4] + (t0 * fit_line[0:2])).astype(np.uint32)
p1 = (fit_line[2:4] + (t1 * fit_line[0:2])).astype(np.uint32)

# draw the line. For my version of opencv, it wants tuples so we
# flatten the arrays and convert
# args: cv2.line(image, p0, p1, color, thickness)
cv2.line(img, tuple(p0.ravel()), tuple(p1.ravel()), (0, 255, 0), 10)

答案 4 :(得分:1)

添加到@brainjam答案:

要裁剪到原始点集的边界框,请执行以下操作:

.html()

要裁剪整个图像边界,请用https://stackoverflow.com/a/14192660/2380455替换// std::vector<Point2i> points = ... //lineParams: [vx,vy, x0,y0]: (normalized vector, point on our contour) Vec4f lineParams; fitLine(points, lineParams, CV_DIST_L2, 0, 0.01, 0.01); // derive the bounding xs of points decltype(points)::iterator minXP, maxXP; std::tie(minXP, maxXP) = std::minmax_element(points.begin(), points.end(), [](const Point2i& p1, const Point2i& p2){ return p1.x < p2.x; }); // derive y coords of fitted line float m = lineParams[1] / lineParams[0]; int y1 = ((minXP->x - lineParams[2]) * m) + lineParams[3]; int y2 = ((maxXP->x - lineParams[2]) * m) + lineParams[3]; line(clearTarget, Point(minXP->x, y1), Point(maxXP->x, y2), Scalar(255, 255, 255), 2); minXP->x0maxXP->x

答案 5 :(得分:0)

我们使用“Vec4f fitedLine”;用于装配线 在fitLine中我们有4个参数 如果我们考虑线关系az bellow: Y - Y0 = M(X - X0)

我们有     Y0 = FitedLine [3];     X0 = FitedLine [2];     m = FitedLine [1] / FitedLine [0];

所以我们有一个线方程,我们可以在其上找到其他点。