QT实现三点求圆心

前言

最近在搞机械臂的研究,其中涉及到的一个问题就是对于坐标系的确定;
现在使用的方案就是将机械臂放在下面,摄像头通过支架架在机械臂正上方40cm左右的位置,此时需要机械臂确定好坐标位置,通过原点坐标进而求出每一个舵机该转动的角度。
随着每一次系统的移动,坐标原点的位置可能会发生偏差,因此需要设计一种方案来确定坐标原点的位置,本次的设计方案为:
操作机械臂在平面上画一个同心圆。然后在同心圆内找到任意三个点(尽量分散一点,有利于减少误差)。


提示:以下是本篇文章正文内容,下面案例可供参考

一、操控机械臂画圆

这个步骤很简单的,可以让机械臂先摆正。然后动手画一个圆弧。或者是下位机控制机械臂握住马克笔,然后转半圈。

二、获取关键点坐标

当我们找到这三个点以后,此时可以控制摄像头进行识别。我的方案是通过写一个色块识别的程序,然后讲物块放在上面画的同心圆的三个任一点上面,此时,可以动手记录下来三个点的坐标。

色块识别代码(示例):

void imgThread::startVideo()
{
    int i;
    int x,y;


    Mat Gray;   //灰度图
    Mat Otus;   //黑白图
    Mat Hsls;   //hsl格式图片

    Mat Frame;  //原图
    Mat dstImg;
    Mat dstImg2;

//    int h_min=156;//红色
//    int s_min=97;
//    int v_min=159;
//    int h_max=180;
//    int s_max=255;
//    int v_max=255;
    int h_min=100;//蓝色
    int s_min=76;
    int v_min=76;
    int h_max=124;
    int s_max=255;
    int v_max=255;
//    int h_min=26;//黄色
//    int s_min=160;
//    int v_min=155;
//    int h_max=34;
//    int s_max=255;
//    int v_max=255;
    VideoCapture capture(1 );    //读取外部摄像头
    capture.set(CAP_PROP_FPS, 120);//帧率 帧/秒
    //stopped = false;
    qDebug()<<"Frame.cols:"<<Frame.cols;//打印列位置
    qDebug()<<"Frame.rows:"<<Frame.rows;//打印行位置
    while(1)
    {
         if(!stopped)
        {
            capture >> Frame;//将视频帧读取到Mat矩阵
            dstImg = Frame(Range(20, 380), Range(135, 540));//裁剪
             Mat textimg=dstImg.clone();
             cv::cvtColor(dstImg,dstImg,COLOR_BGR2HSV);
             Scalar hsv_min(h_min,s_min,v_min);
             Scalar hsv_max(h_max,s_max,v_max);
             Mat dstimg=Mat::zeros(dstImg.size(),CV_8U);
              inRange(dstImg,hsv_min,hsv_max,dstimg);
             Mat element=getStructuringElement(MORPH_RECT,Size(5,5));
             morphologyEx(dstimg,dstimg,MORPH_DILATE,element,Point(-1,-1),4);
             Otus=dstimg.clone();
            getxy(Otus,x,y);    //寻找色块位置
            if(x!=-1||y!=-1)  //有位置才发
            {
                cv::circle(Otus,center, 10, Scalar(120, 120, 120), -1);
                emit sendxy(x,y);//发送位置信息
            }
            else
            {
                emit sendxy(-2,-2);    //没找到位置。
            }
            emit inDisplay(
                        QPixmap::fromImage(
                            QImage(
                                dstImg.data,
                                dstImg.cols,
                                dstImg.rows,
                                dstImg.step,
                                QImage::Format_RGB888)
                            .rgbSwapped()));
              //qDebug()<<"i="<<i++;
            emit outDisplay(
                        QPixmap::fromImage(
                            QImage(
                                Otus.data,
                                Otus.cols,
                                Otus.rows,
                                Otus.step,//访问图片像素
                                QImage::Format_Grayscale8)
                            .rgbSwapped()));
             }

     }
}

上面的那个是色块识别的核心代码,可以通过这个来找到物块的位置。

三、获取圆心

获取圆心的计算可以找这个大佬
文章链接
然后就是代码部分了;
作为一个刚入门的程序小白,自己就动手写了一个简单的程序来得到圆心的坐标以及半径。
最终的qt界面
将需要的内容放里面。
接下来对大家做一个介绍
寻找圆心算法:


QPointF Widget::tcircle(QPointF pt1, QPointF pt2, QPointF pt3, double &radius)
    {
        double x1 = pt1.x(), x2 = pt2.x(), x3 = pt3.x();
        double y1 = pt1.y(), y2 = pt2.y(), y3 = pt3.y();
        double a = x1 - x2;
        double b = y1 - y2;
        double c = x1 - x3;
        double d = y1 - y3;
        double e = ((x1 * x1 - x2 * x2) + (y1 * y1 - y2 * y2)) / 2.0;
        double f = ((x1 * x1 - x3 * x3) + (y1 * y1 - y3 * y3)) / 2.0;
        double det = b * c - a * d;
        if( fabs(det) < 1e-5)
        {
            radius = -1;
            return QPointF(0,0);
        }

        double x0 = -(d * e - b * f) / det;
        double y0 = -(a * f - c * e) / det;
        radius = hypot(x1 - x0, y1 - y0);
        return QPointF(x0, y0);
    }

计算并显示:

void Widget::on_button_0_clicked()
{
    pf0.setX(ui->Spinbox0->value());
    pf0.setY(ui->Spinbox1->value());
    pf1.setX(ui->Spinbox2->value());
    pf1.setY(ui->Spinbox3->value());
    pf2.setX(ui->Spinbox4->value());
    pf2.setY(ui->Spinbox5->value());
    pf3 = tcircle(pf0,pf1,pf2,radius);

    QString pointx = QString("中心(%1,%2) 半径%3").arg(pf3.x()).arg(pf3.y()).arg(radius);
    ui->lineEdit_4->setText(pointx);
    cout<<pf3.x()<<endl;
    cout<<pf3.y()<<endl;
    cout<<radius<<endl;
}

清除信息:

void Widget::on_button_1_clicked()
{
    pf0.setX(0);    //清除原来的信息
    pf0.setY(0);
    pf1.setX(0);
    pf1.setY(0);
    pf2.setX(0);
    pf2.setY(0);
    ui->Spinbox0->setValue(pf0.x());
    ui->Spinbox1->setValue(pf0.y());
    ui->Spinbox2->setValue(pf1.x());
    ui->Spinbox3->setValue(pf1.y());
    ui->Spinbox4->setValue(pf2.x());
    ui->Spinbox5->setValue(pf2.y());

    QString pointx = QString("请重新输入:");
    ui->lineEdit_4->setText(pointx);
}

下面是测试的图片:
在这里插入图片描述

点击清除以后:
在这里插入图片描述

总结

经过了两个小时的编写,才完成了这个小的项目,也算是对自己的能力的一个测试吧。本来感觉十几分钟就可以搞定了,结果遇到的最麻烦的事情却是语法的错误。

QString pointx = QString(“中心(%1,%2) 半径%3”).arg(pf3.x()).arg(pf3.y()).arg(radius);`

就是这部分,因为QT里面不能使用sprintf进行字符串的连接,只能使用这种方法讲字符拼起来放到文本框进行显示。

希望给需要的朋友带来一点点帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值