在工程项目中,开发人员经常需要对线阵传感器(如X光探测器、线阵相机等。)采集的数据实时逐帧可视化显示,即从左到右滚动显示,那么如何编写程序呢?应该面临哪些问题:
-
问题1:传感器采集速度与显示速度的匹配
线阵探测器的采集速度通常为10ms-50ms如何在这么短的时间内逐列快速显示是个问题
-
问题2:人眼分辨率和计算机分辨率
人眼可见的分辨率通常是20-30hz工控计算机的工作频率通常是60hz,探测器的达到探测器的采集速度,那么如何实时逐帧显示呢?
-
问题3:程序的实时性和帧丢失
由于传感器是实时采集的,如果程序设计不合理,会导致显示丢帧。
基于以上问题,大致有两种解决方案可以解决:
① 重写窗口显示控件
② 收集一张图片后通过QGraphicview做滚动显示
方案一代码Demo(可操作):
//qcoreplcobject.cpp#include "qcoreplcobject.h"#include <QPainter>#include <QDebug>QCorePlcObject::QCorePlcObject(QObject *parent) : QObject(parent){ m_image = QImage(800,640,QImage::Format_ARGB32); m_image.fill(QColor(Qt::white)); data_line = 0; updateNum = 0; updateMaxSpeed = 5;}void QCorePlcObject::acceptImageData(QByteArray t_data){ m_data.append(t_data); updateNum ; data_line ; if(data_line >= 200){ emit sendGetImage(); } if(updateNum >= updateMaxSpeed){ ///处理多少帧数据一次 QImage t_image((uchar*)m_data.data(),4*updateNum,640,QImage::Format_Indexed8); t_image = t_image.convertToFormat(QImage::Format_ARGB32); QImage resultImg = QImage(800,640, QImage::Format_ARGB32); for(int w = 0;w < 800;w++){
for(int h = 0;h < 640;h++){
if(w < 800-4*updateNum){
resultImg.setPixel(w,h,m_image.pixel(w+4*updateNum,h)); }else{
resultImg.setPixel(w,h,t_image.pixel(4*updateNum -(800 - w),h)); } } } m_image = resultImg.copy(0,0,resultImg.width(),resultImg.height()); emit sendImage(m_image); updateNum = 0; m_data.clear(); }}void QCorePlcObject::acceptMaxSpeed(int value){
updateMaxSpeed = value;}
//qcoreplcobject.h#ifndef QCOREPLCOBJECT_H#define QCOREPLCOBJECT_H#include <QObject>#include <QImage>class QCorePlcObject : public QObject{
Q_OBJECTpublic: explicit QCorePlcObject(QObject *parent = nullptr);signals: void sendImage(QImage); void sendGetImage();public slots: void acceptImageData(QByteArray); void acceptMaxSpeed(int);//多少帧刷新一次private: QImage m_image; int data_line;//这里记录数据线 int updateNum; int updateMaxSpeed; QByteArray m_data;};#endif // QCOREPLCOBJECT_H
//qcoreplcwidget.cpp#include "qcoreplcwidget.h"#include <QPainter>#include <QImage>QCorePlcWidget::QCorePlcWidget(QWidget *parent) : QWidget(parent){
qRegisterMetaType<QImage>("QImage"); state_a = false; state_b = false; m_QCorePlcObjectA = new QCorePlcObject(); m_QCorePlcObjectA->moveToThread(&m_threadA); connect(&m_threadA, &QThread::finished, m_QCorePlcObjectA, &QObject::deleteLater); connect(this, SIGNAL(sendImageDataA(QByteArray)), m_QCorePlcObjectA, SLOT(acceptImageData(QByteArray))); connect(this, SIGNAL(sendMaxSpeed(int)), m_QCorePlcObjectA, SLOT(acceptMaxSpeed(int))); connect(m_QCorePlcObjectA, SIGNAL(sendImage(QImage)), this, SLOT(acceptImageA(QImage))); connect(m_QCorePlcObjectA, SIGNAL(sendGetImage()), this, SIGNAL(sendGetImage())); m_threadA.start(); m_QCorePlcObjectB = new QCorePlcObject(); m_QCorePlcObjectB->moveToThread(&m_threadB); connect(&m_threadB, &QThread::finished, m_QCorePlcObjectB, &QObject::deleteLater); connect(this, SIGNAL(sendImageDataB(QByteArray)), m_QCorePlcObjectB, SLOT(acceptImageData(QByteArray))); connect(this, SIGNAL(sendMaxSpeed(int)), m_QCorePlcObjectB, SLOT(acceptMaxSpeed(int))); connect(m_QCorePlcObjectB, SIGNAL(sendImage(QImage)), this, SLOT(acceptImageB(QImage))); m_threadB.start();}QCorePlcWidget::~QCorePlcWidget(){
m_threadA.quit(); m_threadA.wait(); m_threadB.quit(); m_threadB.wait();}QImage QCorePlcWidget::getImageA(){
return m_imageA;}QImage QCorePlcWidget::getImageB(){
return m_imageB;}void QCorePlcWidget::paintEvent(QPaintEvent *event){
QPainter painter(this); painter.drawRect(0,0,this->width()-1,this->height()-1); if(!m_imageA.isNull()){
QImage timage = m_imageA.scaled(this->width()-1,this->height()-1); painter.drawPixmap(0,0,this->width()-1,this->height()-1,QPixmap::fromImage(timage)); }}void QCorePlcWidget::acceptImageA(QImage t_image){
m_imageA = t_image.convertToFormat(QImage::Format_ARGB32); m_imageA = m_imageA.mirrored(true,false); state_a = false; update();}void QCorePlcWidget::acceptImageB(QImage t_image){
m_imageB = t_image.convertToFormat(QImage::Format_ARGB32); m_imageB = m_imageB.mirrored(true,false); state_b = false;}void QCorePlcWidget::setImageDataA(QByteArray data){
emit sendImageDataA(data);//发送数据到线程 state_a = true;}void QCorePlcWidget::setMaxSpeed(int value){
emit sendMaxSpeed(value);}void QCorePlcWidget::setImageDataB(QByteArray data){
emit sendImageDataB(data);//发送数据到线程 state_b = true;}
#ifndef QCOREPLCWIDGET_H#define QCOREPLCWIDGET_H#include <QWidget>#include <QThread>#include "qcoreplcobject.h"class QCorePlcWidget : public QWidget{
Q_OBJECTpublic: explicit QCorePlcWidget(QWidget *parent = nullptr); ~QCorePlcWidget(); QImage getImageA();//获取图像 QImage getImageB();//获取图像protected: void paintEvent(QPaintEvent *event);//绘图signals: void sendImageDataA(QByteArray);//发生数据到线程 void sendImageDataB(QByteArray);//发生数据到线程 void sendMaxSpeed(int);//多少帧刷新一次 void sendGetImage();//信号private slots: void acceptImageA(QImage);//接受处理后的图片 void acceptImageB(QImage);//接受处理后的图片public slots: void setImageDataA(QByteArray);//设置图片数据 void setMaxSpeed(int);//多少帧刷新一次 void setImageDataB(QByteArray);//设置图片数据private: QCorePlcObject * m_QCorePlcObjectA;//图像处理对象 QThread m_threadA; QCorePlcObject * m_QCorePlcObjectB;//图像处理对象 QThread m_threadB; //处理结果 QImage m_imageA; QImage m_imageB; bool state_a; bool state_b;};#endif // QCOREPLCWIDGET_H
//mainwidget.h#ifndef MAINWIDGET_H#define MAINWIDGET_H#include <QWidget>#include <QTimer>namespace Ui {
class MainWidget;}class MainWidget : public QWidget{
Q_OBJECTpublic: explicit MainWidget(QWidget *parent = nullptr); ~MainWidget();private slots: void on_pushButton_clicked(); void mtimeout(); void on_horizontalSlider_valueChanged(int value); void on_horizontalSlider_2_valueChanged(int value); void on_pushButton_2_clicked(); void on_pushButton_3_clicked();private: Ui::MainWidget *ui; QTimer *m_QTimer; QByteArray dataA; QByteArray dataB; bool state; int timevalue;};#endif // MAINWIDGET_H
//mainwidget.cpp#include "mainwidget.h"#include "ui_mainwidget.h"#include <QByteArray>MainWidget::MainWidget(QWidget *parent) : QWidget(parent), ui(new Ui::MainWidget){
ui->setupUi(this); timevalue = 15; m_QTimer = new QTimer(); connect(m_QTimer,SIGNAL(timeout()),this,SLOT(mtimeout())); //初始化模拟数据 for(int i = 0;i < 4*640;i++){
dataA.append(125); } for(int i = 0;i < 4*640;i++){
dataB.append(80); } state = false;}MainWidget::~MainWidget(){
delete ui;}void MainWidget::on_pushButton_clicked(){
m_QTimer->start(timevalue);}void MainWidget::mtimeout(){
ui->widget->setImageDataA(dataA); ui->widget->setImageDataB(dataB);}void MainWidget::on_horizontalSlider_valueChanged(int value){
ui->lineEdit_1->setText(QString::number(value)); m_QTimer->stop(); timevalue = value;}void MainWidget::on_horizontalSlider_2_valueChanged(int value){
ui->lineEdit_2->setText(QString::number(value)); ui->widget->setMaxSpeed(value);}void MainWidget::on_pushButton_2_clicked(){
m_QTimer->stop();}void MainWidget::on_pushButton_3_clicked(){
QImage t_imageA = ui->widget->getImageA(); QImage t_imageB = ui->widget->getImageB(); ui->label_a->setPixmap(QPixmap::fromImage(t_imageA)); ui->label_b->setPixmap(QPixmap::fromImage(t_imageB));}