案例分享:Qt用于服务器多图像拼接存在误差的标定工具(像素误差校准)

简介: 案例分享:Qt用于服务器多图像拼接存在误差的标定工具(像素误差校准)

若该文为原创文章,转载请注明原文出处

本文章博客地址:https://blog.csdn.net/qq21497936/article/details/79556106

各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究

红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…(点击传送门)

合作案例专栏:案例分享(体验Demo可下载,只定制)

 

需求

       高性能图像拼接服务器由于在存在误差,需要使用标定软件获取计算后的每个位置图片进行像素标定(校准),将人工校准的图像相关信息以指令形式发送给服务器端,服务器的每次拼接将依赖此标定参数。

       标定80幅图,10台服务器,每台服务器8路1080p摄像头。

 

Demo

       下载地址:https://download.csdn.net/download/qq21497936/10286573

               

效果图

 

原理

       打开文件拼接,按照范围1-80的顺序打开图像文件,加载到软件里面,每图片的5个像素作为一个实际坐标像素,记录每个图片相对于坐标第一张图片的左上角x,y的坐标,以及他们的宽度和高度,组成单幅图像的拼接参数。

 

功能

       可加载任意多的图片,对一个图片进行移动,包括上下左右,校准完后点击制作,将会把所有图片指令以指令格式组成协议包发往拼接服务器,拼接服务器各自记录自己部分的拼接参数,以便运行时使用。

 

关键代码

打开文件图片文件代码(打开“按钮”)

void MainWindow::on_pushButton_locaPics_clicked()
{
    QStringList filePaths = QFileDialog::getOpenFileNames(this, tr("添加图片"), "./", tr("Images (*.png *.bmp *.jpg)"));
    if(!filePaths.size())
    {
        QMessageBox::information(this, tr("提示"), tr("您未选择图片"));
        return;
    }
    ui->pushButton_moveXLess->setEnabled(true);
    ui->pushButton_moveXMore->setEnabled(true);
    ui->pushButton_moveUp->setEnabled(true);
    ui->pushButton_moveDown->setEnabled(true);
    ui->pushButton_make->setEnabled(true);
    for(int index = 0; index < _listPixmapButton.size(); index++)
    {
        delete _listPixmapButton.at(index);
    }
    _listPixmapButton.clear();
    for(int index = 0; index < _listLabel.size(); index++)
    {
        delete _listLabel.at(index);
    }
    _listLabel.clear();
    for(int index = 0; index < filePaths.size(); index++)
    {
        PixmapButton * pPixmapButton = new PixmapButton(ui->frame);
        pPixmapButton->setStyleSheet("");
        pPixmapButton->setPosWidth(_picWidth);
        pPixmapButton->setPosHeight(_picHeight);
        pPixmapButton->resize(_picWidth, _picHeight);
        pPixmapButton->setStyleSheet(QString("border-image: url(%1);").arg(filePaths.at(index)));
        connect(pPixmapButton, SIGNAL(updateChecked(PixmapButton*,bool)), this, SLOT(updateChecked(PixmapButton*,bool)));
        _listPixmapButton.push_back(pPixmapButton);
    }
    for(int index = 0; index < _listPixmapButton.size()-1; index++)
    {
        QLabel *pLabel = new QLabel(ui->frame);
        pLabel->setFixedWidth(100);
        pLabel->setText("0 pixel");
        _listLabel.push_back(pLabel);
    }
    _init = false;
    updateFrame();
}

对于每个图像使用QPusuButton,贴上图片作为一个图片单元,QPushButton存在两套x,y,width和height,一套是QPushButton实际的,一套是对应于左边第一张图片的x,y,width,height(方便制作协议)

pixmapbutton.h

