opencv之7.4用直线拟合一组点

获取直线的位置和方向的精确估计,解决直线拟合的问题。
思想:
用HoughlinesP检测直线,将直线保存在lines中,获取Canny图像并获取lines与canny图相交的点集,再用点集拟合直线。
代码:

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "LineFinder.h"
#define PI 3.141591653
using namespace std;
using namespace cv;

int main()
{
    Mat image, result, result2;
    image = imread("D:/round.jpg", 0);
    namedWindow("image");
    imshow("image", image);
    Canny(image, result, 120, 200);
    namedWindow("Canny");
    imshow("Canny", result);    
    vector<Vec4f> li;       //若此处没有检查到直线则之后使用li会出错
    HoughLinesP(result, li, 1, PI/180, 180, 100, 20);
    vector<Vec4f>::iterator it = li.begin();
    for (;it != li.end();++it)
    {
        Point ptr1((*it)[0], (*it)[1]);
        Point ptr2((*it)[2], (*it)[3]);
        line(image, ptr1, ptr2, Scalar(255));
    }
    namedWindow("HoughP");
    imshow("HoughP", image);
    int n = 0;
    cv::line(image, cv::Point(li[n][0], li[n][1]), cv::Point(li[n][2], li[n][3]), cv::Scalar(255), 5);
    cv::Mat oneline(image.size(), CV_8U, cv::Scalar(0));
    cv::line(oneline, cv::Point(li[n][0], li[n][1]), cv::Point(li[n][2], li[n][3]), cv::Scalar(255), 5);
    cv::bitwise_and(result, oneline, oneline);//按位与
    cv::Mat onelineInv;
    cv::threshold(oneline, onelineInv, 128, 255, cv::THRESH_BINARY_INV);//反转图像
    cv::namedWindow("One line");
    cv::imshow("One line", onelineInv);
    vector<Point> points;
    for (int y = 0;y < oneline.rows;y++)
    {
        uchar *ptr = oneline.ptr<uchar>(y);
        for (int x = 0;x < oneline.cols;++x)
        {
            if (ptr[x])
            {
                points.push_back(Point(x, y));
            }
        }
    }
    Vec4f line;
    fitLine(points, line, DIST_L2, 0, 0.01, 0.01);//寻找直线
    int x0 = line[2];
    int y0 = line[3];
    int x1 = x0 - 200 * line[0];
    int y1 = y0 - 200 * line[1];
    image = imread("D:/round.jpg", 0);
    cv::line(image, Point(x0, y0), Point(x1, y1), Scalar(255), 1);
    namedWindow("imageline");
    imshow("imageline", image);
    waitKey(0);
    return 0;
}
    
    

void fitLine( InputArray points, OutputArray line, int distType, double param, double reps, double aeps );
参数详解:
第一个参数: 存储点序列
第二个参数: line中存储返回值
二维空间时: line[0–3] 分别为 (vx,vy, x0,y0)
其中 vx, vy 是正规化之后的斜率向量。 x0,y0 是直线经过的点。
第三,distType
拟合算法,其中 CV_DIST_L2 就是平常的最小二乘法
dist_type=CV_DIST_L2 (L2): ρ(r)=r2/2 (最简单和最快的最小二乘法)
dist_type=CV_DIST_L1 (L1): ρ(r)=r
dist_type=CV_DIST_L12 (L1-L2): ρ(r)=2•[sqrt(1+r2/2) - 1]
dist_type=CV_DIST_FAIR (Fair): ρ(r)=C2•[r/C - log(1 + r/C)], C=1.3998
dist_type=CV_DIST_WELSCH (Welsch): ρ(r)=C2/2•[1 - exp(-(r/C)2)], C=2.9846
dist_type=CV_DIST_HUBER (Huber): ρ(r)= r2/2, if r < C C•(r-C/2), otherwise; C=1.345
第四,第五参数第六参数:推荐值是 0, 0.01, 0.01, 三维空间时: line[0–5] 分别是 (vx, vy, vz,x0, y0,z0)

fitEllipse可以用来绘制椭圆。

