zoukankan      html  css  js  c++  java
  • SeetaFaceQt:写一个简单的界面

    关于这个界面,我用到了几个控件,这些控件通过Qt是非常容易构建的,窗口的话用的是QWidget,之前说了,QWidget是Qt里面几乎大部分控件的父类,QWidget的布局我使用了简单的水平布局(QHBoxLayout),但是右边的操作区域用了垂直布局(QVBoxLayout),所以应该算是混合布局吧。

    控件的话,首先是显示图像的QLabel(是的,这里我用QLabel来显示图像的),然后是四个按键:加载、开始、停止和训练。在选择图片和本地视频的时候要显示加载按键,用于加载图像或视频,所以当选择摄像机的时候这个按键时隐藏的。开始和停止按键时已知显示的,训练按键时在人脸识别的时候才会显示的。然后时下拉列表QComboBox,这里有两个,分别用于显示数据的三种来源(图片、本地视频和摄像头1)、三种功能(人脸检测、人脸标定和人脸识别)。接着就是QSpinBox和QDoubleSpinBox,这两个基本上是一样的用法,只是一个是对应整数,一个对应浮点数。然后考虑到图像可能会大于界面,这个时候又不想缩放图像,那就给显示图像的QLabel套个QScrollArea,QScrollArea控件是当内部内容大于它的尺寸时,就会自动差生滑动条,垂直的和水平的。OK,差不多啦。

    按钮的使用。按钮的使用也挺简单的,在头文件声明好一个按钮指针,然后在源文件中定义。比如这样:

    //头文件
    QPushButton *m_pLoadBtn;
    
    //源文件
    m_pStartBtn = new QPushButton(this);
    m_pStartBtn->setText(QString::fromWCharArray(L"开始"));
    connect(m_pStartBtn, SIGNAL(clicked(bool)), this, SLOT(detectSlot(bool)));

    这里在定义的时候是传进一个父控件指针的,这样的好处是可以使用Qt的内存自动回收机制,当一个控件指定了父控件的时候,会在销毁父控件前先将子控件销毁,逐层销毁回收内存。这也是很多Qt程序中定义了控件指针后没有使用delete回收内存的原因。这里QString::fromWCharArray(L"开始")这样写的原因是为了显示中文,如果不考虑显示中文的话,就直接"start"即可。connect()函数是连接了信号与槽,信号与槽的参数一般是要一致,如果不同一般就不起作用。

    QComboBox的使用。

    //头文件
    QComboBox *m_pTypeCBox;
    
    //源文件
    m_pTypeCBox = new QComboBox(this);
    m_pTypeCBox->addItem(QString::fromWCharArray(L"人脸检测"), 0);
    m_pTypeCBox->addItem(QString::fromWCharArray(L"人脸标定"), 1);
    m_pTypeCBox->addItem(QString::fromWCharArray(L"人脸识别"), 2);
    connect(m_pTypeCBox, SIGNAL(currentIndexChanged(int)), this, SLOT(typeSlot(int)));

    QComboBox是下拉列表,定义的时候可以通过addItem()来添加下拉菜单里面的项目,然后可以根据currentIndex或者currentData来访问当前选中的序号或者内容。

    QSpinBox和QDoubleSpinBox也是类似的用法,但是QDoubleSpinBox因为是浮点数,所以会有一个精度设置,默认是小数点后两位,但是可以通过setDecimals(n)来设置小数点后n位,因为QDoubleSpinBox的变量类型是double,所以其精度是可以设置得很高得。

    QScrollArea的使用也很简单,定义好显示图片的QLabel后,通过QScrollArea的setWidget()函数,将QLabel嵌套到QScrollArea中,当QLabel的大小大于QScrollArea的时候,QScrollArea就会自动产生垂直或者水平滑动条。

    然后是布局。水平布局或者垂直布局的用法都是类似的,首先是定义,然后通过addLayout()函数添加子布局或者通过addWidget添加子控件:

    m_pMainHLayout = new QHBoxLayout(this);
    m_pMainHLayout->addWidget(m_pFrameSArea, 10);
    m_pMainHLayout->addLayout(m_pChildVLayout, 1);

    后面的数字是设置子控件或者子布局在布局中的比例,Qt并不会严格执行,只是适当调整满足要求。布局设置好之后,要将布局放到QWidget中,通过QWidget的setLayout()函数实现。这里需要注意的是,父布局的定义要先于子布局,不然会出现问题的,比如这样是不行的:

    m_pChildVLayout = new QVBoxLayout(this);
    m_pMainHLayout = new QHBoxLayout(this);
    m_pMainHLayout->addLayout(m_pChildVLayout, 1);

    但是,调整为这样就可以:

    m_pMainHLayout = new QHBoxLayout(this);
    m_pChildVLayout = new QVBoxLayout(this);
    m_pMainHLayout->addLayout(m_pChildVLayout, 1);

    好了,界面部分大致就是这样,其实我感觉没啥好说的,我写的界面一般就仅限于能展示就行了。

    比较完整的代码:

    头文件部分:

    class QScrollArea;
    class QLabel;
    class QComboBox;
    class QSpinBox;
    class QDoubleSpinBox;
    class QPushButton;
    class QHBoxLayout;
    class QVBoxLayout;
    class QTimer;
    class QTextEdit;
    
    //Qt控件
    QScrollArea *m_pFrameSArea;
    QLabel *m_pFrameQLab;
    QLabel *m_pMinFaceSzQLabel;
    QSpinBox *m_pMinFaceSzQSBox;
    QLabel *m_pScoreThresholdQLabel;
    QDoubleSpinBox *m_pScoreThresholdQSBox;
    QLabel *m_pImgPyramidScaleQLabel;
    QDoubleSpinBox *m_pImgPyramidScaleQSBox;
    QLabel *m_pWinStepQLabel;
    QSpinBox *m_pWinStepQSBox;
    QComboBox *m_pCameraCBox;
    QComboBox *m_pTypeCBox;
    QLabel *m_pRecognizerScoreQLabel;
    QDoubleSpinBox *m_pRecognizerScoreQSBox;
    QPushButton *m_pLoadBtn;
    QPushButton *m_pStartBtn;
    QPushButton *m_pStopBtn;
    QPushButton *m_pTrainBtn;
    QTextEdit *m_pTextEdit;
    
    //Qt布局
    QHBoxLayout *m_pMainHLayout;
    QVBoxLayout *m_pChildVLayout;
    QHBoxLayout *m_pMinFaceSzHLayout;
    QHBoxLayout *m_pScoreThresholdHLayout;
    QHBoxLayout *m_pImgPyramidScaleHLayout;
    QHBoxLayout *m_pWinStepHLayout;
    QHBoxLayout *m_pRecognizerScoreHLayout;

    源文件部分:

    QFont font;
    font.setPixelSize(18);
    this->setFont(font);
    
    m_pFrameSArea = new QScrollArea(this);
    m_pFrameSArea->setAlignment(Qt::AlignCenter);
    
    m_pFrameQLab = new QLabel(m_pFrameSArea);
    m_pFrameQLab->setAlignment(Qt::AlignCenter);
    m_pFrameSArea->setWidget(m_pFrameQLab);
    
    m_pMinFaceSzQLabel = new QLabel(this);
    m_pMinFaceSzQLabel->setText(QString::fromLocal8Bit("最小尺寸"));
    m_pMinFaceSzQSBox = new QSpinBox(this);
    m_pMinFaceSzQSBox->setMinimum(4);
    m_pMinFaceSzQSBox->setMaximum(512);
    m_pMinFaceSzQSBox->setSingleStep(1);
    m_pMinFaceSzQSBox->setValue(40);
    connect(m_pMinFaceSzQSBox, SIGNAL(valueChanged(int)), 
        m_pSeetaFaceThread, SLOT(setMinFaceSizeSlot(int)));
    
    m_pScoreThresholdQLabel = new QLabel(this);
    m_pScoreThresholdQLabel->setText(QString::fromLocal8Bit("检测阈值"));
    m_pScoreThresholdQLabel->hide();
    m_pScoreThresholdQSBox = new QDoubleSpinBox(this);
    m_pScoreThresholdQSBox->setMaximum(1.0);
    m_pScoreThresholdQSBox->setMinimum(0.001);
    m_pScoreThresholdQSBox->setSingleStep(0.001);
    m_pScoreThresholdQSBox->setDecimals(3);
    m_pScoreThresholdQSBox->setValue(0.5);
    m_pScoreThresholdQSBox->hide();
    connect(m_pScoreThresholdQSBox, SIGNAL(valueChanged(double)), 
        m_pSeetaFaceThread, SLOT(setScoreThreshSlot(double)));
    
    m_pImgPyramidScaleQLabel = new QLabel(this);
    m_pImgPyramidScaleQLabel->setText(QString::fromLocal8Bit("缩放尺度"));
    m_pImgPyramidScaleQSBox = new QDoubleSpinBox(this);
    m_pImgPyramidScaleQSBox->setMaximum(1.0);
    m_pImgPyramidScaleQSBox->setMinimum(0.0);
    m_pImgPyramidScaleQSBox->setSingleStep(0.1);
    m_pImgPyramidScaleQSBox->setDecimals(1);
    m_pImgPyramidScaleQSBox->setValue(0.8);
    connect(m_pImgPyramidScaleQSBox, SIGNAL(valueChanged(double)), 
        m_pSeetaFaceThread, SLOT(setmagePyramidScaleFactorSlot(double)));
    
    m_pWinStepQLabel = new QLabel(this);
    m_pWinStepQLabel->setText(QString::fromLocal8Bit("窗口步长"));
    m_pWinStepQSBox = new QSpinBox(this);
    m_pWinStepQSBox->setMinimum(2);
    m_pWinStepQSBox->setMaximum(64);
    m_pWinStepQSBox->setSingleStep(1);
    m_pWinStepQSBox->setValue(4);
    connect(m_pWinStepQSBox, SIGNAL(valueChanged(int)), 
        m_pSeetaFaceThread, SLOT(setWindowStepSlot(int)));
    
    m_pCameraCBox = new QComboBox(this);
    connect(m_pCameraCBox, SIGNAL(currentIndexChanged(int)), this, 
        SLOT(cameraSlot(int)));
    m_pLoadBtn = new QPushButton(this);
    m_pLoadBtn->setText(QString::fromWCharArray(L"加载"));
    connect(m_pLoadBtn, SIGNAL(clicked(bool)), this, 
        SLOT(loadSlot(bool)));
    
    m_pTypeCBox = new QComboBox(this);
    m_pTypeCBox->addItem(QString::fromWCharArray(L"人脸检测"), 0);
    m_pTypeCBox->addItem(QString::fromWCharArray(L"人脸标定"), 1);
    m_pTypeCBox->addItem(QString::fromWCharArray(L"人脸识别"), 2);
    connect(m_pTypeCBox, SIGNAL(currentIndexChanged(int)), this, 
        SLOT(typeSlot(int)));
    
    m_pRecognizerScoreQLabel = new QLabel(this);
    m_pRecognizerScoreQLabel->setText(QString::fromLocal8Bit("识别阈值"));
    m_pRecognizerScoreQSBox = new QDoubleSpinBox(this);
    m_pRecognizerScoreQSBox->setMinimum(0.0);
    m_pRecognizerScoreQSBox->setMaximum(100);
    m_pRecognizerScoreQSBox->setSingleStep(0.1);
    m_pRecognizerScoreQSBox->setDecimals(2);
    m_pRecognizerScoreQSBox->setValue(50.0);
    connect(m_pRecognizerScoreQSBox, SIGNAL(valueChanged(double)), 
        m_pSeetaFaceThread, SLOT(setRecognizerScoreSlot(double)));
    
    m_pStartBtn = new QPushButton(this);
    m_pStartBtn->setText(QString::fromWCharArray(L"开始"));
    connect(m_pStartBtn, SIGNAL(clicked(bool)), this, 
        SLOT(detectSlot(bool)));
    
    m_pStopBtn = new QPushButton(this);
    m_pStopBtn->setText(QString::fromWCharArray(L"停止"));
    m_pStopBtn->setEnabled(false);
    connect(m_pStopBtn, SIGNAL(clicked(bool)), this, 
        SLOT(stopSlot(bool)));
    
    m_pTrainBtn = new QPushButton(this);
    m_pTrainBtn->setText(QString::fromWCharArray(L"训练"));
    m_pTrainBtn->hide();
    connect(m_pTrainBtn, SIGNAL(clicked(bool)), this, 
        SLOT(trainSlot(bool)));
    
    
    m_pTextEdit = new QTextEdit(this);
    
    m_pMainHLayout = new QHBoxLayout(this);
    m_pChildVLayout = new QVBoxLayout(this);
    
    m_pMinFaceSzHLayout = new QHBoxLayout(this);
    m_pMinFaceSzHLayout->addWidget(m_pMinFaceSzQLabel);
    m_pMinFaceSzHLayout->addWidget(m_pMinFaceSzQSBox);
    m_pScoreThresholdHLayout = new QHBoxLayout(this);
    m_pScoreThresholdHLayout->addWidget(m_pScoreThresholdQLabel);
    m_pScoreThresholdHLayout->addWidget(m_pScoreThresholdQSBox);
    m_pImgPyramidScaleHLayout = new QHBoxLayout(this);
    m_pImgPyramidScaleHLayout->addWidget(m_pImgPyramidScaleQLabel);
    m_pImgPyramidScaleHLayout->addWidget(m_pImgPyramidScaleQSBox);
    m_pWinStepHLayout = new QHBoxLayout(this);
    m_pWinStepHLayout->addWidget(m_pWinStepQLabel);
    m_pWinStepHLayout->addWidget(m_pWinStepQSBox);
    m_pRecognizerScoreHLayout = new QHBoxLayout(this);
    m_pRecognizerScoreHLayout->addWidget(m_pRecognizerScoreQLabel);
    m_pRecognizerScoreHLayout->addWidget(m_pRecognizerScoreQSBox);
    
    m_pChildVLayout->setAlignment(Qt::AlignTop);
    m_pChildVLayout->addWidget(m_pCameraCBox);
    m_pChildVLayout->addWidget(m_pLoadBtn);
    m_pChildVLayout->addWidget(m_pTypeCBox);
    m_pChildVLayout->addLayout(m_pMinFaceSzHLayout);
    m_pChildVLayout->addLayout(m_pScoreThresholdHLayout);
    m_pChildVLayout->addLayout(m_pImgPyramidScaleHLayout);
    m_pChildVLayout->addLayout(m_pWinStepHLayout);
    m_pChildVLayout->addLayout(m_pRecognizerScoreHLayout);
    m_pChildVLayout->addWidget(m_pStartBtn);
    m_pChildVLayout->addWidget(m_pStopBtn);
    m_pChildVLayout->addWidget(m_pTrainBtn);
    m_pChildVLayout->addWidget(m_pTextEdit);
    
    m_pMainHLayout->addWidget(m_pFrameSArea, 10);
    m_pMainHLayout->addLayout(m_pChildVLayout, 1);
    
    this->setLayout(m_pMainHLayout);

    OK,界面部分大致就是这样。

    桃红复含宿雨,柳绿更带朝烟。

    花落家童未扫,莺啼山客犹眠。

      --王维 《田园乐七首·其六 / 闲居》

    上善若水,为而不争。
  • 相关阅读:
    H5 WebSocket
    JS call()、apply()、bind()
    JS中this指向问题
    JS GET POST请求
    php 常用get post http请求
    php 开启redis
    egret接入华为快应用6004
    PHP生成公私钥,签名和验签
    JS数组去重
    Oracle第九课
  • 原文地址:https://www.cnblogs.com/Bearoom/p/11721771.html
Copyright © 2011-2022 走看看