#ifndef PIXMAPBUTTON_H
#define PIXMAPBUTTON_H
/**************************************************\
 * Demo: 图像块
 * 描述: 图像大小
 * 作者: 红模仿   QQ: 21497936    博客地址:http://blog.csdn.net/qq21497936/
 * 备注:作者提供各种技术相关服务,如开发、调试、IT集成服务等等
 * 版本信息:    版本号       日期                  描述
 *             v1.0    2018年1月31日           基础版本
\**************************************************/
#include <QWidget>
#include <QPushButton>
#include <QPaintEvent>
#include <QColor>
class PixmapButton : public QPushButton
{
    Q_OBJECT
public:
    explicit PixmapButton(QWidget *parent = nullptr);
public:
    inline void setCheckedOne(bool checkedOne) { _checkedOne = checkedOne; }
    inline void setPosX(int x) { _x = x; }
    inline void setPosY(int y) { _y = y; }
    inline int getPosX() { return _x; }
    inline int getPosY() { return _y; }
    inline void setPosWidth(int width) { _width = width; }
    inline int getPosWidth() { return _width; }
    inline void setPosHeight(int height) { _height = height; }
    inline int getPosHeight() { return _height; }
    inline void setPos(int x, int y) { _x = x; _y = y; }
    inline void setPos(int x, int y, int width, int height) { _x = x; _y = y; _width = width; _height = height; }
    inline void getPos(int &x, int &y, int &width, int &height) { x = _x; y = _y; width = _width; height = _height; }
signals:
    void updateChecked(PixmapButton * pPixmapButton, bool checked);
public slots:
    void slotCheck(bool checked);
protected:
    void paintEvent(QPaintEvent *event) override;
private:
    int _x;
    int _y;
    int _width;
    int _height;
    QColor _color;
    bool _checkedOne;
};
#endif // PIXMAPBUTTON_H

pixmapbutton.cpp

#include "pixmapbutton.h"
#include "mainwindow.h"
#include <QPainter>
#include <QDebug>
PixmapButton::PixmapButton(QWidget *parent)
    : QPushButton(parent),
      _color(QColor(41,19,244)),
      _checkedOne(false)
{
    setCheckable(true);
    resize(400,200);
    _width = 400;
    _height = 200;
    connect(this, SIGNAL(clicked(bool)), this, SLOT(slotCheck(bool)));
}
void PixmapButton::slotCheck(bool checked)
{
    emit updateChecked(this, checked);
    emit updateChecked(this, checked);
    emit updateChecked(this, checked);
}
void PixmapButton::paintEvent(QPaintEvent *event)
{
    QPushButton::paintEvent(event);
}

更新显示图片的代码

void MainWindow::updateFrame()
{
    int x, y, width;
    ui->frame->resize(ui->scrollArea->width(), ui->scrollArea->height());
    if(!_init)
    {
        for(int index = 0; index < _listPixmapButton.size(); index++)
        {
            if(index == 0)
            {
                x = 0;
                width = _listPixmapButton.at(index)->width();
                y = (ui->frame->height() - _listPixmapButton.at(index)->height()) / 2.0f;
            }
            x += SPACER;
            _listPixmapButton.at(index)->move(x,y);
            _listPixmapButton.at(index)->setPosX(x);
            _listPixmapButton.at(index)->setPosY(y);
            _listPixmapButton.at(index)->show();
            _listPixmapButton.at(index)->update();
            x += _listPixmapButton.at(index)->width();
            if(index == _listPixmapButton.size() - 1)
            {
                ui->frame->setFixedWidth(x+SPACER);
            }
            if(_listPixmapButton.at(index)->isChecked())
            {
                int x,y,width,height;
                _listPixmapButton.at(index)->getPos(x, y, width, height);
                ui->label_arrow->move((x+(width-ui->label_arrow->width())/2), y+height+_arrowSpace+_dy);
                ui->label_arrow->setVisible(true);
            }
        }
        _init = true;
    }else{
        for(int index = 0; index < _listPixmapButton.size(); index++)
        {
            PixmapButton *pPixmapButton = _listPixmapButton.at(index);
            pPixmapButton->move(pPixmapButton->getPosX(), pPixmapButton->getPosY()+_dy);
            if(pPixmapButton->isChecked())
            {
                int x,y,width,height;
                pPixmapButton->getPos(x, y, width, height);
                ui->label_arrow->move((x+(width-ui->label_arrow->width())/2), y+height+_arrowSpace+_dy);
                ui->label_arrow->setVisible(true);
            }
        }
    }
    for(int index = 0; index < _listPixmapButton.size(); index++)
    {
        if(index == 0)
            continue;
        int interval = _listPixmapButton.at(index)->getPosX()-(_listPixmapButton.at(index-1)->getPosX()+_listPixmapButton.at(index-1)->getPosWidth());
        _listLabel.at(index-1)->setText(QString("%1 pixel").arg(interval*_scale));
        _listLabel.at(index-1)->move(_listPixmapButton.at(index)->getPosX(), _listPixmapButton.at(index)->getPosY()-_pixelSpace+_dy);
        _listLabel.at(index-1)->setVisible(true);
    }
}

