用QT实现线性拟合图像显示

一.实现绘图

QT实现绘图需要QCustomPlot类这里提供QCustomPlot官网地址:Qt Plotting Widget QCustomPlot - Introduction

下载好类后将qcustomplot.cpp和qcustomplot.h两个文件加入到工程中

 添加完成后可以在工程目录中看到这两个文件,并在widget.h中加入代码

#include "qcustomplot.h"

然后可以在ui编辑页面绘制一个Widget图框,右击选择提升为

然后在弹出的对话框,在提升为类名那里输入QCustomPlot,然后头文件那里会自动填充为qcustomplot.h,单击添加,最后单击提升。

 可以回到ui界面,看到现在widget已经变成了QCustomPlot类

在对象列表里更改widget为 customPlot

 如果Qt版本在5.0以上,需要在.pro文件中的QT变量加上printsupport

再加上两个Pushbutton,调整好customPlot的大小,简单的ui界面就设计完成了

 在ui文件中右击绘制散点图按钮,选择转到槽,选择clicked(),加入以下代码,可以测试下功能

void Widget::on_pushButton_clicked()
{
    //绘图前先清除
    ui->customPlot->clearGraphs();//清除图像,函数接受一个int类型的返回值,返回删除的graphs数。
    ui->customPlot->legend->setVisible(false);//设置图例为不可见
    ui->customPlot->replot();//重新绘制

    QCPAxis *xAxis = ui->customPlot->xAxis;//x轴
    QCPAxis *yAxis = ui->customPlot->yAxis;//y轴

    ui->customPlot->addGraph(xAxis,yAxis);//设置图像坐标轴
    QVector<double> x(16), y(16); //初始化向量x和y
    x = {119,116.5,114,111.5,109,106.5,104,101.5,99,96.5,94,91.5,89,86.5,84,81.5};//x,y的值可以随意更改,改为用户需要得到
    y = {9.8,9.2,8.8,8.7,8.9,8.4,8.8,9.1,9.5,10,9.8,10.5,10.4,9.3,8.4,7.3};
    ui->customPlot->graph(0)->setData(x, y);
    ui->customPlot->graph(0)->setName("散点图");// 设置图例名称
    ui->customPlot->legend->setBrush(QColor(255,255,255,0));//设置图例背景

    // 为坐标轴添加标签
    xAxis->setLabel("X轴");
    yAxis->setLabel("Y轴");

    // 设置坐标轴的范围,以看到所有数据
    ui->customPlot->graph(0)->rescaleAxes();
    ui->customPlot->legend->setVisible(true); // 显示图例
    ui->customPlot->graph(0)->setLineStyle((QCPGraph::LineStyle)0);  // 线段风格(QCPGraph::LineStyle)i
    ui->customPlot->graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle,QColor(qBlue(200)),5));//设置散点形状

    // 支持鼠标拖拽轴的范围、滚动缩放轴的范围,左键点选图层(每条曲线独占一个图层)
    ui->customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);

    // 重画图像
    ui->customPlot->replot();
}

 可以参考

wendy_ya文章 QCustomPlot基础教程学习绘图更多的操作。

二.实现拟合(最小二乘法)

1.Eigen矩阵运算库

 到Eigen官网下载Eigen类,解压后保存到QT安装目录,并修改文件夹名称为eigen_3_4_0

再到工程文件中的.pro文件中加入代码,路径为你自己eigen_3_4_0的路径

INCLUDEPATH += D:\Qt\eigen_3_4_0

 添加头文件

#include <Eigen/Dense>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <Eigen/Eigenvalues>

2.拟合函数

右击Pushbutton2,建立槽函数,在槽函数中加入以下代码

