OpenCV(三十七):拟合直线、三角形和圆形

1.点集拟合的含义

       点集拟合是一种通过拟合函数或曲线来近似描述给定离散数据点的技术,在点集拟合中,可以使用不同的函数或曲线拟合方法来拟合直线、三角形和圆形。

直线拟合:对于给定的二维数据点集合,可以使用最小二乘法来拟合一条直线。

三角形拟合: 对于给定的二维或三维数据点集合,可以使用三角形拟合方法来找到尽可能逼近数据点的最佳三角形。

圆形拟合: 对于给定的二维数据点集合,可以使用圆形拟合方法来找到与数据点分布最佳匹配的圆。

2.拟合直线的函数fitLine()

void cv::fitLine ( InputArray   points,

OutputArray line,

int  distType,

double   param,

double    reps,

double     aeps

)

  • points:输入待拟合直线的2D或者3D点集。
  • line:输出描述直线的参数,2D点集描述参数为Vec4f类型,3D点集描述参数为Vec6f类型distType:M-estimator算法使用的距离类型标志。
  • param:某些类型距离的数值参数(C)。如果数值为0,则自动选择最佳值。
  • reps: 坐标原点与直线之间的距离精度,数值0表示选择自适应参数,一般常选择0.01
  • aeps:直线角度精度,数值0表示选择自适应参数,一般常选择0.01。

距离类型选择标志

示例代码:

 //直线拟合
    Vec4f lines;//存放拟合后的直线
    vector<Point2f> point;//待检测是否存在直线的所有点
    const static float Points[20][2]={
            {0.0f,0.0f},{10.0f,11.0f},{21.0f,20.0f},{30.0f,30.0f},
            {40.0f,42.0f},{50.0f,50.0f},{60.0f,60.0f},{70.0f,70.0f},
            {80.0f,80.0f},{90.0f,92.0f},{100.0f,100.0f},{110.0f,110.0f},
            {120.0f,120.0f},{136.0f,130.0f},{138.0f,140.0f},{150.0f,150.0f},
            {160.0f,163.0f},{175.0f,170.0f},{181.0f,180.0f},{200.0f,190.0f},
    };
    //将所有点存放在vector中,用于输入函数中
    for(int i=0;i<20;i++){
        point.push_back(Point2f(Points[i][0],Points[i][1]));
    }
    //参数设置
    double param=0;//距离模型中的数值参数C
    double reps=0.01;//坐标原点与直线之间的距离精度
    double aeps=0.01;//角度精度
    fitLine(point,lines,DIST_L1,0,0.01,0.01);
    double k=lines[1]/lines[0];//直线斜率
    ostringstream ss;
    ss<<"直线效率:"<<k<<endl;
    ss<<"直线上一点坐标x:"<<lines[2]<<",y:"<<lines[3]<<endl;
    ss<<"直线解析式:y="<<k<<"(x-"<<lines[2]<<")+"<<lines[3]<<endl;
    LOGD("%s",ss.str().c_str());

运行结果:

3.拟合三角形的函数 minEnclosingTriangle()

double cv::minEnclosingTriangle ( InputArray points,OutputArray triangle)

  • points:待寻找包围三角形的2D点集
  • triangle:拟合出的三角形三个顶点坐标

4.拟合三角形的函数 minEnclosingTriangle()

minEnclosingCircle()