获取直线的位置和方向的精确估计,解决直线拟合的问题。
思想:
用HoughlinesP检测直线,将直线保存在lines中,获取Canny图像并获取lines与canny图相交的点集,再用点集拟合直线。
代码:

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "LineFinder.h"
#define PI 3.141591653
using namespace std;
using namespace cv;

int main()
{
    Mat image, result, result2;
    image = imread("D:/round.jpg", 0);
    namedWindow("image");
    imshow("image", image);
    Canny(image, result, 120, 200);
    namedWindow("Canny");
    imshow("Canny", result);    
    vector<Vec4f> li;       //若此处没有检查到直线则之后使用li会出错
    HoughLinesP(result, li, 1, PI/180, 180, 100, 20);
    vector<Vec4f>::iterator it = li.begin();
    for (;it != li.end();++it)
    {
        Point ptr1((*it)[0], (*it)[1]);
        Point ptr2((*it)[2], (*it)[3]);
        line(image, ptr1, ptr2, Scalar(255));
    }
    namedWindow("HoughP");
    imshow("HoughP", image);
    int n = 0;
    cv::line(image, cv::Point(li[n][0], li[n][1]), cv::Point(li[n][2], li[n][3]), cv::Scalar(255), 5);
    cv::Mat oneline(image.size(), CV_8U, cv::Scalar(0));
    cv::line(oneline, cv::Point(li[n][0], li[n][1]), cv::Point(li[n][2], li[n][3]), cv::Scalar(255), 5);
    cv::bitwise_and(result, oneline, oneline);//按位与
    cv::Mat onelineInv;
    cv::threshold(oneline, onelineInv, 128, 255, cv::THRESH_BINARY_INV);//反转图像
    cv::namedWindow("One line");
    cv::imshow("One line", onelineInv);
    vector<Point> points;
    for (int y = 0;y < oneline.rows;y++)
    {
        uchar *ptr = oneline.ptr<uchar>(y);
        for (int x = 0;x < oneline.cols;++x)
        {
            if (ptr[x])
            {
                points.push_back(Point(x, y));
            }
        }
    }
    Vec4f line;
    fitLine(points, line, DIST_L2, 0, 0.01, 0.01);//寻找直线
    int x0 = line[2];
    int y0 = line[3];
    int x1 = x0 - 200 * line[0];
    int y1 = y0 - 200 * line[1];
    image = imread("D:/round.jpg", 0);
    cv::line(image, Point(x0, y0), Point(x1, y1), Scalar(255), 1);
    namedWindow("imageline");
    imshow("imageline", image);
    waitKey(0);
    return 0;
}
  
  

void fitLine( InputArray points, OutputArray line, int distType, double param, double reps, double aeps );
参数详解:
第一个参数: 存储点序列
第二个参数: line中存储返回值
二维空间时: line[0–3] 分别为 (vx,vy, x0,y0)
其中 vx, vy 是正规化之后的斜率向量。 x0,y0 是直线经过的点。
第三,distType
拟合算法,其中 CV_DIST_L2 就是平常的最小二乘法
dist_type=CV_DIST_L2 (L2): ρ(r)=r2/2 (最简单和最快的最小二乘法)
dist_type=CV_DIST_L1 (L1): ρ(r)=r
dist_type=CV_DIST_L12 (L1-L2): ρ(r)=2•[sqrt(1+r2/2) - 1]
dist_type=CV_DIST_FAIR (Fair): ρ(r)=C2•[r/C - log(1 + r/C)], C=1.3998
dist_type=CV_DIST_WELSCH (Welsch): ρ(r)=C2/2•[1 - exp(-(r/C)2)], C=2.9846
dist_type=CV_DIST_HUBER (Huber): ρ(r)= r2/2, if r < C C•(r-C/2), otherwise; C=1.345
第四,第五参数第六参数:推荐值是 0, 0.01, 0.01, 三维空间时: line[0–5] 分别是 (vx, vy, vz,x0, y0,z0)

fitEllipse可以用来绘制椭圆。

猜你喜欢

转载自blog.csdn.net/a839766550/article/details/78324470