人脸识别系统开发(4) -- 图片列表功能

在该人脸识别系统中,每次识别过程都会从摄像头实时捕获N(暂定为3)张人脸图片,用这N张图片来和证件上面的人脸进行比对。系统会将每次捕获的人脸图片显示在右侧的列表中,我们可以通过QML中的ListView来实现列表功能。

MVC

在说ListView功能前,就不得不提MVC设计模式了,因为ListView是采用这个模式来实现的。

Model-View—Controller(MVC)是源自SmallTalk的一个设计模式,在构建用户界面或前端网页时经常用到。作为一种经典的设计模式,MVC通过将系统分解为模型、视图、控制器三部分,每一部分相互独立,职责单一,在实现过程中只用专注于自身的核心逻辑。模型代表数据,视图代表呈现给用户看的界面部分,而控制器就是一个中间人,从模型拿数据给视图来呈现。

Qt中MVC框架对Controller部分进行了改动,引入了delegate的概念,合起来就是Model-View-Delegate。模型还是负责提供数据,View负责提供舞台进行呈现,Delegate负责控制以什么方式来显示。

Model

ListView的Model(也就是数据)可以在QML中定义,如:

import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1

Rectangle {
    width: 360;
    height: 300;
    color: "#EEEEEE";

    Component {
        id: phoneDelegate;
        Item {
            id: wrapper;
            width: parent.width;
            height: 30;

            MouseArea {
                anchors.fill: parent;
                onClicked: wrapper.ListView.view.currentIndex = index;
            }

            RowLayout {
                anchors.left: parent.left;
                anchors.verticalCenter: parent.verticalCenter;
                spacing: 8;
                Text { 
                    id: col1;
                    text: name; 
                    color: wrapper.ListView.isCurrentItem ? "red" : "black";
                    font.pixelSize: wrapper.ListView.isCurrentItem ? 22 : 18;
                    Layout.preferredWidth: 120;
                }

                Text { 
                    text: cost; 
                    color: wrapper.ListView.isCurrentItem ? "red" : "black";
                    font.pixelSize: wrapper.ListView.isCurrentItem ? 22 : 18;
                    Layout.preferredWidth: 80;
                }

                Text { 
                    text: manufacturer; 
                    color: wrapper.ListView.isCurrentItem ? "red" : "black";
                    font.pixelSize: wrapper.ListView.isCurrentItem ? 22 : 18;
                    Layout.fillWidth: true;
                }                
            }
        }
    }

    ListView {
        id: listView;
        anchors.fill: parent;

        delegate: phoneDelegate;

        model: ListModel {
            id: phoneModel;
            ListElement{
                name: "iPhone 3GS";
                cost: "1000";
                manufacturer: "Apple";
            }
            ListElement{
                name: "iPhone 4";
                cost: "1800";
                manufacturer: "Apple";
            }            
            ListElement{
                name: "iPhone 4S";
                cost: "2300";
                manufacturer: "Apple";
            } 
            ListElement{
                name: "iPhone 5";
                cost: "4900";
                manufacturer: "Apple";
            }    
            ListElement{
                name: "B199";
                cost: "1590";
                manufacturer: "HuaWei";
            }  
            ListElement{
                name: "MI 2S";
                cost: "1999";
                manufacturer: "XiaoMi";
            }         
            ListElement{
                name: "GALAXY S5";
                cost: "4699";
                manufacturer: "Samsung";
            }                                                  
        }

        focus: true;

        highlight: Rectangle{
            color: "lightblue";
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102

有时候ListView中的Model数据可能是通过某种复杂的方式获取到的(如网络接收、文件读取、硬件解码等),这个就需要通过C++构造Model提供到QML中。我们的人脸识别系统的Model数据就是实时从摄像头捕获的图片数据,所以也是在C++中定义Model。

在Qt中QAbstractItemModel是大部分模型(Model)类的基类,比如QAbstractListModel, QAbstractProxyModel, QAbstractTableModel, QFileSystemModel等。
QAbstractItemView是多部分视图(View)类的基类,如QListView, QTableView, QTreeView等。
QAbstractItemDelegate是所有delegate的基类,它又衍生出了QStyledItemDelegate和QItemDelegate两个分支。如果需要实现自己的delegate,可以从这2个类中选择一个作为基类。

C++中Model类GrapImageListModel定义:

#pragma once

#include <QAbstractListModel>
#include <QImage>
#include "GrapImageData.h"

class GrapImageListModelPrivate;

// http://doc.qt.io/qt-5/qabstractlistmodel.html
//
class GrapImageListModel : public QAbstractListModel {
    Q_OBJECT
public:
    GrapImageListModel(QObject* parent = NULL);
    virtual ~GrapImageListModel();

    // virtual function.
    int rowCount(const QModelIndex &parent = QModelIndex() ) const;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole ) const;
    QHash<int, QByteArray> roleNames() const;
public slots:
    void addGrapImage(const GrapImageData& data);
    void clearGrapImage();
signals:
    void newImage(const QImage &img) const; // 连接ImageDisplay::setImage槽
protected:
    GrapImageListModelPrivate* m_pPrivate;
private:
    mutable int m_iIndex;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

该类的关键在重载的三个虚函数rowCount,data,roleNames,Delegate在需要数据时会调用这3个函数来获取数据。
delegate定义在QML中(因为篇幅有删减):

Component {
    id: grapImageDelegate;

    Rectangle {
        id: wrapper;
        width: 140;
        height: 90;
        color: "transparent";

        Image {
            id: imgGrap;
            anchors.fill: parent;
            smooth: true;
            fillMode: Image.PreserveAspectFit;
            source: imgUri;
            visible: false;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

delegate的定义比较简单,在Component中定义一个Image即可。注意,Image的source设置的不是图片实际地址,而是imgUri
Delegate通过rowCount函数获取数据的总行数;通过roleNames来获取到QHash<int, QByteArray>QHash<int, QByteArray>可以理解为”int - string”的对应集合,比如我们设置0 - imgUri将0对应到imgUri上,在Delegate需要数据,调用data时就会在role参数传0,我们就可以知道这时是需要什么类型的数据了,并且可以根据index参数知道Delegate要获取哪一行的数据。

猜你喜欢

转载自blog.csdn.net/jack_20/article/details/79034883