void cv::minEnclosingCircle ( InputArray points,

Point2f &center,

float &radius

  • points:待寻找包围圆形的2D点集
  • center:圆形的圆心。
  • radius:圆形的半径

拟合三角形和圆形的示例代码:

//点集拟合
void Point_set_fitting(){
  
    Mat img(500,500,CV_8UC3,Scalar::all(0));
    RNG &rng=theRNG();

    int i,count=rng.uniform(1,101);
    vector<Point> points;
    //生成随机点
    for(i=0;i<count;i++){
            Point  pt;
            pt.x=rng.uniform(img.cols/4,img.cols*3/4);
            pt.y=rng.uniform(img.rows/4,img.rows*3/4);
            points.push_back(pt);
    }
    //寻找包围点集的三角形
    vector<Point2f> triangle;
    double area= minEnclosingTriangle(points,triangle);
    //寻找包围点集的圆形
    Point2f center;
    float radius=0;
    minEnclosingCircle(points,center,radius);

    //创建两个图片用于输出结果
    img=Scalar ::all(0);
    Mat img2;
    img.copyTo(img2);
    //在图像中绘制坐标点
    for(i=0;i<count;i++){
        circle(img,points[i],3,Scalar(255,255,255),FILLED,LINE_AA);
        circle(img2,points[i],3,Scalar(255,255,255),FILLED,LINE_AA);
    }
    //绘制三角形
    for(i=0;i<3;i++){
        if(i==2){
            line(img,triangle[i],triangle[0],Scalar(255,255,255),1,16);
            break;
        }
        line(img,triangle[i],triangle[i+1],Scalar(255,255,255),1,16);
    }
    //绘制圆形
    circle(img2,center, cvRound(radius),Scalar(255,255,255),1,LINE_AA);

    //显示图像
    imwrite("/sdcard/DCIM/img.png",img);
    imwrite("/sdcard/DCIM/img2.png",img2);

}

三角形拟合的结果:

圆形拟合的结果:

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 C 语言中实现灯条的圆形拟合可以使用 RANSAC 算法。RANSAC 算法是一种随机抽样一致性算法,可以用来消除噪声并估计数学模型参数。首先,从灯条数据中随机选择 3 个点,然后计算这 3 个点所在的方程。接下来,遍历所有点,如果该点与的距离小于阈值,则将该点视为内点。最后,对于所有内点,重新计算的方程。这个过程重复进行直到找到最终的圆形拟合。 下面是一个简单的示例代码,实现了用 RANSAC 算法拟合灯条圆形的过程: ``` #include<stdio.h> #include<stdlib.h> #include<math.h> #define N 1000 // 灯条数据点的数量 #define THRESHOLD 0.1 // 内点阈值 #define ITERS 10000 // RANSAC 迭代次数 // 点结构体 struct point { double x, y; }; // 结构体 struct circle { double x, y, r; }; // 计算的方程 void calc_circle(struct point p1, struct point p2, struct point p3, struct circle *c) { double x1 = p1.x, y1 = p1.y; double x2 = p2.x, y2 = p2.y; double x3 = p3.x, y3 = p3.y; double a = x1*(y2-y3) + x2*(y3-y1) + x3*(y1-y2); double b = x1*x1 + y1*y1 + x2*x2 + y2*y2 + x3*x3 + y3*y3; double c = x1*(x3-x ### 回答2: 要用C语言写一个灯条的圆形拟合,可以使用OpenCV库来实现。 首先,需要引入OpenCV库: ```c #include <opencv2/opencv.hpp> using namespace cv; ``` 然后,读取图像并将其转换为灰度图像: ```c Mat img = imread("image.jpg"); Mat gray; cvtColor(img, gray, COLOR_BGR2GRAY); ``` 接下来,进行二值化处理,以便找到灯条的轮廓: ```c Mat binary; threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU); ``` 然后,对图像进行形态学操作,以去除噪点并连接断开的轮廓: ```c Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3)); morphologyEx(binary, binary, MORPH_OPEN, kernel); ``` 接下来,使用腐蚀和膨胀操作来进一步改善轮廓的质量: ```c erode(binary, binary, kernel, Point(-1, -1), 2); dilate(binary, binary, kernel, Point(-1, -1), 2); ``` 然后,使用轮廓提取算法(如findContours函数)来找到图像中的所有轮廓: ```c vector<vector<Point>> contours; vector<Vec4i> hierarchy; findContours(binary, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); ``` 接下来,通过遍历所有轮廓,找到最佳拟合圆形: ```c for (int i = 0; i < contours.size(); i++) { if (contours[i].size() > 5) { RotatedRect rect = fitEllipse(contours[i]); // 对拟合出的圆形进行进一步处理,比如筛选最佳圆形等 // ... } } ``` 最后,你可以根据需要对找到的圆形做进一步的处理,比如标记出来或计算心和半径等。 以上是使用C语言编写灯条圆形拟合的基本步骤,具体的细节和算法选择可以根据实际需求进行调整和优化。 ### 回答3: 在C语言中实现灯条的圆形拟合可以使用 数学库来帮助完成。以下是一个简单的示例代码,用于演示如何使用C语言实现灯条的圆形拟合。 ```c #include <stdio.h> #include <math.h> // 定义一个灯条的结构体,包含x坐标、y坐标和半径 typedef struct { double x; double y; double radius; } LightBar; // 计算两个点之间的距离 double calculateDistance(double x1, double y1, double x2, double y2) { return sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2)); } // 利用最小二乘法拟合圆形 void fitCircle(LightBar* lightBarArr, int num) { double sumX = 0.0, sumY = 0.0, sumX2 = 0.0, sumY2 = 0.0; double sumXY = 0.0, sumX3 = 0.0, sumY3 = 0.0, sumX2Y = 0.0, sumXY2 = 0.0; for (int i = 0; i < num; i++) { double x = lightBarArr[i].x; double y = lightBarArr[i].y; sumX += x; sumY += y; sumX2 += x * x; sumY2 += y * y; sumXY += x * y; sumX3 += x * x * x; sumY3 += y * y * y; sumX2Y += x * x * y; sumXY2 += x * y * y; } double A = sumX2 - sumX * sumX / num; double B = sumXY - sumX * sumY / num; double C = sumY2 - sumY * sumY / num; double D = 0.5 * (sumX3 + sumXY2 - (sumX2 + sumY2) * sumX / num); double E = 0.5 * (sumY3 + sumX2Y - (sumX2 + sumY2) * sumY / num); // 心坐标为(h,k),半径为r double h = (D * C - B * E) / (A * C - B * B); double k = (A * E - B * D) / (A * C - B * B); double r = sqrt((sumX2 - 2 * sumX * h + num * h * h + sumY2 - 2 * sumY * k + num * k * k) / num); printf("拟合得到的心坐标为:(%lf, %lf),半径为:%lf\n", h, k, r); } int main() { // 构造一个灯条数组 LightBar lightBars[3] = {{1, 2, 0}, {3, 4, 0}, {5, 6, 0}}; // 调用拟合函数 fitCircle(lightBars, 3); return 0; } ``` 以上示例代码实现了对3个灯条进行圆形拟合。在实际应用中,我们可以根据具体情况修改代码,适应不同数量的灯条数据进行圆形拟合拟合得到的心坐标和半径可以用于后续处理和应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值