左移代码

void MainWindow::on_pushButton_moveXLess_clicked()
{
    bool isChecked = false;
    for(int index = 0; index < _listPixmapButton.size(); index++)
    {
        PixmapButton *pPixmapButton = _listPixmapButton.at(index);
        if(pPixmapButton->isChecked())
        {
            isChecked = true;
            if(pPixmapButton->getPosX() - _xStep < 0)
            {
                break;
            }else{
                if(index > 0)
                {
                    // 当右边的图片的x与左边的图片x相差小于_minXSapce时,从右边到最后边的所有图片将不会做x移动
                    if(_listPixmapButton.at(index)->getPosX() - _listPixmapButton.at(index-1)->getPosX() < _minXSapce)
                    {
                        break;
                    }
                }
                for(int index2 = index; index2 < _listPixmapButton.size(); index2++)
                {
                    PixmapButton *pPixmapButton = _listPixmapButton.at(index2);
                    pPixmapButton->setPosX(pPixmapButton->getPosX()-_xStep);
                }
                break;
            }
        }
    }
    if(!isChecked)
    {
        int start;
        for(int index = 0; index < _listPixmapButton.size(); index++)
        {
            if(index > 0)
            {
                // 当右边的图片的x与左边的图片x相差小于_minXSapce时,从右边到最后边的所有图片将不会做x移动
                if(_listPixmapButton.at(index)->getPosX() - _listPixmapButton.at(index-1)->getPosX() < _minXSapce)
                {
                    break;
                }
            }
            PixmapButton *pPixmapButton = _listPixmapButton.at(index);
            if(pPixmapButton->getPosX()-_xStep < 0)
            {
                start = index;
                continue;
            }else
            {
                pPixmapButton->setPosX(pPixmapButton->getPosX()-(index-start)*_xStep);
            }
            if(index == _listPixmapButton.size() - 1)
            {
//                ui->frame->setFixedWidth(_listPixmapButton.at(index)->x()+_listPixmapButton.at(index)->width());
            }
        }
    }
    updateFrame();
}

左移代码

void MainWindow::on_pushButton_moveXMore_clicked()
{
    bool isChecked = false;
    for(int index = 0; index < _listPixmapButton.size(); index++)
    {
        PixmapButton *pPixmapButton = _listPixmapButton.at(index);
        if(pPixmapButton->isChecked())
        {
            isChecked = true;
            if(index == 0)
                break;
            for(int index2 = index; index2 < _listPixmapButton.size(); index2++)
            {
                PixmapButton *pPixmapButton = _listPixmapButton.at(index2);
                pPixmapButton->setPosX(pPixmapButton->getPosX()+_xStep);
                if(index2 == _listPixmapButton.size() - 1)
                {
                    if(ui->frame->width() < _listPixmapButton.at(index2)->x()+_listPixmapButton.at(index2)->width())
                        ui->frame->setFixedWidth(_listPixmapButton.at(index2)->x()+_listPixmapButton.at(index2)->width());
                }
            }
            break;
        }
    }
    if(!isChecked)
    {
        for(int index = 0; index < _listPixmapButton.size(); index++)
        {
            if(index == 0)
                continue;
            PixmapButton *pPixmapButton = _listPixmapButton.at(index);
            pPixmapButton->setPosX(pPixmapButton->getPosX()+index*_xStep);
            if(index == _listPixmapButton.size() - 1)
            {
                if(ui->frame->width() < _listPixmapButton.at(index)->x()+_listPixmapButton.at(index)->width())
                    ui->frame->setFixedWidth(_listPixmapButton.at(index)->x()+_listPixmapButton.at(index)->width());
            }
        }
    }
    updateFrame();
}

上移代码

