QT开发OPENCV和串口程序

1、绪论


随着QT的广泛应用,QT的优点逐步显现,可移植性好,和C良好的兼容性,都足以和VS的WPF媲美,随着国际竞争的加大,相信QT可能在国内会有更加广泛的前景。本文以QT为基础,结合OPENCV,串口通信,实现了一个基于QT的可以在linux上运行的实时温度测量显示系统。
在这里插入图片描述

2、QT版本

一开始采用QT5.12,用了不久就发现5.12 与我的UBUNTU16.04兼容性很差,不停地死机,只要打开QTCreator,15分钟可以死一次,真的没办法干活,都想放弃了,后来想想,还是时下其他版本,先用qt自带的maintenancetool将原来的5.12删除掉,然后安装了qt-opensource-linux-x64-5.9.7.run,神奇的事情发生了,非常稳定,在完成本案例开发前,竟然从没死机过了。

3、安装OPENCV4.1.0

opencv安装的坑很多,尤其跟QT联合开发的时候。经过几次的测试,发现还是老老实实的按照以下流程安装。
(1) 下载opencv-4.1.0.tar.gz,然后解压:

tar -zxvf opencv-4.1.0.tar.gz

(2)安装前的准备

sudo apt-get install build-essential cmake unzip pkg-config
sudo apt-get install libjpeg-dev libpng-dev libtiff-dev
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
sudo apt-get install libxvidcore-dev libx264-dev
sudo apt-get install libgtk-3-dev
sudo apt-get install libatlas-base-dev gfortran
sudo apt-get install python3-dev

(3)安装过程
然后进入到解压的目录,执行