void Widget::on_pushButton_2_clicked()
{
    const int N = 6;
    //参考C++最小二乘拟合 (高阶最小二乘拟合)(附C++代码)作者:koko_TT
    QVector<double> x(16), y(16); //初始化向量x和y
    x = {119,116.5,114,111.5,109,106.5,104,101.5,99,96.5,94,91.5,89,86.5,84,81.5};//x,y的值可以随意更改,改为用户需要得到
    y = {9.8,9.2,8.8,8.7,8.9,8.4,8.8,9.1,9.5,10,9.8,10.5,10.4,9.3,8.4,7.3};
    Eigen::MatrixXd A(x.size(), N + 1);
    for (unsigned int i = 0; i < x.size(); ++i) {  // 遍历所有点

        for (int n = N, dex = 0; n >= 1; --n, ++dex) {  // 遍历N到1阶
            A(i, dex) = pow(x[i], n);
        }

        A(i, N) = 1;  //
    }
    // 创建B矩阵
    Eigen::MatrixXd B(y.size(), 1);

    for (unsigned int i = 0; i < y.size(); ++i) {
        B(i, 0) = y[i];
    }

    Eigen::MatrixXd W;
    W = (A.transpose() * A).inverse() * A.transpose() * B;
    double w[N+1];
    for(int i = 0;i <= 6;i++)
    {
        w[i] = W(i,0);
    }
    QVector<double> x_fit(16), y_fit(16); //初始化向量x_fit和y_fit
    for (int i=0; i<16; ++i)
    {
        x_fit[i] = x[i];
        for (int n = N; n >= 1; --n) // 遍历N到1阶
        {
            y_fit[i] = y_fit[i] + w[6-n]*pow(x[i], n);
        }
        y_fit[i] = y_fit[i]+w[6];
    }

    //绘图前先清除
    ui->customPlot->clearGraphs();//清除图像,函数接受一个int类型的返回值,返回删除的graphs数。
    ui->customPlot->legend->setVisible(false);//设置图例为不可见
    ui->customPlot->replot();//重新绘制

    QCPAxis *xAxis = ui->customPlot->xAxis;//x轴
    QCPAxis *yAxis = ui->customPlot->yAxis;//y轴

    // 为坐标轴添加标签
    xAxis->setLabel("X轴");
    yAxis->setLabel("Y轴");
    ui->customPlot->addGraph(xAxis,yAxis);//设置图像坐标轴
    ui->customPlot->graph(0)->setData(x, y);
    ui->customPlot->graph(0)->setName("散点图");// 设置图例名称
    ui->customPlot->legend->setBrush(QColor(255,255,255,0));//设置图例背景

    // 设置坐标轴的范围,以看到所有数据
    ui->customPlot->graph(0)->rescaleAxes();
    ui->customPlot->legend->setVisible(true); // 显示图例
    ui->customPlot->graph(0)->setLineStyle((QCPGraph::LineStyle)0);  // 线段风格(QCPGraph::LineStyle)i
    ui->customPlot->graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle,QColor(qBlue(200)),5));//设置散点形状

    ui->customPlot->addGraph(xAxis,yAxis);
    ui->customPlot->graph(1)->setData(x_fit, y_fit);
    ui->customPlot->graph(1)->setName("曲线拟合后");// 设置图例名称
    ui->customPlot->legend->setVisible(true); // 显示图例
    // 设置坐标轴的范围,以看到所有数据
    ui->customPlot->graph(1)->rescaleAxes(true);
    ui->customPlot->graph(1)->setPen(QPen(QColor(255, 0, 0)));       // 设置画笔
    ui->customPlot->graph(1)->setLineStyle((QCPGraph::LineStyle)1);  // 线段风格(QCPGraph::LineStyle)i
    // 支持鼠标拖拽轴的范围、滚动缩放轴的范围,左键点选图层(每条曲线独占一个图层)
    ui->customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
    // 重画图像
    ui->customPlot->replot();
}

 关于最小二乘法可以参考

koko_TT
C++最小二乘拟合 (高阶最小二乘拟合)这篇文章,写的很详细

三.运行效果

1.无操作界面

 2.绘制散点图

3.绘制拟合图

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值