void MainWindow::on_pushButton_moveUp_clicked()
{
    bool isChecked = false;
    for(int index = 0; index < _listPixmapButton.size(); index++)
    {
        PixmapButton *pPixmapButton = _listPixmapButton.at(index);
        if(pPixmapButton->isChecked())
        {
            isChecked = true;
            if(index >= 1)
            {
                if(pPixmapButton->getPosY()+pPixmapButton->height()-_listPixmapButton.at(index-1)->getPosY() <= _minXSapce)
                    break;
            }
            if(index < _listPixmapButton.size()-1)
            {
                if(pPixmapButton->getPosY()+pPixmapButton->height()-_listPixmapButton.at(index+1)->getPosY() <= _minXSapce)
                    break;
            }
            pPixmapButton->setPosY(pPixmapButton->getPosY()-_yStep);
            break;
        }
    }
    if(!isChecked)
    {
        for(int index = 0; index < _listPixmapButton.size(); index++)
        {
            PixmapButton *pPixmapButton = _listPixmapButton.at(index);
            pPixmapButton->setPosY(pPixmapButton->getPosY()-_yStep);
        }
    }
    updateFrame();
}

下移代码

void MainWindow::on_pushButton_moveDown_clicked()
{
    bool isChecked = false;
    for(int index = 0; index < _listPixmapButton.size(); index++)
    {
        PixmapButton *pPixmapButton = _listPixmapButton.at(index);
        if(pPixmapButton->isChecked())
        {
            isChecked = true;
            if(index >= 1)
            {
                if(pPixmapButton->getPosY() - (_listPixmapButton.at(index-1)->getPosY() + _listPixmapButton.at(index-1)->getPosHeight()) >= -_minYSapce)
                    break;
            }
            if(index < _listPixmapButton.size()-1)
            {
                if(pPixmapButton->getPosY() - (_listPixmapButton.at(index+1)->getPosY() + _listPixmapButton.at(index+1)->getPosHeight()) >= -_minYSapce)
                    break;
            }
            pPixmapButton->setPosY(pPixmapButton->getPosY()+_yStep);
            break;
        }
    }
    if(!isChecked)
    {
        for(int index = 0; index < _listPixmapButton.size(); index++)
        {
            PixmapButton *pPixmapButton = _listPixmapButton.at(index);
            pPixmapButton->setPosY(pPixmapButton->getPosY()+_yStep);
        }
    }
    updateFrame();
}

快捷键代码

void MainWindow::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    case Qt::Key_W:
        if(ui->pushButton_moveUp->isEnabled())
        {
            on_pushButton_moveUp_clicked();
        }
        break;
    case Qt::Key_S:
        if(ui->pushButton_moveDown->isEnabled())
        {
            on_pushButton_moveDown_clicked();
        }
        break;
    case Qt::Key_A:
        if(ui->pushButton_moveXLess->isEnabled())
        {
            on_pushButton_moveXLess_clicked();
        }
        break;
    case Qt::Key_D:
        if(ui->pushButton_moveXMore->isEnabled())
        {
            on_pushButton_moveXMore_clicked();
        }
        break;
    case Qt::Key_O:
        on_pushButton_locaPics_clicked();
        break;
    default:
        break;
    }
}

制作标定协议代码

void MainWindow::on_pushButton_make_clicked()
{
    QList<PicInfo> listPicInfo;
    for(int index = 0;  index < _listPixmapButton.size(); index++)
    {
        PixmapButton *pPixmapButton = _listPixmapButton.at(index);
        PicInfo info;
        info.index = index+1;
        info.x = pPixmapButton->getPosX()*_scale;
        info.y = pPixmapButton->getPosY()*_scale;
        info.width = pPixmapButton->getPosWidth()*_scale;
        info.height = pPixmapButton->getPosHeight()*_scale;
        listPicInfo.push_back(info);
    }
    // show data
    qDebug() << "*******************************************************";
    for(int index = 0; index < listPicInfo.size(); index++)
    {
        qDebug() << "index :" << listPicInfo.at(index).index << "   "
                 << "x :" << listPicInfo.at(index).x << "   "
                 << "y :" << listPicInfo.at(index).y << "   "
                 << "width :" << listPicInfo.at(index).width << "   "
                 << "height :" << listPicInfo.at(index).height;
    }
    qDebug() << "*******************************************************";
}

原博主博客地址:https://blog.csdn.net/qq21497936

原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062

本文章博客地址:https://blog.csdn.net/qq21497936/article/details/79556106


