一开始采用QT5.12,用了不久就发现5.12 与我的UBUNTU16.04兼容性很差,不停地死机,只要打开QTCreator,15分钟可以死一次,真的没办法干活,都想放弃了,后来想想,还是时下其他版本,先用qt自带的maintenancetool将原来的5.12删除掉,然后安装了qt-opensource-linux-x64-5.9.7.run,神奇的事情发生了,非常稳定,在完成本案例开发前,竟然从没死机过了。
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
#include
#include
#include
#include
#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();
}
我采用了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;
}
在开发过程中,感觉到真正的强大的,是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程序员,感触颇深.就不细细说来了,都可以开专题的.
欢迎大家交流~