```bash
mkdir build 
cmake ..
make -j4
sudo make install
sudo gedit /etc/ld.so.conf.d/opencv.conf
加入/usr/local/lib
sudo ldconfig

要注意的是,在安装的时候,可能那个ippicv下载不动了,可以先下载下来,再把3rdparty下的ippicv目录中的makefile 修改成 file:/home/xxxx/
(4)QT测试
在QT的pro文件中加入

INCLUDEPATH += -I /usr/local/include/opencv4/
DEPENDPATH += -I /usr/local/include/opencv4/

LIBS += -L /home/xxx/opencv-4.1.0/build/lib/ -lopencv_videoio
LIBS += -L /home/xxx/opencv-4.1.0/build/lib/ -lopencv_video
LIBS += -L /home/xxx/opencv-4.1.0/build/lib/ -lopencv_stitching
LIBS += -L /home/xxx/opencv-4.1.0/build/lib/ -lopencv_photo
LIBS += -L /home/xxx/opencv-4.1.0/build/lib/ -lopencv_objdetect
LIBS += -L /home/xxx/opencv-4.1.0/build/lib/ -lopencv_ml
LIBS += -L /home/xxx/opencv-4.1.0/build/lib/ -lopencv_imgproc
LIBS += -L /home/xxx/opencv-4.1.0/build/lib/ -lopencv_imgcodecs
LIBS += -L /home/xxx/opencv-4.1.0/build/lib/ -lopencv_highgui
LIBS += -L /home/xxx/opencv-4.1.0/build/lib/ -lopencv_gapi
LIBS += -L /home/xxx/opencv-4.1.0/build/lib/ -lopencv_flann
LIBS += -L /home/xxx/opencv-4.1.0/build/lib/ -lopencv_features2d
LIBS += -L /home/xxx/opencv-4.1.0/build/lib/ -lopencv_dnn
LIBS += -L /home/xxx/opencv-4.1.0/build/lib/ -lopencv_core
LIBS += -L /home/xxx/opencv-4.1.0/build/lib/ -lopencv_calib3d

然后,可以用下面的代码测试:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QColor>
#include <QQuickView>
#include "opencv2/core/cvdef.h"
#include "opencv2/core/hal/interface.h"
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/opencv.hpp"
#include "qmltest.h"
#include "showimage.h"

int main(int argc, char *argv[])
{
    cv::Mat image = cv::imread("/home/xxx/kkk.jpg", cv::IMREAD_COLOR);
    cv::imshow("mytestcv",image);
    cv::waitKey(0);
    
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);

    engine.load(url);

    return app.exec();

4、串口驱动

我采用了QT自带的QSerialPort ,具体如下:

class QmlTest : public QObject
{
    Q_OBJECT
    QSerialPort * m_serialPort;
    QString m_strPortName;
    QString m_strBaudrate;
    QTimer*  m_qtTimer;
    QByteArray m_recvBuffer;

public:
    explicit QmlTest(QObject *parent = nullptr);
    ~QmlTest();

signals:
    void dataReceived(const QString &strrecvd, const QByteArray& recvbuffer);

public slots:
    QStringList getSerialPorts();
    void setPortName(const QString &strPortName);
    void setBaudrate(const QString &strBaund);
    void open();
    void receiveInfo();
    void delayrecv();
};
#include "qmltest.h"

QmlTest::QmlTest(QObject *parent) : QObject(parent)
{
    m_serialPort = new QSerialPort();
    m_qtTimer = new QTimer();
    m_strPortName="";
}

QmlTest::~QmlTest()
{
    if (m_serialPort->isOpen())
    {
        m_serialPort->clear();
        m_serialPort->close();
    }
    delete m_serialPort;
    delete m_qtTimer;
}

QStringList QmlTest::getSerialPorts()
{
    QStringList m_serialPortName;
    foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
    {
        m_serialPortName << info.portName();
    }

    return m_serialPortName;
}

void QmlTest::setPortName(const QString &strPortName)
{
    m_strPortName = strPortName;
    qDebug("PortName: %s\n", strPortName.toStdString().data());

}

void QmlTest::setBaudrate(const QString &strBaud)
{
    m_strBaudrate = strBaud;
    qDebug("Baudrate: %s\n", strBaud.toStdString().data());

}

void QmlTest::open()
{
    if (m_serialPort->isOpen())
    {
        m_serialPort->clear();
        m_serialPort->close();
        qDebug("%s open failed!\n", m_strPortName.toStdString().data());
    }

    m_serialPort->setPortName(m_strPortName);
    m_serialPort->setReadBufferSize(1024);

    if (!m_serialPort->open(QIODevice::ReadWrite))
    {
        qDebug("%s open failed!\n", m_strPortName.toStdString().data());
    }

    m_serialPort->setBaudRate(QSerialPort::Baud115200,QSerialPort::AllDirections);//设置波特率和读写方向
    m_serialPort->setDataBits(QSerialPort::Data8);		//数据位为8位
    m_serialPort->setFlowControl(QSerialPort::NoFlowControl);//无流控制
    m_serialPort->setParity(QSerialPort::NoParity);	//无校验位
    m_serialPort->setStopBits(QSerialPort::OneStop); //一位停止位

    connect(m_serialPort,SIGNAL(readyRead()),this,SLOT(delayrecv()));
    connect(m_qtTimer, SIGNAL(timeout()), this, SLOT(receiveInfo()));

}

void QmlTest::receiveInfo()
{
    m_qtTimer->stop();
    qDebug("receive size:%d\n", m_recvBuffer.size());
    //qDebug("receive info:%s\n", m_recvBuffer.toStdString().data());
    QString strRecv="";
    //strRecv=QString::fromStdString(m_recvBuffer.toStdString());

    emit dataReceived(strRecv, m_recvBuffer);

    m_recvBuffer.clear();
}

void QmlTest::delayrecv()
{
    m_qtTimer->start(100);
    m_recvBuffer.append(m_serialPort->readAll());
}

数据的显示:

class ShowImage : public QObject
{
    Q_OBJECT

public:
    explicit ShowImage(QObject *parent = nullptr);
    ImageProvider *m_pImgProvider;
    QImage  MattoQImage(Mat cvImg);
    Mat Array2Mat(int a[]);

public slots:
    void generateIRImage(const QByteArray& recvbuffer);
};

Mat ShowImage::Array2Mat(int a[])
{
    Mat M(24, 32, CV_8UC1);
    for (int i = 0; i < M.rows; ++i)
    {
        uchar *p = M.ptr<uchar>(i);
        for (int j = 0; j < M.cols; ++j)
            p[j] = static_cast<uchar>(a[i*32 + j]);
    }

    return M;
}

void ShowImage::generateIRImage(const QByteArray& recvbuffer)
{
    qDebug("recv: %x, %x\n", recvbuffer.at(0), recvbuffer.at(1));

    if(recvbuffer.size()<1543) return;
    if (recvbuffer.data()[0] != 0x5A && recvbuffer.data()[1] != 0x5A) return;

    long mean = 0;
    long max = 0;
    long min = 0;
    int maxi = 0;
    short tempdata[768];

    for (int i = 0; i < 768; i++)
    {
        tempdata[i] = static_cast<short>(recvbuffer.data()[2 * i + 5] * 256 + recvbuffer.data()[2 * i + 4]);
    }

    for (int i = 0; i < 768; i++)
    {
        mean += tempdata[i];
        if (tempdata[i] > max)
        {
            max = tempdata[i];
            maxi = i;
        }
        if (tempdata[i] < min) min = tempdata[i];
    }

    mean = mean / 768;

    long scale = 0;
    if ((max - mean) > (mean - min))
        scale = max - mean;
    else scale = mean - min;

    int imgdata[768];
    for (int j = 0; j < 768; j++)
    {
        imgdata[j] = static_cast<int>((tempdata[j] - mean)*255.0 / scale);
    }
    Mat mtir = Array2Mat(imgdata);

    m_pImgProvider->img = MattoQImage(mtir);
    emit callQmlRefeshImg();

    qDebug()<<"setIRImage";
    qDebug("Max Temp: %f", max/100.0);
}

void ShowImage::setImage()
{
    capture>>src_frame;
    m_pImgProvider->img = MattoQImage(src_frame);
    emit callQmlRefeshImg();
    qDebug()<<"setImage";
}

QImage ShowImage::MattoQImage(Mat cvImg)
{
    QImage qImg;

    if(cvImg.channels()==3)
    {
        cvtColor(cvImg,cvImg,CV_BGR2RGB);
        qImg =QImage((const unsigned char*)(cvImg.data),
                        cvImg.cols, cvImg.rows,
                        cvImg.cols*cvImg.channels(),
                        QImage::Format_RGB888);
    }
    else if(cvImg.channels()==1)
    {
        qImg =QImage((const unsigned char*)(cvImg.data),
                            cvImg.cols,cvImg.rows,
                            cvImg.cols*cvImg.channels(),
                            QImage::Format_Indexed8);
    }
    else
    {
        qImg =QImage((const unsigned char*)(cvImg.data),
                     cvImg.cols,cvImg.rows,
                     cvImg.cols*cvImg.channels(),
                     QImage::Format_RGB888);
    }

    return qImg;
}

5、QML和C的交互

在开发过程中,感觉到真正的强大的,是QT的QML和C的交互能力,用一个形象的比喻,就像用C++直接跟HTML通信一样,另外,QML的3维处理能力非同一般,科幻片上的那些超炫界面,轻而易举.废话少说,来点实际的:
(1)c++ ->Qml
主要通过集成QOBJECT,然后注册
如.qmlRegisterType(“an.Qt.QmlTest”,1,0,“QmlTest”);
这样,就可以在QML中声明为对象了.
或者engine.rootContext()->setContextProperty(“serial”, &serial);

(2)QML->C++
在qml中就可以直接用serial的相关函数了.
(3) 消息和槽
slots和signal,通过connect,简单不失灵活,可以完成太多的花样,让我这个老MFC程序员,感触颇深.就不细细说来了,都可以开专题的.

欢迎大家交流~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值