相关文章
|
15天前
|
运维 数据挖掘 开发工具
服务器数据恢复—硬盘离线导致raid5阵列热备盘上线失败的数据恢复案例
服务器磁盘阵列数据恢复环境: 服务器中有两组分别由4块SAS硬盘组建的raid5磁盘阵列,两组raid5阵列划分LUN,组成LVM结构,格式化为EXT3文件系统。 服务器磁盘阵列故障: 服务器中一组raid5阵列中有一块硬盘离线,热备盘自动上线替换离线硬盘。热备盘上线同步数据过程中又有一块硬盘离线,热备盘同步失败,该组raid5阵列崩溃,LVM结构变得不完整,文件系统无法使用。 硬件工程师对两块离线硬盘进行硬件故障检测,发现先离线硬盘无法识别,初步判断该硬盘存在硬件故障,需要进行开盘修复。后离线硬盘可以正常识别。
服务器数据恢复—硬盘离线导致raid5阵列热备盘上线失败的数据恢复案例
|
5天前
|
存储 数据挖掘 数据库
服务器数据恢复—raid磁盘故障导致数据库数据损坏的数据恢复案例
存储中有一组由3块SAS硬盘组建的raid。上层win server操作系统层面划分了3个分区,数据库存放在D分区,备份存放在E分区。 RAID中一块硬盘的指示灯亮红色,D分区无法识别;E分区可识别,但是拷贝文件报错。管理员重启服务器,导致离线的硬盘上线开始同步数据,同步还没有完成就直接强制关机了,之后就没有动过服务器。
|
5天前
|
Java
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
16 4
|
23天前
|
SQL 数据挖掘 数据库
服务器数据恢复—意外断电导致XenServer虚拟机不可用的数据恢复案例
服务器数据恢复环境: 一台服务器中有一组由4块STAT硬盘通过RAID卡组建的RAID10阵列,上层是XenServer虚拟化平台,虚拟机安装Windows Server操作系统,作为Web服务器使用。 服务器故障: 因机房异常断电导致服务器中一台VPS(Xen Server虚拟机)不可用,虚拟磁盘文件丢失。
服务器数据恢复—意外断电导致XenServer虚拟机不可用的数据恢复案例
|
9天前
|
JavaScript 前端开发
vue配合axios连接express搭建的node服务器接口_简单案例
文章介绍了如何使用Express框架搭建一个简单的Node服务器,并使用Vue结合Axios进行前端开发和接口调用,同时讨论了开发过程中遇到的跨域问题及其解决方案。
12 0
vue配合axios连接express搭建的node服务器接口_简单案例
|
1月前
|
网络协议
keepalived对后端服务器的监测方式实战案例
关于使用keepalived进行后端服务器TCP监测的实战案例,包括配置文件的编辑和keepalived服务的重启,以确保配置生效。
37 1
keepalived对后端服务器的监测方式实战案例
|
21天前
|
存储 数据挖掘 Linux
服务器数据恢复—Linux操作系统网站服务器数据恢复案例
服务器数据恢复环境: 一台linux操作系统服务器上跑了几十个网站,服务器上只有一块SATA硬盘。 服务器故障: 服务器突然宕机,尝试再次启动失败。将硬盘拆下检测,发现存在坏扇区
|
6天前
|
存储 Oracle 关系型数据库
服务器数据恢复—存储硬盘故障导致映射到服务器上的卷挂载不上的数据恢复案例
一台存储上有一组由16块FC硬盘组建了一组raid。存储前面板上的对应10号和13号硬盘的故障灯亮起,存储映射到redhat linux操作系统服务器上的卷挂载不上,业务中断。
|
1月前
|
监控 Kubernetes 安全
如何设置一个有效的远程管理工具来简化服务器的维护工作?
如何设置一个有效的远程管理工具来简化服务器的维护工作?
|
7天前
|
存储 Unix 数据挖掘
服务器数据恢复—SAN环境下LUN Mapping出错导致文件系统共享冲突的数据恢复案例
服务器数据恢复环境: SAN环境下一台存储设备中有一组由6块硬盘组建的RAID6磁盘阵列,划分若干LUN,MAP到不同业务的SOLARIS操作系统服务器上。 服务器故障: 用户新增了一台服务器,将存储中的某个LUN映射到新增加的这台服务器上。这个映射的LUN其实之前已经MAP到其他SOLARIS操作系统的服务器上了。由于没有及时发现问题,新增加的这台服务器已经对此LUN做了初始化操作,磁盘报错,重启后发现卷无法挂载。

热门文章

最新文章

下一篇
无影云桌面