【发布时间】:2020-03-31 02:42:30
【问题描述】:
我正在使用 OpenCV 使用 cvFitLine() 从一组点拟合一条线
cvFitLine() 返回一个与直线和直线上的点共线的归一化向量。
查看详情here
使用这些信息我怎样才能得到一条线的方程以便我可以画线?
【问题讨论】:
我正在使用 OpenCV 使用 cvFitLine() 从一组点拟合一条线
cvFitLine() 返回一个与直线和直线上的点共线的归一化向量。
查看详情here
使用这些信息我怎样才能得到一条线的方程以便我可以画线?
【问题讨论】:
如果cvFitLine()返回归一化向量(vx,vy)和点(x0,y0),则直线方程为
(x,y) = (x0,y0) + t*(vx,vy)
t 从 -∞ 到 +∞。
这是您要求的,但可能不会立即帮助您划清界限。您可能希望将其剪辑到屏幕边界,或者可能是原始点集的边界框。要将一条线剪成一个矩形,只需求解该线与矩形边界相交的t 的值。
【讨论】:
只画一条大线,而不是求解边界。例如:
cv.Line(img, (x0-m*vx[0], y0-m*vy[0]), (x0+m*vx[0], y0+m*vy[0]), (0,0,0))
例如会这样做.. m 足够大:)
【讨论】:
我在上面使用了类似于 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);
}
【讨论】:
这只是向任何路人说明@brainjam 在python 中的答案。
使用单位向量(vx, vy) 和线上某个点(x0, y0) 的线的公式是:
(x, y) = (x0, y0) + t*(vx, vy)
cv2.fitLine() 的返回是:
np.array([vx, vy, x0, y0])
在示例情况下,我有一条跨越图像高度的线,因此我想找到与 y=0 和 y=img.shape[0](顶部/底部边界)相交的 t0 和 t1。
# 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)
【讨论】:
添加到@brainjam 答案:
裁剪到原始点集的边界框:
// 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->x替换为0和maxXP->x替换为image.cols - 1,最初在https://stackoverflow.com/a/14192660/2380455中回答
【讨论】:
我们使用“ Vec4f fitedLine;”用于拟合线 在 fitLine 我们有 4 个参数 如果我们考虑下面的线关系: Y - Y0 = M (X - X0)
我们有 Y0 = FitedLine[3]; X0 = FitedLine[2]; m = FitedLine[1]/FitedLine[0];
所以我们有一个直线方程,我们可以在上面找到其他点。
【讨论】: