【问题标题】:Draw fitted line (OpenCV)绘制拟合线(OpenCV)
【发布时间】:2020-03-31 02:42:30
【问题描述】:

我正在使用 OpenCV 使用 cvFitLine() 从一组点拟合一条线

cvFitLine() 返回一个与直线和直线上的点共线的归一化向量。 查看详情here

使用这些信息我怎样才能得到一条线的方程以便我可以画线?

【问题讨论】:

    标签: math geometry opencv


    【解决方案1】:

    如果cvFitLine()返回归一化向量(vx,vy)和点(x0,y0),则直线方程为

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

    t 从 -∞ 到 +∞。

    这是您要求的,但可能不会立即帮助您划清界限。您可能希望将其剪辑到屏幕边界,或者可能是原始点集的边界框。要将一条线剪成一个矩形,只需求解该线与矩​​形边界相交的t 的值。

    【讨论】:

    • 我认为这是分析上最正确的答案(与例如制作一条大线和剪裁相比)。我在下面的答案中对此进行了扩展,详细说明了如何在 python 中的图像边界处获取线端点。
    【解决方案2】:

    只画一条大线,而不是求解边界。例如:

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

    例如会这样做.. m 足够大:)

    【讨论】:

      【解决方案3】:

      我在上面使用了类似于 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);
      }
      

      【讨论】:

        【解决方案4】:

        这只是向任何路人说明@brainjam 在python 中的答案。

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

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

        cv2.fitLine() 的返回是:

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

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

        # 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)
        

        【讨论】:

          【解决方案5】:

          添加到@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-&gt;x替换为0maxXP-&gt;x替换为image.cols - 1,最初在https://stackoverflow.com/a/14192660/2380455中回答

          【讨论】:

            【解决方案6】:

            我们使用“ Vec4f fitedLine;”用于拟合线 在 fitLine 我们有 4 个参数 如果我们考虑下面的线关系: Y - Y0 = M (X - X0)

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

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

            【讨论】:

            • 是的,或者如果直线垂直或接近垂直线,则交换 x 和 y。这是对我立即有用的唯一答案。
            猜你喜欢
            • 1970-01-01
            • 2017-03-31
            • 1970-01-01
            • 2016-06-11
            • 2012-07-28
            • 1970-01-01
            • 1970-01-01
            • 2013-03-17
            相关资源
            最近更新 更多