├── client ├── qt │ ├── source │ │ ├── qml │ │ │ ├── qmldir │ │ │ ├── Views │ │ │ │ ├── StatisticsSettingsView.qml │ │ │ │ ├── CameraSettingsView.qml │ │ │ │ ├── SettingsView.qml │ │ │ │ ├── LogView.qml │ │ │ │ └── MainView.qml │ │ │ ├── Popups │ │ │ │ ├── SendMessagePopup.qml │ │ │ │ ├── ConnectionPopup.qml │ │ │ │ └── AboutPopup.qml │ │ │ ├── Common.qml │ │ │ └── Widgets │ │ │ │ └── ModalPopup.qml │ │ ├── common │ │ │ ├── common.hpp │ │ │ ├── ThreadSafeBuffer.hpp │ │ │ ├── Log.hpp │ │ │ ├── Log.cpp │ │ │ ├── YUVFrame.hpp │ │ │ ├── BaseSettings.hpp │ │ │ └── SettingObject.hpp │ │ ├── yuv2rgb │ │ │ ├── LICENSE │ │ │ └── yuv_rgb.h │ │ ├── main.cpp │ │ ├── Application │ │ │ ├── Application.hpp │ │ │ └── Application.cpp │ │ ├── Interface │ │ │ ├── LogModel.hpp │ │ │ ├── Interface.hpp │ │ │ ├── LogModel.cpp │ │ │ ├── InterfaceSettings.hpp │ │ │ └── Interface.cpp │ │ ├── Camera │ │ │ ├── YUVProviderVideoSurface.hpp │ │ │ ├── CameraWorker.hpp │ │ │ ├── CameraController.hpp │ │ │ └── YUVProviderVideoSurface.cpp │ │ ├── Client │ │ │ ├── ClientWorker.hpp │ │ │ ├── Client.hpp │ │ │ ├── ClientSettings.hpp │ │ │ └── ClientWorker.cpp │ │ ├── QMLGLYUVWidget │ │ │ └── QMLGLYUVWidget.hpp │ │ └── Statistics │ │ │ └── Statistics.hpp │ ├── assets │ │ ├── bgImages │ │ │ ├── dark.jpg │ │ │ ├── light.jpg │ │ │ └── license.txt │ │ ├── icons │ │ │ ├── built-with-qt.png │ │ │ ├── Information.svg │ │ │ ├── Error.svg │ │ │ ├── Warning.svg │ │ │ ├── license.txt │ │ │ ├── Log.svg │ │ │ ├── Message.svg │ │ │ ├── Statistics.svg │ │ │ ├── About.svg │ │ │ ├── Camera.svg │ │ │ ├── Shutdown.svg │ │ │ └── Settings.svg │ │ └── assets.qrc │ ├── qml.qrc │ └── iot-facerecognition-client-qt.pro └── python │ ├── setup.py │ ├── .gitignore │ └── examples │ └── raspberrypi-pir.py ├── readme-images ├── server-1.png ├── server-2.png ├── schematic.png ├── client-qt-1.png ├── client-qt-2.png ├── client-qt-3.png ├── client-qt-4.png ├── client-qt-5.png ├── client-qt-6.png ├── client-qt-7.png ├── client-qt-8.png ├── client-qt-9.png └── server-faces-json.png ├── server ├── config.ini ├── test.crt ├── source │ ├── ClientDialog │ │ ├── ClientDialog.ui │ │ ├── ClientDialog.h │ │ └── ClientDialog.cpp │ ├── Server │ │ ├── Server.h │ │ └── Server.cpp │ ├── main.cpp │ ├── MainWindow │ │ ├── MainWindow.h │ │ ├── MainWindow.ui │ │ └── MainWindow.cpp │ ├── SocketHandler │ │ ├── SocketHandler.h │ │ └── SocketHandler.cpp │ ├── config.h │ ├── Client │ │ └── Client.h │ └── DLIBWorker │ │ └── DLIBWorker.h ├── test.key ├── cmake │ └── FindTurboJPEG.cmake └── CMakeLists.txt └── .gitignore /client/qt/source/qml/qmldir: -------------------------------------------------------------------------------- 1 | singleton Common 1.0 Common.qml 2 | -------------------------------------------------------------------------------- /readme-images/server-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzun/iot-facerecognition/HEAD/readme-images/server-1.png -------------------------------------------------------------------------------- /readme-images/server-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzun/iot-facerecognition/HEAD/readme-images/server-2.png -------------------------------------------------------------------------------- /readme-images/schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzun/iot-facerecognition/HEAD/readme-images/schematic.png -------------------------------------------------------------------------------- /readme-images/client-qt-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzun/iot-facerecognition/HEAD/readme-images/client-qt-1.png -------------------------------------------------------------------------------- /readme-images/client-qt-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzun/iot-facerecognition/HEAD/readme-images/client-qt-2.png -------------------------------------------------------------------------------- /readme-images/client-qt-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzun/iot-facerecognition/HEAD/readme-images/client-qt-3.png -------------------------------------------------------------------------------- /readme-images/client-qt-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzun/iot-facerecognition/HEAD/readme-images/client-qt-4.png -------------------------------------------------------------------------------- /readme-images/client-qt-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzun/iot-facerecognition/HEAD/readme-images/client-qt-5.png -------------------------------------------------------------------------------- /readme-images/client-qt-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzun/iot-facerecognition/HEAD/readme-images/client-qt-6.png -------------------------------------------------------------------------------- /readme-images/client-qt-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzun/iot-facerecognition/HEAD/readme-images/client-qt-7.png -------------------------------------------------------------------------------- /readme-images/client-qt-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzun/iot-facerecognition/HEAD/readme-images/client-qt-8.png -------------------------------------------------------------------------------- /readme-images/client-qt-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzun/iot-facerecognition/HEAD/readme-images/client-qt-9.png -------------------------------------------------------------------------------- /client/qt/assets/bgImages/dark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzun/iot-facerecognition/HEAD/client/qt/assets/bgImages/dark.jpg -------------------------------------------------------------------------------- /client/qt/assets/bgImages/light.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzun/iot-facerecognition/HEAD/client/qt/assets/bgImages/light.jpg -------------------------------------------------------------------------------- /readme-images/server-faces-json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzun/iot-facerecognition/HEAD/readme-images/server-faces-json.png -------------------------------------------------------------------------------- /client/qt/assets/icons/built-with-qt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzun/iot-facerecognition/HEAD/client/qt/assets/icons/built-with-qt.png -------------------------------------------------------------------------------- /client/qt/assets/bgImages/license.txt: -------------------------------------------------------------------------------- 1 | All images are used under Pexels License (https://www.pexels.com/license). 2 | * dark.jpg file contains "Northern Lights" photo photographed by "stein egil liland" which was available at (https://www.pexels.com/photo/northern-lights-1933319). 3 | * light.jpg file contains "Landscape Photo of Mountain Filled With Snow" photo photographed by "eberhard grossgasteiger" which was available at (https://www.pexels.com/photo/landscape-photo-of-mountain-filled-with-snow-1004665). 4 | -------------------------------------------------------------------------------- /server/config.ini: -------------------------------------------------------------------------------- 1 | [GUI] 2 | Enable=1 3 | 4 | [Certificate] 5 | TestMode=0 6 | Key=test.key 7 | Certificate=test.crt 8 | QSsl::KeyAlgorithm=1 9 | QSsl::EncodingFormat=0 10 | 11 | [Log] 12 | Enable=1 13 | Location=log.txt 14 | 15 | [DLIB] 16 | ReferenceFile=faces.json 17 | FaceLandmarkModelFile=shape_predictor_5_face_landmarks.dat 18 | FaceRecognitionModelFile=dlib_face_recognition_resnet_model_v1.dat 19 | ImageNetClassifierFile=resnet34_1000_imagenet_classifier.dnn 20 | NumberOfCrops=16 21 | 22 | [Connection] 23 | ;ServerName= 24 | Port=50000 25 | -------------------------------------------------------------------------------- /client/python/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name='iot-facerecognition-client', 5 | version='1.2.0', 6 | py_modules=['iot_facerecognition_client'], 7 | install_requires=['opencv-python', 'websocket-client', 'screeninfo'], 8 | entry_points={ 9 | 'console_scripts': [ 10 | 'iot-facerecognition-client = iot_facerecognition_client:main' 11 | ]}, 12 | url='https://github.com/fuzun/iot-facerecognition', 13 | license='GPLv3', 14 | author='fuzun', 15 | author_email='fuzun54@outlook.com', 16 | description='python client for iot-facerecognition-server' 17 | ) 18 | -------------------------------------------------------------------------------- /client/qt/assets/assets.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | bgImages/dark.jpg 4 | bgImages/light.jpg 5 | icons/Camera.svg 6 | icons/Log.svg 7 | icons/Settings.svg 8 | icons/About.svg 9 | bgImages/license.txt 10 | icons/license.txt 11 | icons/Message.svg 12 | icons/Shutdown.svg 13 | icons/Error.svg 14 | icons/Information.svg 15 | icons/Warning.svg 16 | icons/Statistics.svg 17 | icons/built-with-qt.png 18 | 19 | 20 | -------------------------------------------------------------------------------- /client/qt/assets/icons/Information.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | *.slo 3 | *.lo 4 | *.o 5 | *.a 6 | *.la 7 | *.lai 8 | *.so 9 | *.so.* 10 | *.dll 11 | *.dylib 12 | 13 | # Qt-es 14 | object_script.*.Release 15 | object_script.*.Debug 16 | *_plugin_import.cpp 17 | /.qmake.cache 18 | /.qmake.stash 19 | *.pro.user 20 | *.pro.user.* 21 | *.qbs.user 22 | *.qbs.user.* 23 | *.moc 24 | moc_*.cpp 25 | moc_*.h 26 | qrc_*.cpp 27 | ui_*.h 28 | *.qmlc 29 | *.jsc 30 | Makefile* 31 | *build-* 32 | *.qm 33 | *.prl 34 | 35 | # Qt unit tests 36 | target_wrapper.* 37 | 38 | # QtCreator 39 | *.autosave 40 | 41 | # QtCreator Qml 42 | *.qmlproject.user 43 | *.qmlproject.user.* 44 | 45 | # QtCreator CMake 46 | CMakeLists.txt.user* 47 | 48 | # QtCreator 4.8< compilation database 49 | compile_commands.json 50 | 51 | # QtCreator local machine specific files for imported projects 52 | *creator.user* 53 | 54 | .idea/ 55 | venv/ 56 | 57 | -------------------------------------------------------------------------------- /client/qt/qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | source/qml/main.qml 4 | source/qml/Common.qml 5 | source/qml/qmldir 6 | source/qml/Views/MainView.qml 7 | source/qml/Views/LogView.qml 8 | source/qml/Views/SettingsView.qml 9 | source/qml/Views/CameraView.qml 10 | source/qml/Widgets/ModalPopup.qml 11 | source/qml/Widgets/SettingsList.qml 12 | source/qml/Views/CameraSettingsView.qml 13 | source/qml/Popups/AboutPopup.qml 14 | source/qml/Popups/ConnectionPopup.qml 15 | source/qml/Popups/SendMessagePopup.qml 16 | source/qml/Views/StatisticsView.qml 17 | source/qml/Views/StatisticsSettingsView.qml 18 | 19 | 20 | -------------------------------------------------------------------------------- /client/qt/source/common/common.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #ifndef COMMON_H 20 | #define COMMON_H 21 | 22 | #include 23 | 24 | #ifndef NDEBUG 25 | #include 26 | #endif 27 | 28 | #endif // COMMON_H 29 | -------------------------------------------------------------------------------- /client/qt/assets/icons/Error.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /client/qt/source/common/ThreadSafeBuffer.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #ifndef THREADSAFEBUFFER_H 20 | #define THREADSAFEBUFFER_H 21 | 22 | #include 23 | 24 | struct ThreadSafeBuffer : public QReadWriteLock 25 | { 26 | void* buffer = nullptr; 27 | size_t size = 0; 28 | }; 29 | 30 | #endif // THREADSAFEBUFFER_H 31 | -------------------------------------------------------------------------------- /client/qt/assets/icons/Warning.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /server/test.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDRTCCAi2gAwIBAgIUOT2Yofqzosl4tW6vMxIuuPpowBowDQYJKoZIhvcNAQEL 3 | BQAwMjEcMBoGA1UECgwTaW90LWZhY2VyZWNvZ25pdGlvbjESMBAGA1UEAwwJbG9j 4 | YWxob3N0MB4XDTIwMDUwOTAzMDgyM1oXDTIzMDIyNzAzMDgyM1owMjEcMBoGA1UE 5 | CgwTaW90LWZhY2VyZWNvZ25pdGlvbjESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjAN 6 | BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyD+y4ZvvIjGVkufQYl0hbiEBk5k1 7 | lC/NV0WW6OLC7jOPgMI8QjwDKWhVsX6yyajKl3H6yR7Vwu6mPokfP4b+K76ucn1h 8 | JK1cgpr6RoUJpkTGaqtZb20wB49bVGYI+q0nawOeXfdpUX9NfEThnI4+8Cv4SKyY 9 | 7MKrDzaLG3i6BzyELq++aarIlhHUvw+skk6nSf4gWYyBPlKoSAng2riCCq0Q11GW 10 | fyJp8mmACIjDcG3YZz4aBKDhV4feA39q/fdu6UnMqGQSJBUnMHddG8DarIKxsTLc 11 | 67o4+qVFuYQ5UyONiEkzVTcvm2x+AYMByZbZC5pqXf735VtWh83sOkttgwIDAQAB 12 | o1MwUTAdBgNVHQ4EFgQU7qbQ6TadFSS+t5mc5E11Jvu+3CUwHwYDVR0jBBgwFoAU 13 | 7qbQ6TadFSS+t5mc5E11Jvu+3CUwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B 14 | AQsFAAOCAQEAuLeNu5J8x6GXOmiTTUz6H7wuxcaDlrTQahcAfL7Nna6ilR6x4rRO 15 | 37327y/3BgYECvI6lHgR3A1xztZEWOUcBLZzvG7Nr/NVXS2YoXT0EtH61GmQ9QBu 16 | s/MZd7IcleSRRJe7dhxjOQEKRLu7nrF0xyhonX37iD1lFTjipyRyCT7Ppbv0b9v6 17 | dlM4XP5c6PtfWW9Wgv6Mg2VruOmtgCLw6CJCpAQIfCoZ/s63ZZYkrab0ApwF18tj 18 | 8GuG/mgCk4uQCbrOOMEN7vLx+DfRqzB156s7t8ylQY1XmMfgAzLbTfPsj+nAl8I4 19 | m7uspGDUJOU8WMtUnWt7CBzOLExZUznAwg== 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /server/source/ClientDialog/ClientDialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ClientDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1280 10 | 720 11 | 12 | 13 | 14 | false 15 | 16 | 17 | Dialog 18 | 19 | 20 | false 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 0 31 | 0 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | OK 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /client/qt/source/common/Log.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #ifndef LOG_H 20 | #define LOG_H 21 | 22 | #include 23 | #include 24 | 25 | class Log 26 | { 27 | Q_GADGET 28 | 29 | public: 30 | enum LogType 31 | { 32 | INFORMATION, 33 | WARNING, 34 | ERROR 35 | }; 36 | Q_ENUM(LogType) 37 | 38 | private: 39 | QVariant m_ctx; 40 | LogType m_type; 41 | QString m_timeStamp; 42 | 43 | public: 44 | explicit Log(const QVariant& ctx, LogType type = INFORMATION); 45 | 46 | QVariant ctx() const; 47 | LogType type() const; 48 | QString typeStr() const; 49 | QString timeStamp() const; 50 | }; 51 | 52 | #endif // LOG_H 53 | -------------------------------------------------------------------------------- /server/source/Server/Server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-server 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef SERVER_H 19 | #define SERVER_H 20 | 21 | #include 22 | 23 | class Server : public QObject 24 | { 25 | Q_OBJECT 26 | 27 | private: 28 | class QSettings *config = nullptr; 29 | class MainWindow *mainWindow = nullptr; 30 | class SocketHandler *socketHandler = nullptr; 31 | 32 | class QFile* logFile = nullptr; 33 | class QTextStream* logStream = nullptr; 34 | 35 | private slots: 36 | void log(const QString& message); 37 | 38 | 39 | public: 40 | explicit Server(QObject *parent = nullptr); 41 | ~Server(); 42 | 43 | static QString generateDateTime(); 44 | 45 | signals: 46 | void end(); 47 | }; 48 | 49 | #endif // SERVER_H 50 | -------------------------------------------------------------------------------- /server/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-server 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "Server/Server.h" 19 | 20 | #include 21 | 22 | int main(int argc, char *argv[]) 23 | { 24 | QApplication app(argc, argv); 25 | 26 | QCoreApplication::setOrganizationName("github.com/fuzun"); 27 | QCoreApplication::setApplicationName("iot-facerecognition-server"); 28 | QCoreApplication::setApplicationVersion(VERSION); 29 | 30 | Server server(nullptr); 31 | 32 | QObject::connect(&server, &Server::end, &app, &QApplication::quit, Qt::QueuedConnection); 33 | QObject::connect(&app, &QApplication::lastWindowClosed, &app, &QApplication::quit, Qt::QueuedConnection); 34 | 35 | // TODO: Handle SIGTERM to safely terminate the application when it runs in console mode. 36 | return app.exec(); 37 | } 38 | -------------------------------------------------------------------------------- /client/qt/source/qml/Views/StatisticsSettingsView.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | import QtQml 2.15 19 | 20 | import ".." 21 | import "../Widgets" as Widgets 22 | 23 | Widgets.SettingsList { 24 | readonly property string title: qsTr("Settings") 25 | readonly property string backNavigation: Common.statisticsView 26 | readonly property bool resetButtonVisible: true 27 | 28 | model: [ 29 | { 30 | model: statistics.settingModel, 31 | title: qsTr("Statistics Settings") 32 | } 33 | ] 34 | 35 | Connections { 36 | target: root 37 | 38 | function onResetButtonClicked() { 39 | statistics.settings.reset() 40 | } 41 | } 42 | 43 | Component.onDestruction: { 44 | statistics.settings.save() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /client/qt/source/yuv2rgb/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Adrien Descamps 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of yuv2rgb nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /client/qt/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "Application/Application.hpp" 24 | 25 | int main(int argc, char *argv[]) 26 | { 27 | qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard")); 28 | 29 | QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 30 | 31 | QCoreApplication::setApplicationName("iot-facerecognition-client-qt"); 32 | QCoreApplication::setOrganizationDomain("com"); 33 | QCoreApplication::setOrganizationName("fuzun"); 34 | QCoreApplication::setApplicationVersion(VERSION); 35 | 36 | QDir::setSearchPaths("qrc", QStringList(":/")); 37 | 38 | QApplication app(argc, argv); 39 | 40 | Application application(nullptr, &app); 41 | 42 | return app.exec(); 43 | } 44 | -------------------------------------------------------------------------------- /client/qt/source/Application/Application.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef APPLICATION_H 19 | #define APPLICATION_H 20 | 21 | #include 22 | 23 | #include "common/Log.hpp" 24 | 25 | class Application : public QObject 26 | { 27 | Q_OBJECT 28 | 29 | public: 30 | explicit Application(QObject *parent, class QApplication *application); 31 | ~Application(); 32 | 33 | private: 34 | class QQmlApplicationEngine* engine; 35 | class Interface* interface; 36 | class Client* client; 37 | class QMLGLYUVRenderer* renderer; 38 | class CameraController* camera; 39 | class Statistics* statistics; 40 | 41 | class QFile* logFile = nullptr; 42 | class QTextStream* logStream = nullptr; 43 | 44 | private slots: 45 | void log(const QVariant& str, Log::LogType type = Log::INFORMATION); 46 | void setLoggingToFile(bool enabled); 47 | }; 48 | 49 | #endif // APPLICATION_H 50 | -------------------------------------------------------------------------------- /client/qt/source/qml/Views/CameraSettingsView.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | import QtQml 2.15 19 | 20 | import ".." 21 | import "../Widgets" as Widgets 22 | 23 | Widgets.SettingsList { 24 | readonly property string title: qsTr("Settings") 25 | readonly property string backNavigation: Common.cameraView 26 | readonly property bool resetButtonVisible: true 27 | 28 | model: [ 29 | { 30 | model: camera.intfSettingModel, 31 | title: qsTr("Interface Settings") 32 | }, 33 | { 34 | model: camera.settingModel, 35 | title: qsTr("Camera Settings (changes requires restart)") 36 | } 37 | ] 38 | 39 | Connections { 40 | target: root 41 | 42 | function onResetButtonClicked() { 43 | camera.settings.reset() 44 | } 45 | } 46 | 47 | Component.onDestruction: { 48 | camera.settings.save() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /client/qt/source/Interface/LogModel.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #ifndef LOGMODEL_H 20 | #define LOGMODEL_H 21 | 22 | #include 23 | 24 | #include "common/Log.hpp" 25 | 26 | class LogModel : public QAbstractListModel 27 | { 28 | Q_OBJECT 29 | 30 | Q_PROPERTY(int count READ count NOTIFY countChanged) 31 | 32 | int m_count = 0; 33 | 34 | QVector m_data; 35 | 36 | public: 37 | enum Roles 38 | { 39 | TimeStampRole = Qt::UserRole, 40 | TypeRole, 41 | ContextRole 42 | }; 43 | 44 | explicit LogModel(QObject *parent = nullptr); 45 | 46 | QHash roleNames() const override; 47 | 48 | int count() const; 49 | 50 | void add(const Log& log); 51 | 52 | QVariant data(const QModelIndex &index, int role) const override; 53 | 54 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; 55 | 56 | signals: 57 | void countChanged(int count); 58 | }; 59 | 60 | #endif // LOGMODEL_H 61 | -------------------------------------------------------------------------------- /client/qt/source/common/Log.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #include "Log.hpp" 20 | 21 | #include 22 | #include 23 | 24 | Log::Log(const QVariant &ctx, LogType type) 25 | : m_ctx(ctx), 26 | m_type(type) 27 | { 28 | QDateTime dateTime = QDateTime::currentDateTime(); 29 | m_timeStamp = dateTime.toString("dd-MM-yyyy / hh:mm:ss"); 30 | } 31 | 32 | QVariant Log::ctx() const 33 | { 34 | return m_ctx; 35 | } 36 | 37 | Log::LogType Log::type() const 38 | { 39 | return m_type; 40 | } 41 | 42 | QString Log::typeStr() const 43 | { 44 | switch (m_type) 45 | { 46 | case LogType::WARNING: 47 | return QCoreApplication::tr("WARNING"); 48 | case LogType::ERROR: 49 | return QCoreApplication::tr("ERROR"); 50 | case LogType::INFORMATION: 51 | default: 52 | return QCoreApplication::tr("INFORMATION"); 53 | } 54 | } 55 | 56 | QString Log::timeStamp() const 57 | { 58 | return m_timeStamp; 59 | } 60 | -------------------------------------------------------------------------------- /server/source/MainWindow/MainWindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-server 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef MAINWINDOW_H 19 | #define MAINWINDOW_H 20 | 21 | #include 22 | #include 23 | 24 | QT_BEGIN_NAMESPACE 25 | namespace Ui { class MainWindow; } 26 | QT_END_NAMESPACE 27 | 28 | class QListWidgetItem; 29 | class Client; 30 | 31 | class MainWindow : public QMainWindow 32 | { 33 | Q_OBJECT 34 | 35 | QHash clientListItemMap; 36 | 37 | public: 38 | MainWindow(QWidget *parent = nullptr, class Server* _server = nullptr); 39 | ~MainWindow(); 40 | 41 | 42 | public slots: 43 | void newClient(class Client* client); 44 | void print(const QString& message); 45 | 46 | signals: 47 | void end(); 48 | 49 | private slots: 50 | void on_quitButton_clicked(); 51 | void on_aboutButton_clicked(); 52 | 53 | 54 | 55 | private: 56 | Ui::MainWindow *ui; 57 | class Server* server; 58 | 59 | QString getClientName(Client *client); 60 | }; 61 | #endif // MAINWINDOW_H 62 | -------------------------------------------------------------------------------- /server/test.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDIP7Lhm+8iMZWS 3 | 59BiXSFuIQGTmTWUL81XRZbo4sLuM4+AwjxCPAMpaFWxfrLJqMqXcfrJHtXC7qY+ 4 | iR8/hv4rvq5yfWEkrVyCmvpGhQmmRMZqq1lvbTAHj1tUZgj6rSdrA55d92lRf018 5 | ROGcjj7wK/hIrJjswqsPNosbeLoHPIQur75pqsiWEdS/D6ySTqdJ/iBZjIE+UqhI 6 | CeDauIIKrRDXUZZ/ImnyaYAIiMNwbdhnPhoEoOFXh94Df2r9927pScyoZBIkFScw 7 | d10bwNqsgrGxMtzrujj6pUW5hDlTI42ISTNVNy+bbH4BgwHJltkLmmpd/vflW1aH 8 | zew6S22DAgMBAAECggEBAKDcOrBteS34svTt70H1GjPDo+aTfqzpsYRXzKCL+Jct 9 | KCwA3DNAzjFnNN9+rdS9GPGLiDAj6wfKehVmRYncwTUW2j/yZCT4doYcRMx9doDw 10 | Youx1ghip+CK0oz74l6s1itrHr7RTvM+1lnrY2lGA10flTWcIMSgpJV19U0+MAI6 11 | uQ14GyaI5c9pFsKs1EbxBcj/VBH7xWRkbF6iPz2mlWlHna5liaxl62G8cynQWOJM 12 | 22AAg63HycKqYdIun3/WObwas2Ce1/pkcWHCSyPpnUdIbc3yJ6FSq+8bn0avKiIL 13 | yNJyvOYRE+85KDBmIGVPxtUlHDkbH6lOpmQLAmbZrqECgYEA5fMIkK/Oq9Lt89ZV 14 | igeJwjJ7Z2XzhjJORm4vxhjkF6EbtEGRZswT02XxDxRICd7Rimhwpmto6SktR8ah 15 | 5orRDgCCPoxcoGnT2rdeRRRdI0U5NlUDoQvGj1Kg/srDA8IFWiYhrAT1Y7dzMz2+ 16 | +QHL5OUjxCb+UVACnnVAmYn4DRkCgYEA3u9LNnxE3zqDpx9Owzmkzra3+6G9fhrR 17 | 6ew4WnVmMXsd90QwKdrV6O8HIIE+T0IMgeetHcpahps87pR4DfQ+z4iLkl9bQ5Wl 18 | mOJO61IMGFdbvaLtQl+2SiyORJtWoBUjyd9DZROPskXENsqA/mMEnVFmru/7Sc+y 19 | ckoxj/MIBvsCgYEAnkmqtrZehMbAx93dqhNAT+6iJe33MYRFf5PvzORrdpyPTojo 20 | ByQp7ZY51tB2Ol0oTqdQDC7Z285dfhAMeH9MIuBUx6ulQ0M181PQT6sR5eqL1Iu2 21 | 4NATUatmaZ23mkmfl4uyGBCdvpOUeExjvlLvQNQ+x5Kz89Moyl0aJ9bialkCgYEA 22 | heVvZSAqNXDtlbjGE5dRlx5DTo0MROtS3I6WIi6U3G83xkVcMCdRhv/ZZfp6NBxV 23 | ash9P4FD8cjXRexCVw81kmxOd/Fx3RvKRBLYl5nFzfDaFwH+Qnk+ATrVj/tEgg1w 24 | W1UPI2wmSEqC2O2zoBZUtTAo3jUg1mo6oU5SikTLs3UCgYAtGIq5g0TsEsmKTE3H 25 | lj/rN0BWAtMphM1r7UCzNOaUdHh+V+k3wnwMltJdCtpopLBZ9iX1Z+qMvC/bWd4H 26 | C/4Awqe61CBFfrM5bE98Y/0NRI431QyZQ7o8i8pboRwjdjduRmhnBURTa8mYBE21 27 | y8Y0Tk8koX+rhXvg46rtksmK7w== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /client/qt/source/Camera/YUVProviderVideoSurface.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef YUVPROVIDERVIDEOSURFACE_H 19 | #define YUVPROVIDERVIDEOSURFACE_H 20 | 21 | #include 22 | 23 | struct YUVFrame; 24 | class CameraSettings; 25 | 26 | class YUVProviderVideoSurface : public QAbstractVideoSurface 27 | { 28 | Q_OBJECT 29 | 30 | YUVFrame* m_frame = nullptr; 31 | 32 | #ifdef TURBOJPEG_AVAILABLE 33 | void* tjHandle = NULL; 34 | #endif 35 | 36 | CameraSettings *m_settings = nullptr; 37 | 38 | public: 39 | explicit YUVProviderVideoSurface(QObject *parent = nullptr, YUVFrame* frame = nullptr, CameraSettings *settings = nullptr); 40 | ~YUVProviderVideoSurface(); 41 | 42 | QList supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const override; 43 | bool present(const QVideoFrame& frame) override; 44 | 45 | private: 46 | void cleanBuffer(); 47 | 48 | signals: 49 | void updated(); 50 | void jpegReady(const QByteArray& data); 51 | 52 | }; 53 | 54 | #endif // YUVPROVIDERVIDEOSURFACE_H 55 | -------------------------------------------------------------------------------- /client/qt/source/common/YUVFrame.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #ifndef YUVFRAME_H 20 | #define YUVFRAME_H 21 | 22 | #include "ThreadSafeBuffer.hpp" 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | // YUV420 29 | struct YUVFrame : public ThreadSafeBuffer 30 | { 31 | using BufferType = unsigned char *; 32 | using layer = QPair; 33 | 34 | int width = 0, height = 0; 35 | 36 | inline layer y() const 37 | { 38 | return { QSize{ width, height }, static_cast(buffer) }; 39 | } 40 | 41 | inline layer u() const 42 | { 43 | return { QSize{ width / 2, height / 2 }, static_cast(buffer) + width * height }; 44 | } 45 | 46 | inline layer v() const 47 | { 48 | return { QSize{ width / 2, height / 2 }, static_cast(buffer) + width * height * 5 / 4}; 49 | } 50 | 51 | inline size_t size() const 52 | { 53 | return width * height * 3 / 2; 54 | } 55 | }; 56 | 57 | Q_DECLARE_METATYPE(YUVFrame *); 58 | 59 | #endif // YUVFRAME_H 60 | -------------------------------------------------------------------------------- /client/qt/assets/icons/license.txt: -------------------------------------------------------------------------------- 1 | All icons are used under Creative Commons(Attribution 3.0 unported) license (https://creativecommons.org/licenses/by/3.0). 2 | * Settings.svg file contains "gear, services, gears, preferences, settings icon" icon made by "MD Badsha Meah" which was available at (https://freeicons.io/basic-symbol/gear-services-gears-preferences-settings-icon-38524). 3 | * Camera.svg file contains "materializecss, photo, camera icon" icon made by "Raj Dev" which was available at (https://freeicons.io/free-valentines-day/materializecss-photo-camera-icon-7780). 4 | * Log.svg file contains "file, text icon" icon made by "Anu Rocks" which was available at (https://freeicons.io/regular-life-icons/file-text-icon-17825). 5 | * About.svg file contains "help, support, information, info, about icon" icon made by "MD Badsha Meah" which was available at (https://freeicons.io/basic-symbol/help-support-information-info-about-icon-38500). 6 | * Message.svg file contains 'envelope icon" icon made by "Anu Rocks" which was available at (https://freeicons.io/regular-life-icons/envelope-icon-17807). 7 | * Shutdown.svg file contains "shutdown, off, on, power icon" icon made by "MD Badsha Meah" which was available at (https://freeicons.io/basic-symbol/shutdown-off-on-power-icon-38515). 8 | * Warning.svg file contains "sign, warning icon" icon made by "Anu Rocks" which was available at (https://freeicons.io/regular-life-icons/sign-warning-icon-17898). 9 | * Error.svg file contains "sign, error icon" icon made by "Anu Rocks" which was available at (https://freeicons.io/regular-life-icons/sign-error-icon-17891). 10 | * Information.svg file contains "sign, info icon" icon made by "Anu Rocks" which was available at (https://freeicons.io/regular-life-icons/sign-info-icon-17892). 11 | * Statistics.svg file contains "statistics icon" icon made by "Free Preloaders" which was available at (https://freeicons.io/office-and-workstation-icons-6/statistics-icon-19021). 12 | -------------------------------------------------------------------------------- /server/source/ClientDialog/ClientDialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-server 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef CLIENTDIALOG_H 19 | #define CLIENTDIALOG_H 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | namespace Ui { 26 | class ClientDialog; 27 | } 28 | 29 | class Client; 30 | 31 | class ClientDialog : public QDialog 32 | { 33 | Q_OBJECT 34 | 35 | public: 36 | explicit ClientDialog(Client* client, QWidget *parent = nullptr); 37 | ~ClientDialog(); 38 | 39 | private: 40 | Ui::ClientDialog *ui; 41 | 42 | QGraphicsPixmapItem primaryDisplay; 43 | QGraphicsPixmapItem secondaryDisplay; 44 | QGraphicsPixmapItem tertiaryDisplay; 45 | 46 | QTimer secondaryDisplayCleaner; 47 | QTimer tertiaryDisplayCleaner; 48 | 49 | private slots: 50 | void on_okButton_clicked(); 51 | 52 | public slots: 53 | void updatePrimaryDisplay(const QPixmap& pixmap); 54 | 55 | void drawTextBox(const QVector> & list); 56 | void drawFaceIdentificators(const QVector>& identificators); 57 | 58 | void print(const QString& message); 59 | 60 | }; 61 | 62 | #endif // CLIENTDIALOG_H 63 | -------------------------------------------------------------------------------- /client/qt/assets/icons/Log.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /server/source/MainWindow/MainWindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 900 10 | 600 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | iot-facerecognition-server 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 12 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 0 38 | 0 39 | 40 | 41 | 42 | true 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | About... 53 | 54 | 55 | 56 | 57 | 58 | 59 | Quit 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /client/qt/source/Interface/Interface.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #ifndef INTERFACE_H 20 | #define INTERFACE_H 21 | 22 | #include 23 | 24 | #include "common/Log.hpp" 25 | 26 | class SettingObject; 27 | class InterfaceSettings; 28 | class LogModel; 29 | 30 | class Interface : public QObject 31 | { 32 | Q_OBJECT 33 | 34 | Q_PROPERTY(QList settingModel READ settingModel NOTIFY settingModelChanged) 35 | 36 | Q_PROPERTY(InterfaceSettings* settings READ settings CONSTANT) 37 | 38 | Q_PROPERTY(LogModel* logModel READ logModel CONSTANT) 39 | 40 | QList m_settingModel; 41 | InterfaceSettings* m_settings; 42 | LogModel* m_logModel; 43 | 44 | void setupSettings(); 45 | 46 | public: 47 | Q_INVOKABLE static QString readTextFile(const QUrl &fileName, bool convertLineBreak = true); 48 | 49 | public: 50 | explicit Interface(QObject *parent); 51 | 52 | QList settingModel() const; 53 | InterfaceSettings* settings() const; 54 | LogModel* logModel() const; 55 | 56 | signals: 57 | void settingModelChanged(QList settingModel); 58 | 59 | Q_INVOKABLE void log(const QVariant& str, Log::LogType type = Log::INFORMATION); 60 | 61 | void setLoggingToFile(bool enabled); 62 | }; 63 | 64 | #endif // INTERFACE_H 65 | -------------------------------------------------------------------------------- /server/source/SocketHandler/SocketHandler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-server 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef SOCKETHANDLER_H 19 | #define SOCKETHANDLER_H 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | class QWebSocket; 26 | class QWebSocketServer; 27 | class QSettings; 28 | class Client; 29 | 30 | class SocketHandler : public QObject 31 | { 32 | Q_OBJECT 33 | 34 | private: 35 | QThread socketThread; 36 | 37 | unsigned short m_port; 38 | QString m_serverName; 39 | QString m_keyFile; 40 | QString m_crtFile; 41 | int m_keyAlgorithm; 42 | int m_encodingFormat; 43 | bool m_testMode; 44 | 45 | protected: 46 | QSettings *m_config; 47 | 48 | public: 49 | explicit SocketHandler(QObject *parent, class QSettings* config); 50 | ~SocketHandler(); 51 | 52 | signals: 53 | void newClient(Client* socket); 54 | void log(const QString& message); 55 | 56 | protected: 57 | QWebSocketServer* webSocketServer; 58 | 59 | private slots: 60 | void onNewConnection(); 61 | void onDisconnect(); 62 | void onSslErrors(const QList& errors); 63 | 64 | signals: 65 | 66 | }; 67 | 68 | #endif // SOCKETHANDLER_H 69 | -------------------------------------------------------------------------------- /client/qt/source/qml/Views/SettingsView.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | import QtQml 2.15 19 | 20 | import "../Widgets" as Widgets 21 | 22 | Widgets.SettingsList { 23 | readonly property string title: qsTr("Settings") 24 | readonly property bool resetButtonVisible: true 25 | 26 | model: [ 27 | { 28 | model: intf.settingModel, 29 | title: qsTr("Interface Settings") 30 | }, 31 | { 32 | model: client.settingModel, 33 | title: qsTr("Client Settings") 34 | }, 35 | { 36 | model: statistics.settingModel, 37 | title: qsTr("Statistics Settings") 38 | }, 39 | { 40 | model: camera.settingModel, 41 | title: qsTr("Camera Settings (changes requires restart)") 42 | } 43 | ] 44 | 45 | Connections { 46 | target: root 47 | 48 | function onResetButtonClicked() { 49 | intf.settings.reset() 50 | client.settings.reset() 51 | statistics.settings.reset() 52 | camera.settingModel.reset() 53 | } 54 | } 55 | 56 | Component.onDestruction: { 57 | intf.settings.save() 58 | client.settings.save() 59 | statistics.settings.save() 60 | camera.settings.save() 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /client/qt/source/qml/Popups/SendMessagePopup.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | import QtQuick 2.15 19 | import QtQuick.Controls 2.15 20 | import QtQuick.Controls.Universal 2.15 21 | import QtQuick.Layouts 1.12 22 | 23 | import "../Widgets" as Widgets 24 | 25 | Widgets.ModalPopup { 26 | title: qsTr("Send Message") 27 | 28 | context: Component { 29 | Item { 30 | id: parentItem 31 | implicitHeight: childrenRect.height 32 | 33 | signal closePopup() 34 | 35 | ColumnLayout { 36 | anchors.left: parent.left 37 | anchors.right: parent.right 38 | 39 | TextArea { 40 | id: messageField 41 | 42 | Layout.preferredHeight: 125 43 | Layout.fillWidth: true 44 | 45 | placeholderText: qsTr("Message...") 46 | } 47 | 48 | RoundButton { 49 | Layout.fillWidth: true 50 | text: qsTr("Send!") 51 | 52 | onClicked: { 53 | console.assert(client.connected) 54 | 55 | client.sendMessage(messageField.text) 56 | messageField.clear() 57 | parentItem.closePopup() 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /client/qt/assets/icons/Message.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /client/qt/source/Interface/LogModel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #include "LogModel.hpp" 20 | 21 | #include "common/Log.hpp" 22 | 23 | LogModel::LogModel(QObject *parent) : QAbstractListModel(parent) 24 | { 25 | 26 | } 27 | 28 | QHash LogModel::roleNames() const 29 | { 30 | QHash roles; 31 | roles[TimeStampRole] = "timeStamp"; 32 | roles[TypeRole] = "type"; 33 | roles[ContextRole] = "context"; 34 | return roles; 35 | } 36 | 37 | int LogModel::count() const 38 | { 39 | return m_count; 40 | } 41 | 42 | void LogModel::add(const Log &log) 43 | { 44 | beginInsertRows(QModelIndex(), 0, 0); 45 | m_data.push_back(log); 46 | endInsertRows(); 47 | 48 | m_count++; 49 | emit countChanged(m_count); 50 | } 51 | 52 | QVariant LogModel::data(const QModelIndex &index, int role) const 53 | { 54 | if(!index.isValid()) 55 | return QVariant(); 56 | 57 | const Log& log = m_data[rowCount() - index.row() - 1]; 58 | 59 | switch (role) 60 | { 61 | case TimeStampRole: 62 | return QVariant(log.timeStamp()); 63 | case TypeRole: 64 | return QVariant(log.type()); 65 | case ContextRole: 66 | return QVariant(log.ctx()); 67 | default: 68 | return QVariant(); 69 | } 70 | } 71 | 72 | int LogModel::rowCount(const QModelIndex &parent) const 73 | { 74 | Q_UNUSED(parent); 75 | return m_data.size(); 76 | } 77 | 78 | -------------------------------------------------------------------------------- /client/python/.gitignore: -------------------------------------------------------------------------------- 1 | # Editors 2 | .vscode/ 3 | .idea/ 4 | 5 | # Vagrant 6 | .vagrant/ 7 | 8 | # Mac/OSX 9 | .DS_Store 10 | 11 | # Windows 12 | Thumbs.db 13 | 14 | # Source for the following rules: https://raw.githubusercontent.com/github/gitignore/master/Python.gitignore 15 | # Byte-compiled / optimized / DLL files 16 | __pycache__/ 17 | *.py[cod] 18 | *$py.class 19 | 20 | # C extensions 21 | *.so 22 | 23 | # Distribution / packaging 24 | .Python 25 | build/ 26 | develop-eggs/ 27 | dist/ 28 | downloads/ 29 | eggs/ 30 | .eggs/ 31 | lib/ 32 | lib64/ 33 | parts/ 34 | sdist/ 35 | var/ 36 | wheels/ 37 | *.egg-info/ 38 | .installed.cfg 39 | *.egg 40 | MANIFEST 41 | 42 | # PyInstaller 43 | # Usually these files are written by a python script from a template 44 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 45 | *.manifest 46 | *.spec 47 | 48 | # Installer logs 49 | pip-log.txt 50 | pip-delete-this-directory.txt 51 | 52 | # Unit test / coverage reports 53 | htmlcov/ 54 | .tox/ 55 | .nox/ 56 | .coverage 57 | .coverage.* 58 | .cache 59 | nosetests.xml 60 | coverage.xml 61 | *.cover 62 | .hypothesis/ 63 | .pytest_cache/ 64 | 65 | # Translations 66 | *.mo 67 | *.pot 68 | 69 | # Django stuff: 70 | *.log 71 | local_settings.py 72 | db.sqlite3 73 | 74 | # Flask stuff: 75 | instance/ 76 | .webassets-cache 77 | 78 | # Scrapy stuff: 79 | .scrapy 80 | 81 | # Sphinx documentation 82 | docs/_build/ 83 | 84 | # PyBuilder 85 | target/ 86 | 87 | # Jupyter Notebook 88 | .ipynb_checkpoints 89 | 90 | # IPython 91 | profile_default/ 92 | ipython_config.py 93 | 94 | # pyenv 95 | .python-version 96 | 97 | # celery beat schedule file 98 | celerybeat-schedule 99 | 100 | # SageMath parsed files 101 | *.sage.py 102 | 103 | # Environments 104 | .env 105 | .venv 106 | env/ 107 | venv/ 108 | ENV/ 109 | env.bak/ 110 | venv.bak/ 111 | 112 | # Spyder project settings 113 | .spyderproject 114 | .spyproject 115 | 116 | # Rope project settings 117 | .ropeproject 118 | 119 | # mkdocs documentation 120 | /site 121 | 122 | # mypy 123 | .mypy_cache/ 124 | .dmypy.json 125 | dmypy.json -------------------------------------------------------------------------------- /client/qt/assets/icons/Statistics.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /client/qt/source/common/BaseSettings.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef BASESETTINGS_H 19 | #define BASESETTINGS_H 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | class BaseSettings : public QObject 27 | { 28 | Q_OBJECT 29 | 30 | QSettings settings; 31 | 32 | protected: 33 | explicit BaseSettings(QObject *parent = nullptr) : QObject(parent) { } 34 | 35 | void load(const QMetaObject& metaObject) 36 | { 37 | settings.beginGroup(metaObject.className()); 38 | 39 | for (int i = metaObject.propertyOffset(); i < metaObject.propertyCount(); ++i) 40 | { 41 | QMetaProperty p = metaObject.property(i); 42 | p.write(this, settings.value(p.name(), p.read(this))); 43 | } 44 | } 45 | 46 | void save(const QMetaObject& metaObject) 47 | { 48 | for (int i = metaObject.propertyOffset(); i < metaObject.propertyCount(); ++i) 49 | { 50 | QMetaProperty p = metaObject.property(i); 51 | settings.setValue(p.name(), p.read(this)); 52 | } 53 | } 54 | 55 | void reset(const QMetaObject& oldMetaObject, const QObject* newObject) 56 | { 57 | if (!newObject) 58 | return; 59 | 60 | for (int i = oldMetaObject.propertyOffset(); i < oldMetaObject.propertyCount(); ++i) 61 | { 62 | QMetaProperty p = oldMetaObject.property(i); 63 | p.write(this, newObject->metaObject()->property(i).read(newObject)); 64 | } 65 | } 66 | }; 67 | 68 | #endif // BASESETTINGS_H 69 | -------------------------------------------------------------------------------- /client/qt/assets/icons/About.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /server/cmake/FindTurboJPEG.cmake: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS GATHERED FROM ANOTHER OPEN-SOURCE PROJECT (LIBFREENECT2) 2 | # THEREFORE, THIS FILE IS SUBJECT TO A DIFFERENT LICENSE (GPLV2 or LATER) 3 | # ORIGINAL REPOSITORY: https://github.com/OpenKinect/libfreenect2 4 | 5 | 6 | # FindTurboJPEG.cmake 7 | # Uses environment variable TurboJPEG_ROOT as backup 8 | # - TurboJPEG_FOUND 9 | # - TurboJPEG_INCLUDE_DIRS 10 | # - TurboJPEG_LIBRARIES 11 | 12 | FIND_PATH(TurboJPEG_INCLUDE_DIRS 13 | turbojpeg.h 14 | DOC "Found TurboJPEG include directory" 15 | PATHS 16 | "${DEPENDS_DIR}/libjpeg_turbo" 17 | "${DEPENDS_DIR}/libjpeg-turbo64" 18 | "/usr/local/opt/jpeg-turbo" # homebrew 19 | "/opt/local" # macports 20 | "C:/libjpeg-turbo64" 21 | "/opt/libjpeg-turbo" 22 | ENV TurboJPEG_ROOT 23 | PATH_SUFFIXES 24 | include 25 | ) 26 | 27 | #Library names: 28 | # debian sid,strech: libturbojpeg0 29 | # debian/ubuntu else: libturbojpeg1-dev #provided by libjpeg-turbo8-dev (ubuntu) 30 | FIND_LIBRARY(TurboJPEG_LIBRARIES 31 | NAMES libturbojpeg.so.1 libturbojpeg.so.0 turbojpeg 32 | DOC "Found TurboJPEG library path" 33 | PATHS 34 | "${DEPENDS_DIR}/libjpeg_turbo" 35 | "${DEPENDS_DIR}/libjpeg-turbo64" 36 | "/usr/local/opt/jpeg-turbo" # homebrew 37 | "/opt/local" # macports 38 | "C:/libjpeg-turbo64" 39 | "/opt/libjpeg-turbo" 40 | ENV TurboJPEG_ROOT 41 | PATH_SUFFIXES 42 | lib 43 | lib64 44 | ) 45 | 46 | IF(WIN32) 47 | FIND_FILE(TurboJPEG_DLL 48 | turbojpeg.dll 49 | DOC "Found TurboJPEG DLL path" 50 | PATHS 51 | "${DEPENDS_DIR}/libjpeg_turbo" 52 | "${DEPENDS_DIR}/libjpeg-turbo64" 53 | "C:/libjpeg-turbo64" 54 | ENV TurboJPEG_ROOT 55 | PATH_SUFFIXES 56 | bin 57 | ) 58 | ENDIF() 59 | 60 | IF(TurboJPEG_INCLUDE_DIRS AND TurboJPEG_LIBRARIES) 61 | INCLUDE(CheckCSourceCompiles) 62 | set(CMAKE_REQUIRED_INCLUDES ${TurboJPEG_INCLUDE_DIRS}) 63 | set(CMAKE_REQUIRED_LIBRARIES ${TurboJPEG_LIBRARIES}) 64 | check_c_source_compiles("#include \nint main(void) { tjhandle h=tjInitCompress(); return 0; }" TURBOJPEG_WORKS) 65 | set(CMAKE_REQUIRED_DEFINITIONS) 66 | set(CMAKE_REQUIRED_INCLUDES) 67 | set(CMAKE_REQUIRED_LIBRARIES) 68 | ENDIF() 69 | 70 | INCLUDE(FindPackageHandleStandardArgs) 71 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(TurboJPEG FOUND_VAR TurboJPEG_FOUND 72 | REQUIRED_VARS TurboJPEG_LIBRARIES TurboJPEG_INCLUDE_DIRS TURBOJPEG_WORKS) 73 | -------------------------------------------------------------------------------- /client/qt/source/Camera/CameraWorker.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef CAMERAWORKER_H 19 | #define CAMERAWORKER_H 20 | 21 | #include 22 | 23 | #include "common/Log.hpp" 24 | 25 | #ifdef CAM_QTMULTIMEDIA 26 | class QCamera; 27 | class YUVProviderVideoSurface; 28 | #include 29 | Q_DECLARE_METATYPE(QCameraInfo); 30 | #endif 31 | 32 | 33 | #ifdef CAM_OMX 34 | namespace IL 35 | { 36 | class Camera; 37 | class VideoEncode; 38 | } 39 | #endif 40 | 41 | struct YUVFrame; 42 | class CameraSettings; 43 | 44 | class CameraWorker : public QObject 45 | { 46 | Q_OBJECT 47 | 48 | friend class CameraController; 49 | 50 | #ifdef CAM_QTMULTIMEDIA 51 | QCamera *m_camera = nullptr; 52 | YUVProviderVideoSurface *m_surface = nullptr; 53 | #endif 54 | 55 | #ifdef CAM_OMX 56 | IL::Camera *m_camera = nullptr; 57 | IL::VideoEncode *m_encoder = nullptr; 58 | 59 | bool m_stop = false; 60 | #endif 61 | 62 | YUVFrame *m_frame = nullptr; 63 | 64 | CameraSettings *m_settings = nullptr; 65 | 66 | public: 67 | explicit CameraWorker(QObject *parent = nullptr, YUVFrame *frame = nullptr, CameraSettings *settings = nullptr); 68 | ~CameraWorker(); 69 | 70 | public slots: 71 | void start(); 72 | void stop(); 73 | 74 | private slots: 75 | void init(); 76 | 77 | #ifdef CAM_QTMULTIMEDIA 78 | void createCamera(const QCameraInfo& cameraInfo); 79 | #endif 80 | 81 | public: 82 | signals: 83 | void log(const QVariant& str, Log::LogType type = Log::INFORMATION); 84 | 85 | void frameBufferUpdated(); 86 | 87 | void jpegReady(const QByteArray& data); 88 | 89 | 90 | void started(); 91 | void stopped(); 92 | }; 93 | 94 | #endif // CAMERAWORKER_H 95 | -------------------------------------------------------------------------------- /client/qt/assets/icons/Camera.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /client/qt/assets/icons/Shutdown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /client/qt/source/Client/ClientWorker.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef CLIENTWORKER_H 19 | #define CLIENTWORKER_H 20 | 21 | #include 22 | 23 | #include "common/Log.hpp" 24 | 25 | class ClientWorker : public QObject 26 | { 27 | Q_OBJECT 28 | 29 | friend class Client; 30 | 31 | class QWebSocket *socket = nullptr; 32 | 33 | inline static const QString keyContext {"context"}; 34 | inline static const QString keyCommand {"command"}; 35 | 36 | inline const QWebSocket* getSocket() const { return socket; }; 37 | 38 | public: 39 | explicit ClientWorker(QObject *parent = nullptr); 40 | 41 | enum class Command : unsigned int 42 | { 43 | SETTING_NAME = 1, 44 | MESSAGE = 2, 45 | MESSAGE_TAG_FACE = 3, 46 | MESSAGE_TAG_OBJECT = 4, 47 | SETTING_OBJDETECTIONENABLED = 5, 48 | SETTING_LABELCOUNT = 6, 49 | SETTING_DETERMINISTICOBJECTDETECTION = 7, 50 | SETTING_FACERECOGNITIONENABLED = 8, 51 | INIT_REQUEST = 9 52 | }; 53 | 54 | private: 55 | qint64 sendTextMessage(const QString& ctx); 56 | qint64 sendBinaryMessage(const QByteArray& ctx); 57 | 58 | signals: 59 | void initRequest(); 60 | 61 | private slots: 62 | void processCommand(ClientWorker::Command cmd, const QVariant& ctx); 63 | void processTextMessage(const QString& message); 64 | void init(); 65 | 66 | public slots: 67 | void sendCommand(ClientWorker::Command cmd, const QVariant& ctx = QVariant()); 68 | void connect(const QUrl& url); 69 | void disconnect(); 70 | 71 | QString serverAddress(); 72 | QVariant serverPort(); 73 | 74 | void sendMessage(const QString& string); 75 | 76 | void sendData(const QByteArray& data); 77 | 78 | signals: 79 | void log(const QVariant& str, Log::LogType type = Log::INFORMATION); 80 | 81 | void faceTagReceived(const QVariantList &); 82 | void objectTagReceived(const QVariantList &); 83 | void commandReceived(ClientWorker::Command cmd, const QVariant& ctx); 84 | 85 | void sentBytes(qint64 size); 86 | void receivedBytes(qint64 size); 87 | }; 88 | 89 | Q_DECLARE_METATYPE(ClientWorker::Command) 90 | 91 | #endif // CLIENTWORKER_H 92 | -------------------------------------------------------------------------------- /client/qt/source/Camera/CameraController.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef CAMERACONTROLLER_H 19 | #define CAMERACONTROLLER_H 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "common/Log.hpp" 27 | 28 | struct YUVFrame; 29 | class CameraSettings; 30 | class SettingObject; 31 | class CameraWorker; 32 | class Statistics; 33 | 34 | class CameraController : public QObject 35 | { 36 | Q_OBJECT 37 | 38 | Q_PROPERTY(YUVFrame* currentFrame MEMBER m_currentFrame CONSTANT) 39 | Q_PROPERTY(QList settingModel READ settingModel NOTIFY settingModelChanged) 40 | Q_PROPERTY(QList intfSettingModel READ intfSettingModel NOTIFY intfSettingModelChanged) 41 | 42 | Q_PROPERTY(CameraSettings* settings READ settings CONSTANT) 43 | 44 | Q_PROPERTY(int fps MEMBER m_fps NOTIFY fpsChanged) 45 | 46 | YUVFrame* m_currentFrame = nullptr; 47 | QList m_settingModel; 48 | QList m_intfSettingModel; 49 | CameraSettings* m_settings = nullptr; 50 | 51 | QThread workerThread; 52 | CameraWorker *worker = nullptr; 53 | 54 | QTimer fpsTimer; 55 | size_t m_elapsedTime = 0; 56 | 57 | // size_t frameCount = 0; 58 | 59 | public: 60 | explicit CameraController(QObject *parent = nullptr, Statistics *statistics = nullptr); 61 | ~CameraController(); 62 | 63 | QList settingModel() const; 64 | QList intfSettingModel() const; 65 | CameraSettings* settings() const; 66 | 67 | Q_INVOKABLE QSize frameSize() const; 68 | 69 | private: 70 | void setupSettings(); 71 | int m_fps = 0; 72 | 73 | signals: 74 | void frameBufferUpdated(); 75 | void settingModelChanged(QList settingModel); 76 | 77 | void jpegReady(const QByteArray& data); 78 | 79 | signals: 80 | void log(const QVariant& str, Log::LogType type = Log::INFORMATION); 81 | 82 | Q_INVOKABLE void start(); 83 | Q_INVOKABLE void stop(); 84 | 85 | void fpsChanged(int fps); 86 | 87 | void started(); 88 | void stopped(); 89 | void intfSettingModelChanged(QList intfSettingModel); 90 | }; 91 | 92 | #endif // CAMERACONTROLLER_H 93 | -------------------------------------------------------------------------------- /server/source/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-server 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef CONFIG_H 19 | #define CONFIG_H 20 | 21 | #define CONFIG_FILENAME "config.ini" 22 | 23 | #define CONFIG_GUI "GUI" 24 | #define CONFIG_GUI_ENABLE "Enable" 25 | #define CONFIG_GUI_DEFAULT_ENABLE 1 26 | 27 | #define CONFIG_CRT "Certificate" 28 | #define CONFIG_CRT_TESTMODE "TestMode" 29 | #define CONFIG_CRT_DEFAULT_TESTMODE 1 30 | #define CONFIG_CRT_KEY_LOCATION "Key" 31 | #define CONFIG_CRT_CRT_LOCATION "Certificate" 32 | #define CONFIG_CRT_DEFAULT_KEY_LOCATION "test.key" 33 | #define CONFIG_CRT_DEFAULT_CRT_LOCATION "test.crt" 34 | #define CONFIG_CRT_KEYALGORITHM "QSsl::KeyAlgorithm" 35 | #define CONFIG_CRT_DEFAULT_KEYALGORITHM 1 36 | #define CONFIG_CRT_ENCODINGFORMAT "QSsl::EncodingFormat" 37 | #define CONFIG_CRT_DEFAULT_ENCODINGFORMAT 0 38 | 39 | #define CONFIG_LOG "Log" 40 | #define CONFIG_LOG_ENABLE "Enable" 41 | #define CONFIG_LOG_DEFAULT_ENABLE 1 42 | #define CONFIG_LOG_LOCATION "Location" 43 | #define CONFIG_LOG_DEFAULT_LOCATION "log.txt" 44 | 45 | #define CONFIG_DLIB "DLIB" 46 | #define CONFIG_DLIB_FACELANDMARKFILE "FaceLandmarkModelFile" 47 | #define CONFIG_DLIB_DEFAULT_FACELANDMARKFILE "shape_predictor_5_face_landmarks.dat" 48 | #define CONFIG_DLIB_FACERECOGNITIONFILE "FaceRecognitionModelFile" 49 | #define CONFIG_DLIB_DEFAULT_FACERECOGNITIONFILE "dlib_face_recognition_resnet_model_v1.dat" 50 | #define CONFIG_DLIB_THRESHOLD "Threshold" 51 | #define CONFIG_DLIB_DEFAULT_THRESHOLD 0.6 52 | #define CONFIG_DLIB_FACE_DETAILSIZE "FaceDetailSize" 53 | #define CONFIG_DLIB_DEFAULT_FACE_DETAILSIZE 150 54 | #define CONFIG_DLIB_FACE_PADDING "FacePadding" 55 | #define CONFIG_DLIB_DEFAULT_FACE_PADDING 0.25 56 | #define CONFIG_DLIB_REFERENCEFACEFILE "ReferenceFile" 57 | #define CONFIG_DLIB_DEFAULT_REFERENCEFACEFILE "faces.json" 58 | #define CONFIG_DLIB_IMAGENETCLASSIFIERFILE "ImageNetClassifierFile" 59 | #define CONFIG_DLIB_DEFAULT_IMAGENETCLASSIFIERFILE "resnet34_1000_imagenet_classifier.dnn" 60 | #define CONFIG_DLIB_NUMCROPS "NumberOfCrops" 61 | #define CONFIG_DLIB_DEFAULT_NUMCROPS 16 62 | 63 | #define CONFIG_CONN "Connection" 64 | #define CONFIG_CONN_SERVERNAME "ServerName" 65 | #define CONFIG_CONN_DEFAULT_SERVERNAME "iot-facerecognition-server" 66 | #define CONFIG_CONN_PORT "Port" 67 | #define CONFIG_CONN_DEFAULT_PORT 50000 68 | 69 | #endif // CONFIG_H 70 | -------------------------------------------------------------------------------- /client/qt/source/QMLGLYUVWidget/QMLGLYUVWidget.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | * This file contains portions from "Scene Graph - OpenGL Under QML" article of official Qt Framework docs. 21 | * This file contains portions from "SampleYUVRenderer" project of MasterAler. 22 | */ 23 | 24 | #ifndef QMLGLYUVWIDGET_H 25 | #define QMLGLYUVWIDGET_H 26 | 27 | #include 28 | #include 29 | 30 | // Microsoft related: 31 | #ifdef interface 32 | #undef interface 33 | #endif 34 | #ifdef ERROR 35 | #undef ERROR 36 | #endif 37 | 38 | struct YUVFrame; 39 | class QOpenGLTexture; 40 | 41 | class QMLGLYUVRenderer : public QObject, protected QOpenGLFunctions 42 | { 43 | Q_OBJECT 44 | 45 | public: 46 | explicit QMLGLYUVRenderer(QObject* parent); 47 | ~QMLGLYUVRenderer(); 48 | 49 | inline void setViewportSize(const QSize &size) { m_viewportSize = size; } 50 | inline void setWindow(QQuickWindow *window) { m_window = window; } 51 | inline void setFrame(YUVFrame *frame) { m_frame = frame; }; 52 | 53 | public slots: 54 | void init(); 55 | void paint(); 56 | 57 | private: 58 | QSize m_viewportSize; 59 | class QOpenGLShaderProgram *m_program = nullptr; 60 | QQuickWindow *m_window = nullptr; 61 | 62 | YUVFrame *m_frame = nullptr; 63 | 64 | QOpenGLTexture *m_textureY = nullptr; 65 | QOpenGLTexture *m_textureU = nullptr; 66 | QOpenGLTexture *m_textureV = nullptr; 67 | 68 | GLuint id_y = 0, id_u = 0, id_v = 0; 69 | 70 | int textureUniformY = 0, textureUniformU = 0, textureUniformV = 0; 71 | }; 72 | 73 | class QMLGLYUVWidget : public QQuickItem 74 | { 75 | Q_OBJECT 76 | 77 | Q_PROPERTY(YUVFrame* frame READ frame WRITE setFrame NOTIFY frameChanged) 78 | 79 | public: 80 | QMLGLYUVWidget(); 81 | 82 | YUVFrame* frame() const; 83 | 84 | signals: 85 | void frameChanged(YUVFrame* frame); 86 | 87 | public slots: 88 | void sync(); 89 | void cleanup(); 90 | void setFrame(YUVFrame* frame); 91 | 92 | private slots: 93 | void handleWindowChanged(QQuickWindow *win); 94 | 95 | private: 96 | void releaseResources() override; 97 | 98 | QMLGLYUVRenderer *m_renderer = nullptr; 99 | YUVFrame* m_frame = nullptr; 100 | }; 101 | 102 | #endif // QMLGLYUVWIDGET_H 103 | -------------------------------------------------------------------------------- /client/qt/source/qml/Common.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | pragma Singleton 19 | 20 | import QtQml 2.12 21 | 22 | QtObject { 23 | 24 | function setColorAlpha(color, alpha) { 25 | return Qt.rgba(color.r, color.g, color.b, alpha) 26 | } 27 | 28 | readonly property real toolbarHeight: height / 8 29 | 30 | readonly property string _viewDir: "Views/" 31 | readonly property string mainView: _viewDir + "MainView.qml" 32 | readonly property string cameraView: _viewDir + "CameraView.qml" 33 | readonly property string logView: _viewDir + "LogView.qml" 34 | readonly property string settingsView: _viewDir + "SettingsView.qml" 35 | readonly property string cameraSettingsView: _viewDir + "CameraSettingsView.qml" 36 | readonly property string statisticsView: _viewDir + "StatisticsView.qml" 37 | readonly property string statisticsSettingsView: _viewDir + "StatisticsSettingsView.qml" 38 | 39 | 40 | readonly property real width: 1024 41 | readonly property real height: 600 42 | 43 | readonly property string title: qsTr("iot-facerecognition qt client") 44 | 45 | readonly property int bgImgTransitionDuration: 250 46 | readonly property string _bgImgDir: "qrc:/bgImages/" 47 | readonly property string bgDarkImage: _bgImgDir + "dark.jpg" 48 | readonly property string bgLightImage: _bgImgDir + "light.jpg" 49 | readonly property string bgLicense: _bgImgDir + "license.txt" 50 | 51 | readonly property string _iconDir: "qrc:/icons/" 52 | readonly property string cameraIcon: _iconDir + "Camera.svg" 53 | readonly property string logIcon: _iconDir + "Log.svg" 54 | readonly property string settingsIcon: _iconDir + "Settings.svg" 55 | readonly property string messageIcon: _iconDir + "Message.svg" 56 | readonly property string aboutIcon: _iconDir + "About.svg" 57 | readonly property string shutdownIcon: _iconDir + "Shutdown.svg" 58 | readonly property string informationIcon: _iconDir + "Information.svg" 59 | readonly property string warningIcon: _iconDir + "Warning.svg" 60 | readonly property string errorIcon: _iconDir + "Error.svg" 61 | readonly property string statisticsIcon: _iconDir + "Statistics.svg" 62 | readonly property string iconLicense: _iconDir + "license.txt" 63 | 64 | readonly property string builtWithQt: _iconDir + "built-with-qt.png" 65 | } 66 | -------------------------------------------------------------------------------- /client/python/examples/raspberrypi-pir.py: -------------------------------------------------------------------------------- 1 | # iot-facerecognition-client 2 | # Example script for Raspberry Pi 3 | # License: GPLv3 4 | # Author: fuzun, 2020 5 | # Address: github.com/fuzun/iot-facerecognition 6 | 7 | # Description: 8 | # This script allows Raspberry Pi to detect human presence through PIR sensor and check if the present human's face is recognized by the server. 9 | # If a face is not detected, the red LED turns on. If a face detected but is unknown (no tag attached), the yellow LED turns on. 10 | # And when a face is detected and is recognized, the green LED turns on. 11 | # LED blink interval is 1.5 seconds. 12 | 13 | # import FaceRecognition class from iot-facerecognition-client: 14 | from iot_facerecognition_client import FaceRecognition 15 | 16 | import RPi.GPIO as GPIO 17 | import time 18 | import sys 19 | import threading 20 | import os 21 | 22 | # GPIO (BOARD) PINS, CONFIGURE AS YOU NEED 23 | GREENLED_PIN = 3 24 | YELLOWRED_PIN = 5 25 | REDLED_PIN = 7 26 | PIR_DATA_IN = 10 27 | 28 | GPIO.setwarnings(False) 29 | GPIO.setmode(GPIO.BOARD) 30 | GPIO.setup(GREENLED_PIN, GPIO.OUT) 31 | GPIO.setup(YELLOWRED_PIN, GPIO.OUT) 32 | GPIO.setup(REDLED_PIN, GPIO.OUT) 33 | GPIO.setup(PIR_DATA_IN, GPIO.IN) 34 | 35 | def turnoff(): 36 | print("No face is detected!") 37 | GPIO.output(GREENLED_PIN, 0) 38 | GPIO.output(YELLOWRED_PIN, 0) 39 | GPIO.output(REDLED_PIN, 1) 40 | timer = None 41 | 42 | isStarted = False 43 | def motionDetection(pin): 44 | global isStarted 45 | if GPIO.input(pin) and isStarted == False: 46 | print("Motion detected! Starting video capture...") 47 | faceRecognition.start() 48 | isStarted = True 49 | elif isStarted == True: 50 | print("Motion is not detected! Stopping video capture...") 51 | faceRecognition.stop() 52 | isStarted = False 53 | 54 | def callback(tag): 55 | global timer 56 | if timer is not None: 57 | timer.cancel() 58 | if tag == "": 59 | print("Unknown face is detected!") 60 | GPIO.output(YELLOWRED_PIN, 1) 61 | else: 62 | print("Known face is detected! Tag:" + tag) 63 | GPIO.output(GREENLED_PIN, 1) 64 | GPIO.output(REDLED_PIN, 0) 65 | timer = threading.Timer(1.5, turnoff) 66 | timer.start() 67 | 68 | if __name__ == "__main__": 69 | arglen = len(sys.argv) 70 | arglist = sys.argv 71 | 72 | ipaddr = "localhost" 73 | port = 50000 74 | 75 | if arglen == 3: 76 | ipaddr = arglist[1] 77 | port = arglist[2] 78 | 79 | faceRecognition = FaceRecognition("Raspberry-with-PIR-sensor", ipaddr, port, 1280, 720, callback, 0, 80 | 0, True) 81 | 82 | print("Connecting to the server...") 83 | faceRecognition.connect() 84 | print("Connected.") 85 | GPIO.output(7, 1) 86 | GPIO.add_event_detect(PIR_DATA_IN, GPIO.BOTH, callback=motionDetection) 87 | motionDetection(PIR_DATA_IN) 88 | print("Started seeking for motion...") 89 | input('Press a key to terminate...') 90 | faceRecognition.stop() 91 | turnoff() 92 | GPIO.output(REDLED_PIN, 0) 93 | os._exit(os.EX_OK) 94 | -------------------------------------------------------------------------------- /client/qt/source/Interface/InterfaceSettings.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #ifndef INTERFACESETTINGS_H 20 | #define INTERFACESETTINGS_H 21 | 22 | #include "common/BaseSettings.hpp" 23 | 24 | class InterfaceSettings : public BaseSettings 25 | { 26 | Q_OBJECT 27 | 28 | Q_PROPERTY(bool darkMode READ darkMode WRITE setDarkMode NOTIFY darkModeChanged) 29 | Q_PROPERTY(bool logToFile READ logToFile WRITE setLogToFile NOTIFY logToFileChanged) 30 | Q_PROPERTY(bool testMode READ testMode WRITE setTestMode NOTIFY testModeChanged) 31 | 32 | bool m_darkMode = true; 33 | bool m_logToFile = true; 34 | bool m_testMode = false; 35 | 36 | public: 37 | inline explicit InterfaceSettings(QObject *parent = nullptr, bool load = true) : BaseSettings(parent) 38 | { 39 | qRegisterMetaType(); 40 | 41 | if (!load) 42 | return; 43 | 44 | this->load(InterfaceSettings::staticMetaObject); 45 | } 46 | 47 | inline ~InterfaceSettings() 48 | { 49 | save(); 50 | } 51 | 52 | Q_INVOKABLE void save() 53 | { 54 | BaseSettings::save(InterfaceSettings::staticMetaObject); 55 | } 56 | 57 | Q_INVOKABLE void reset() 58 | { 59 | InterfaceSettings nonLoadedInstance(this, false); 60 | BaseSettings::reset(InterfaceSettings::staticMetaObject, &nonLoadedInstance); 61 | } 62 | 63 | inline bool darkMode() const 64 | { 65 | return m_darkMode; 66 | } 67 | 68 | inline bool logToFile() const 69 | { 70 | return m_logToFile; 71 | } 72 | 73 | inline bool testMode() const 74 | { 75 | return m_testMode; 76 | } 77 | 78 | public slots: 79 | inline void setDarkMode(bool darkMode) 80 | { 81 | if (m_darkMode == darkMode) 82 | return; 83 | 84 | m_darkMode = darkMode; 85 | emit darkModeChanged(m_darkMode); 86 | } 87 | 88 | inline void setLogToFile(bool logToFile) 89 | { 90 | if (m_logToFile == logToFile) 91 | return; 92 | 93 | m_logToFile = logToFile; 94 | emit logToFileChanged(m_logToFile); 95 | } 96 | 97 | inline void setTestMode(bool testMode) 98 | { 99 | if (m_testMode == testMode) 100 | return; 101 | 102 | m_testMode = testMode; 103 | emit testModeChanged(m_testMode); 104 | } 105 | 106 | signals: 107 | void darkModeChanged(bool darkMode); 108 | void logToFileChanged(bool logToFile); 109 | void testModeChanged(bool testMode); 110 | }; 111 | 112 | #endif // INTERFACESETTINGS_H 113 | -------------------------------------------------------------------------------- /server/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # iot-facerecognition-server 2 | # Author: fuzun, 2020 3 | # License: AGPLv3 4 | 5 | cmake_minimum_required(VERSION 3.14) 6 | 7 | project(iot-facerecognition-server LANGUAGES CXX) 8 | project(iot-facerecognition-server VERSION 2.0.0) 9 | add_compile_definitions(VERSION="${CMAKE_PROJECT_VERSION}") 10 | 11 | set(CMAKE_INCLUDE_CURRENT_DIR OFF) 12 | 13 | set(CMAKE_AUTOUIC ON) 14 | set(CMAKE_AUTOMOC ON) 15 | set(CMAKE_AUTORCC ON) 16 | 17 | set(CMAKE_CXX_STANDARD 17) 18 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 19 | 20 | SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}") 21 | 22 | if (MSVC) 23 | add_definitions(/bigobj) 24 | add_definitions(/FS) 25 | add_definitions(/arch:AVX) 26 | endif (MSVC) 27 | 28 | find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Widgets WebSockets REQUIRED) 29 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Widgets WebSockets REQUIRED) 30 | 31 | set(PROJECT_SOURCES 32 | source/ClientDialog/ClientDialog.cpp 33 | source/Client/Client.cpp 34 | source/DLIBWorker/DLIBWorker.cpp 35 | source/Server/Server.cpp 36 | source/SocketHandler/SocketHandler.cpp 37 | source/main.cpp 38 | source/MainWindow/MainWindow.cpp 39 | 40 | source/ClientDialog/ClientDialog.ui 41 | source/MainWindow/MainWindow.ui 42 | ) 43 | 44 | if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) 45 | qt_add_executable(iot-facerecognition-server 46 | ${PROJECT_SOURCES} 47 | ) 48 | else() 49 | add_executable(iot-facerecognition-server 50 | ${PROJECT_SOURCES} 51 | ) 52 | endif() 53 | 54 | # copy config file 55 | # TODO: generate config file dynamically 56 | configure_file(config.ini config.ini COPYONLY) 57 | 58 | # copy self-signed test certificate 59 | configure_file(test.crt test.crt COPYONLY) 60 | configure_file(test.key test.key COPYONLY) 61 | 62 | include(FetchContent) 63 | FetchContent_Declare(dlib 64 | GIT_REPOSITORY https://github.com/davisking/dlib.git 65 | GIT_TAG v19.21 66 | ) 67 | FetchContent_MakeAvailable(dlib) 68 | 69 | if (NOT DLIB_JPEG_SUPPORT) 70 | message(FATAL_ERROR "dlib's jpeg support must be enabled!") 71 | endif() 72 | 73 | find_package(TurboJPEG) 74 | if (TurboJPEG_FOUND OR DLIB_JPEG_SUPPORT) 75 | target_include_directories(iot-facerecognition-server PRIVATE ${TurboJPEG_INCLUDE_DIRS}) 76 | target_link_libraries(iot-facerecognition-server PRIVATE ${TurboJPEG_LIBRARIES}) 77 | target_compile_definitions(iot-facerecognition-server PRIVATE TURBOJPEG_AVAILABLE) 78 | 79 | message(STATUS "libjpeg-turbo is found. It will be used for fast JPEG decoding.") 80 | elseif (DLIB_JPEG_SUPPORT) 81 | message(WARNING "libjpeg-turbo is NOT found. Real-time JPEG decoding may be slow.") 82 | endif() 83 | 84 | 85 | target_include_directories(iot-facerecognition-server 86 | PRIVATE 87 | source/ClientDialog 88 | source/Client 89 | source/DLIBWorker 90 | source/MainWindow 91 | source/Server 92 | source/SocketHandler 93 | source 94 | ) 95 | 96 | target_compile_definitions(iot-facerecognition-server 97 | PRIVATE $<$,$>:QT_QML_DEBUG> VER=${APP_VERSION}) 98 | target_link_libraries(iot-facerecognition-server 99 | PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::WebSockets dlib::dlib) 100 | 101 | -------------------------------------------------------------------------------- /server/source/Client/Client.h: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-server 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef CLIENT_H 19 | #define CLIENT_H 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | class QWebSocket; 27 | class QGraphicsPixmapItem; 28 | class QTimer; 29 | class QListWidgetItem; 30 | class QThread; 31 | class QSettings; 32 | class DLIBWorker; 33 | 34 | struct Settings 35 | { 36 | std::atomic objectDetectionEnabled = true; 37 | std::atomic labelCount = 5; 38 | std::atomic deterministicObjectDetection = false; 39 | std::atomic faceRecognitionEnabled = true; 40 | }; 41 | 42 | class Client : public QObject 43 | { 44 | Q_OBJECT 45 | 46 | Settings settings; 47 | DLIBWorker *dlibWorker = nullptr; 48 | QString name {"?"}; 49 | 50 | QThread dlibWorkerThread; 51 | 52 | protected: 53 | QWebSocket *socket = nullptr; 54 | 55 | 56 | public: 57 | inline static const char * keyCommand = "command"; 58 | inline static const char * keyContext = "context"; 59 | 60 | enum class Command : unsigned int 61 | { 62 | SETTING_NAME = 1, 63 | MESSAGE = 2, 64 | MESSAGE_TAG_FACE = 3, 65 | MESSAGE_TAG_OBJECT = 4, 66 | SETTING_OBJDETECTIONENABLED = 5, 67 | SETTING_LABELCOUNT = 6, 68 | SETTING_DETERMINISTICOBJECTDETECTION = 7, 69 | SETTING_FACERECOGNITIONENABLED = 8, 70 | INIT_REQUEST = 9 71 | }; 72 | 73 | explicit Client(QObject *parent, QWebSocket* _socket, QSettings* _config); 74 | ~Client(); 75 | 76 | 77 | private: 78 | qint64 sendTextMessage(const QString& ctx); 79 | qint64 sendBinaryMessage(const QByteArray& ctx); 80 | 81 | public slots: 82 | void sendCommand(Client::Command cmd, const QVariant& ctx = QVariant()); 83 | QString getName() const; 84 | 85 | private slots: 86 | void processFaceResults(const QVector>& results); 87 | void processObjectResults(const QVector> &results); 88 | 89 | void processTextMessage(const QString& message); 90 | void processBinaryMessage(const QByteArray& data); 91 | void processCommand(Client::Command cmd, const QVariant& ctx); 92 | 93 | public: 94 | signals: 95 | void nameChanged(const QString& name); 96 | void commandReceived(Client::Command cmd, const QVariant& ctx); 97 | 98 | void primaryDisplayUpdated(const QPixmap& pixmap); 99 | 100 | void doneFace(const QVector>&); 101 | void doneObject(const QVector> &); 102 | 103 | void log(const QString& str); 104 | 105 | private: 106 | signals: 107 | void processImage(const QByteArray& buffer); 108 | 109 | }; 110 | 111 | Q_DECLARE_METATYPE(Client::Command); 112 | 113 | #endif // CLIENT_H 114 | -------------------------------------------------------------------------------- /server/source/MainWindow/MainWindow.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-server 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "MainWindow.h" 19 | #include "ui_MainWindow.h" 20 | 21 | #include 22 | #include 23 | 24 | #include "Server/Server.h" 25 | #include "Client/Client.h" 26 | #include "ClientDialog/ClientDialog.h" 27 | 28 | #include "config.h" 29 | 30 | MainWindow::MainWindow(QWidget *parent, Server *_server) 31 | : QMainWindow(parent) 32 | , ui(new Ui::MainWindow) 33 | , server(_server) 34 | { 35 | ui->setupUi(this); 36 | setWindowTitle(windowTitle() + " - v" + VERSION); 37 | 38 | connect(ui->clientList, &QListWidget::itemDoubleClicked, this, [this](QListWidgetItem *item) { 39 | const auto ptrClient = clientListItemMap[item]; 40 | 41 | ClientDialog* clientDialog = new ClientDialog(ptrClient, this); 42 | 43 | clientDialog->setWindowTitle(getClientName(ptrClient)); 44 | 45 | connect(ptrClient, &Client::nameChanged, clientDialog, &ClientDialog::setWindowTitle); 46 | 47 | connect(clientDialog, &ClientDialog::finished, this, [this]() { 48 | ClientDialog* dialog = qobject_cast(sender()); 49 | 50 | if(dialog) 51 | dialog->deleteLater(); // really needed? 52 | }); 53 | 54 | clientDialog->show(); 55 | }); 56 | } 57 | 58 | MainWindow::~MainWindow() 59 | { 60 | delete ui; 61 | } 62 | 63 | void MainWindow::newClient(Client *client) 64 | { 65 | if (!client) 66 | return; 67 | 68 | connect(client, &Client::log, this, [this](const QString& msg) { 69 | const auto ptrClient = qobject_cast(sender()); 70 | 71 | print(QString("%1: %2").arg(getClientName(ptrClient)).arg(msg)); 72 | }); 73 | 74 | QListWidgetItem* item = new QListWidgetItem(client->getName()); 75 | 76 | clientListItemMap[item] = client; 77 | connect(client, &Client::nameChanged, this, [item](const QString& name) { 78 | item->setText(name); 79 | }); 80 | 81 | connect(client, &Client::destroyed, this, [item]() { 82 | delete item; 83 | }); 84 | ui->clientList->addItem(item); 85 | } 86 | 87 | void MainWindow::on_quitButton_clicked() 88 | { 89 | emit end(); 90 | } 91 | 92 | void MainWindow::on_aboutButton_clicked() 93 | { 94 | QMessageBox::information(this, "About...", QString("iot-facerecognition-server
Address: GitHub Repository
Author: fuzun
Version: ") + VERSION); 95 | } 96 | 97 | QString MainWindow::getClientName(Client *client) 98 | { 99 | QString name; 100 | QMetaObject::invokeMethod(client, "getName", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, name)); 101 | return name; 102 | } 103 | 104 | void MainWindow::print(const QString &message) 105 | { 106 | ui->serverLog->append(QString("[%1] %2
").arg(Server::generateDateTime(), message)); 107 | } 108 | -------------------------------------------------------------------------------- /client/qt/source/Interface/Interface.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #include "Interface.hpp" 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "common/SettingObject.hpp" 26 | #include "InterfaceSettings.hpp" 27 | #include "LogModel.hpp" 28 | 29 | #include "common/common.hpp" 30 | 31 | Interface::Interface(QObject *parent) 32 | : QObject(parent), 33 | m_settings(new InterfaceSettings(this)), 34 | m_logModel(new LogModel(this)) 35 | { 36 | qRegisterMetaType>(); 37 | qRegisterMetaType(); 38 | 39 | qmlRegisterUncreatableType("com.iotfacerecognition.settings", 1, 0, "InterfaceSettings", "This type is uncreatable!"); 40 | 41 | connect(this, &Interface::log, this, [this](const QVariant& str, Log::LogType type = Log::INFORMATION) { 42 | m_logModel->add(Log(str, type)); 43 | }, Qt::QueuedConnection); 44 | 45 | connect(m_settings, &InterfaceSettings::logToFileChanged, this, &Interface::setLoggingToFile); 46 | 47 | setupSettings(); 48 | } 49 | 50 | QList Interface::settingModel() const 51 | { 52 | return m_settingModel; 53 | } 54 | 55 | InterfaceSettings *Interface::settings() const 56 | { 57 | return m_settings; 58 | } 59 | 60 | LogModel *Interface::logModel() const 61 | { 62 | return m_logModel; 63 | } 64 | 65 | void Interface::setupSettings() 66 | { 67 | using SettingType = SettingObject::SettingType; 68 | 69 | static const auto& newSetting = SettingObject::newSetting; 70 | static const auto& makePropPair = SettingObject::makePropertyPair; 71 | 72 | newSetting(m_settingModel, this, 73 | { 74 | tr("Dark Mode"), 75 | {{SettingObject::keyType, SettingType::ToggleButton}}, 76 | makePropPair(m_settings, "darkMode") 77 | } ); 78 | 79 | newSetting(m_settingModel, this, 80 | { 81 | tr("Test Mode (throw exception on log::error)"), 82 | {{SettingObject::keyType, SettingType::ToggleButton}}, 83 | makePropPair(m_settings, "testMode") 84 | } ); 85 | 86 | newSetting(m_settingModel, this, 87 | { 88 | tr("Enable logging to file? (log.txt)"), 89 | {{SettingObject::keyType, SettingType::ToggleButton}}, 90 | makePropPair(m_settings, "logToFile") 91 | }); 92 | 93 | emit settingModelChanged(m_settingModel); 94 | } 95 | 96 | QString Interface::readTextFile(const QUrl &fileName, bool convertLineBreak) 97 | { 98 | if (!fileName.isValid()) 99 | return QString(); 100 | 101 | QFile file(fileName.toString()); 102 | 103 | if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) 104 | return QString(); 105 | 106 | QString ret = file.readAll(); 107 | 108 | if (convertLineBreak) 109 | return ret.replace("\r", "").replace("\n", "
"); 110 | else 111 | return ret; 112 | } 113 | -------------------------------------------------------------------------------- /client/qt/assets/icons/Settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /client/qt/source/Client/Client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #ifndef CLIENT_H 20 | #define CLIENT_H 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "ClientWorker.hpp" 27 | #include "common/Log.hpp" 28 | 29 | class ClientWorker; 30 | class ClientSettings; 31 | class SettingObject; 32 | class Statistics; 33 | class QTimer; 34 | 35 | class Client : public QObject 36 | { 37 | Q_OBJECT 38 | 39 | Q_PROPERTY(QList settingModel READ settingModel NOTIFY settingModelChanged) 40 | Q_PROPERTY(ClientSettings* settings READ settings CONSTANT) 41 | Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged) 42 | 43 | Q_PROPERTY(qint64 receivedBytes READ receivedBytes WRITE setReceivedBytes NOTIFY receivedBytesChanged) 44 | Q_PROPERTY(qint64 sentBytes READ sentBytes WRITE setSentBytes NOTIFY sentBytesChanged) 45 | 46 | Q_PROPERTY(qint64 totalReceivedBytes READ totalReceivedBytes NOTIFY totalReceivedBytesChanged) 47 | Q_PROPERTY(qint64 totalSentBytes READ totalSentBytes NOTIFY totalSentBytesChanged) 48 | 49 | 50 | QThread workerThread; 51 | ClientWorker *worker = nullptr; 52 | 53 | bool m_connected = false; 54 | 55 | QTimer *m_trafficMeter = nullptr; 56 | size_t m_elapsedTime = 0; 57 | qint64 m_receivedBytes[2] { 0 }; 58 | qint64 m_sentBytes[2] { 0 }; 59 | 60 | inline static const auto keyContext { ClientWorker::keyContext }; 61 | inline static const auto keyCommand { ClientWorker::keyCommand }; 62 | 63 | private: 64 | ClientSettings* m_settings; 65 | QList m_settingModel; 66 | 67 | void setupSettings(); 68 | 69 | private slots: 70 | void processCommand(ClientWorker::Command cmd, const QVariant& ctx = QVariant()); 71 | 72 | public: 73 | explicit Client(QObject *parent = nullptr, Statistics *statistics = nullptr); 74 | ~Client(); 75 | 76 | using Command = ClientWorker::Command; 77 | 78 | QString serverAddress(); 79 | quint16 serverPort(); 80 | 81 | ClientSettings* settings() const; 82 | bool connected() const; 83 | 84 | QList settingModel() const; 85 | 86 | qint64 receivedBytes() const; 87 | 88 | qint64 sentBytes() const; 89 | 90 | qint64 totalReceivedBytes() const; 91 | 92 | qint64 totalSentBytes() const; 93 | 94 | public slots: 95 | void setReceivedBytes(qint64 receivedBytes); 96 | 97 | void setSentBytes(qint64 sentBytes); 98 | 99 | signals: 100 | void log(const QVariant& str, Log::LogType type = Log::INFORMATION); 101 | 102 | void faceTagReceived(const QVariantList &); 103 | void objectTagReceived(const QVariantList &); 104 | 105 | void connectedChanged(bool connected); 106 | void settingModelChanged(QList settingModel); 107 | 108 | Q_INVOKABLE void connect(const QUrl& url); 109 | Q_INVOKABLE void disconnect(); 110 | 111 | void sendCommand(ClientWorker::Command cmd, const QVariant& ctx = QVariant()); 112 | Q_INVOKABLE void sendMessage(const QString& string); 113 | 114 | void sendData(const QByteArray& data); 115 | void receivedBytesChanged(qint64 receivedBytes); 116 | void sentBytesChanged(qint64 sentBytes); 117 | void totalReceivedBytesChanged(qint64 totalReceivedBytes); 118 | void totalSentBytesChanged(qint64 totalSentBytes); 119 | }; 120 | 121 | #endif // CLIENT_H 122 | -------------------------------------------------------------------------------- /server/source/Server/Server.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-server 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "Server.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "MainWindow/MainWindow.h" 26 | #include "SocketHandler/SocketHandler.h" 27 | #include "Client/Client.h" 28 | 29 | #include "config.h" 30 | 31 | #ifdef NDEBUG 32 | #include 33 | #endif 34 | 35 | Q_DECLARE_METATYPE(QWebSocket*) 36 | 37 | Server::Server(QObject *parent) 38 | : QObject(parent) 39 | { 40 | config = new QSettings(QApplication::applicationDirPath() + "/" + CONFIG_FILENAME, QSettings::IniFormat, this); 41 | 42 | config->beginGroup(CONFIG_GUI); 43 | bool guiEnabled = config->value(CONFIG_GUI_ENABLE, CONFIG_GUI_DEFAULT_ENABLE).toBool(); 44 | config->endGroup(); 45 | 46 | config->beginGroup(CONFIG_LOG); 47 | bool logEnabled = config->value(CONFIG_LOG_ENABLE, CONFIG_LOG_DEFAULT_ENABLE).toBool(); 48 | QString logFileName = config->value(CONFIG_LOG_LOCATION, CONFIG_LOG_DEFAULT_LOCATION).toString(); 49 | config->endGroup(); 50 | 51 | if (logEnabled) 52 | { 53 | logFile = new QFile(logFileName, this); 54 | if (!logFile->open(QFile::Text | QFile::Append)) 55 | { 56 | log("Can't write to log file. Logging to file is disabled."); 57 | } 58 | else 59 | { 60 | logStream = new QTextStream(logFile); 61 | } 62 | } 63 | 64 | if (guiEnabled) 65 | { 66 | mainWindow = new MainWindow(nullptr); 67 | connect(mainWindow, &MainWindow::end, this, &Server::end, Qt::QueuedConnection); 68 | mainWindow->show(); 69 | } 70 | 71 | qRegisterMetaType(); 72 | 73 | socketHandler = new SocketHandler(this, config); 74 | 75 | if (mainWindow) 76 | { 77 | connect(socketHandler, &SocketHandler::newClient, mainWindow, &MainWindow::newClient); 78 | connect(socketHandler, &SocketHandler::log, mainWindow, &MainWindow::print); 79 | } 80 | 81 | connect(socketHandler, &SocketHandler::log, this, &Server::log); 82 | 83 | connect(socketHandler, &SocketHandler::newClient, this, [this](Client* client) { 84 | connect(client, &Client::log, this, &Server::log); 85 | }); 86 | } 87 | 88 | Server::~Server() 89 | { 90 | logStream->flush(); 91 | delete logStream; 92 | 93 | if(logFile->isOpen()) 94 | { 95 | logFile->flush(); 96 | logFile->close(); 97 | } 98 | 99 | delete logFile; 100 | } 101 | 102 | QString Server::generateDateTime() 103 | { 104 | QDateTime dateTime = QDateTime::currentDateTime(); 105 | return dateTime.toString("dd-MM-yyyy / hh:mm:ss"); 106 | } 107 | 108 | void Server::log(const QString &message) 109 | { 110 | QString preface = QString("[%1]: ").arg(generateDateTime()); 111 | 112 | if ( const auto ptrClient = qobject_cast(sender()) ) 113 | { 114 | preface += ptrClient->getName() + ": "; 115 | } 116 | 117 | #ifdef NDEBUG 118 | std::cout << preface.toStdString() << message.toStdString() << std::endl; 119 | #else 120 | qDebug((preface + message).toStdString().c_str()); 121 | #endif 122 | 123 | if (logStream) 124 | { 125 | *logStream << preface << message; 126 | Qt::endl(*logStream); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /client/qt/iot-facerecognition-client-qt.pro: -------------------------------------------------------------------------------- 1 | # iot-facerecognition-client-qt 2 | # Author: fuzun, 2021 3 | # License: AGPLv3 4 | 5 | VERSION = 1.0.0 6 | DEFINES += VERSION=\\\"$$VERSION\\\" 7 | 8 | QT += widgets quick virtualkeyboard quickcontrols2 websockets charts 9 | 10 | CONFIG += c++17 11 | 12 | INCLUDEPATH += $$PWD/source 13 | 14 | QT_CONFIG -= no-pkg-config 15 | CONFIG += link_pkgconfig 16 | 17 | CONFIG(release, debug|release) : DEFINES += NDEBUG 18 | 19 | if (linux-rasp*) { 20 | message("Target device is Raspberry Pi...") 21 | 22 | LIBS += -L$$[QT_SYSROOT]/lib/arm-linux-gnueabihf 23 | 24 | message("Checking if OpenMaxIL++ available") 25 | 26 | exists("$$[QT_SYSROOT]/opt/vc/lib/OpenMaxIL++/libOpenMaxIL++*") { 27 | message("OpenMaxIL++ library is found!") 28 | LIBS += -L$$[QT_SYSROOT]/opt/vc/lib/OpenMaxIL++ -lOpenMaxIL++ 29 | INCLUDEPATH += $$[QT_SYSROOT]/opt/vc/include/OpenMaxIL++ 30 | DEFINES += CAM_OMX 31 | 32 | LIBS += -lbcm_host -lvcos -lvchiq_arm -lrt -lpthread -ldl -lopenmaxil -lvcsm 33 | 34 | DEFINES += HAVE_LIBOPENMAX=2 OMX OMX_SKIP64BIT USE_EXTERNAL_OMX HAVE_LIBBCM_HOST USE_EXTERNAL_LIBBCM_HOST USE_VCHIQ_ARM 35 | } else { 36 | error("Could not found OpenMaxIL++ library! Check the README file and https://github.com/dridri/OpenMaxIL-cpp repository for more information!") 37 | } 38 | } 39 | 40 | !contains (DEFINES, CAM_OMX) { 41 | message("Qt Multimedia backend will be used for the camera") 42 | QT += multimedia 43 | DEFINES += CAM_QTMULTIMEDIA 44 | 45 | packagesExist(libturbojpeg) { 46 | message("pkgconfig found libturboconfig! It will be used for fast RGB to JPEG encoding!") 47 | DEFINES += TURBOJPEG_AVAILABLE 48 | PKGCONFIG += libturbojpeg 49 | } else : contains(QMAKE_HOST.arch, x86_64) : exists("C:\libjpeg-turbo64\lib\turbojpeg.lib") { 50 | message("libjpeg-turbo is found! It will be used for fast RGB to JPEG encoding!") 51 | DEFINES += TURBOJPEG_AVAILABLE 52 | LIBS += -LC:\libjpeg-turbo64\lib -lturbojpeg 53 | INCLUDEPATH += C:\libjpeg-turbo64\include 54 | } else { 55 | message("libjpeg-turbo library could not be found! JPEG encoding will be slow!") 56 | } 57 | } 58 | 59 | 60 | HEADERS += \ 61 | source/Application/Application.hpp \ 62 | source/Camera/CameraController.hpp \ 63 | source/Camera/CameraSettings.hpp \ 64 | source/Camera/CameraWorker.hpp \ 65 | source/Client/Client.hpp \ 66 | source/Client/ClientSettings.hpp \ 67 | source/Client/ClientWorker.hpp \ 68 | source/Interface/Interface.hpp \ 69 | source/Interface/InterfaceSettings.hpp \ 70 | source/Interface/LogModel.hpp \ 71 | source/QMLGLYUVWidget/QMLGLYUVWidget.hpp \ 72 | source/Statistics/Statistics.hpp \ 73 | source/Statistics/StatisticsSettings.hpp \ 74 | source/common/BaseSettings.hpp \ 75 | source/common/Log.hpp \ 76 | source/common/SettingObject.hpp \ 77 | source/common/ThreadSafeBuffer.hpp \ 78 | source/common/YUVFrame.hpp \ 79 | source/common/common.hpp 80 | 81 | contains (DEFINES, CAM_QTMULTIMEDIA) { 82 | HEADERS += source/Camera/YUVProviderVideoSurface.hpp 83 | HEADERS += source/yuv2rgb/yuv_rgb.h 84 | } 85 | 86 | SOURCES += \ 87 | source/Application/Application.cpp \ 88 | source/Camera/CameraController.cpp \ 89 | source/Camera/CameraWorker.cpp \ 90 | source/Client/Client.cpp \ 91 | source/Client/ClientWorker.cpp \ 92 | source/Interface/Interface.cpp \ 93 | source/Interface/LogModel.cpp \ 94 | source/QMLGLYUVWidget/QMLGLYUVWidget.cpp \ 95 | source/Statistics/Statistics.cpp \ 96 | source/common/Log.cpp \ 97 | source/main.cpp 98 | 99 | contains (DEFINES, CAM_QTMULTIMEDIA) { 100 | SOURCES += source/Camera/YUVProviderVideoSurface.cpp 101 | SOURCES += source/yuv2rgb/yuv_rgb.c 102 | } 103 | 104 | RESOURCES += qml.qrc \ 105 | assets/assets.qrc 106 | 107 | # Default rules for deployment. 108 | qnx: target.path = /tmp/$${TARGET}/bin 109 | else: unix:!android: target.path = /opt/$${TARGET}/bin 110 | !isEmpty(target.path): INSTALLS += target 111 | -------------------------------------------------------------------------------- /client/qt/source/qml/Views/LogView.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | import QtQuick 2.15 19 | import QtQuick.Controls 2.15 20 | import QtQuick.Controls.Universal 2.15 21 | import QtQuick.Layouts 1.12 22 | 23 | import QtGraphicalEffects 1.0 24 | 25 | import com.iotfacerecognition.log 1.0 26 | 27 | import ".." 28 | 29 | Item { 30 | id: logView 31 | 32 | readonly property string title: qsTr("Logs") 33 | 34 | Column { 35 | id: header 36 | anchors.left: parent.left 37 | anchors.right: parent.right 38 | 39 | anchors.top: parent.top 40 | anchors.margins: logList.anchors.margins 41 | 42 | RowLayout { 43 | id: headerLayout 44 | anchors.left: parent.left 45 | anchors.right: parent.right 46 | 47 | spacing: 25 48 | 49 | Label { 50 | text: qsTr("Timestamp") 51 | Layout.preferredWidth: tsMetric.width 52 | 53 | Label { 54 | id: tsMetric 55 | text: "00-00-0000 / 00:00:00" 56 | visible: false 57 | } 58 | } 59 | 60 | Label { 61 | id: typeLabel 62 | text: qsTr("Type") 63 | } 64 | 65 | Label { 66 | Layout.fillWidth: true 67 | 68 | text: qsTr("Description") 69 | } 70 | } 71 | 72 | Rectangle { 73 | anchors.left: parent.left 74 | anchors.right: parent.right 75 | 76 | height: 2 77 | color: "lightgray" 78 | opacity: 0.5 79 | } 80 | } 81 | 82 | ListView { 83 | id: logList 84 | 85 | anchors.left: parent.left 86 | anchors.right: parent.right 87 | anchors.top: header.bottom 88 | anchors.bottom: parent.bottom 89 | anchors.margins: 10 90 | 91 | model: intf.logModel 92 | 93 | clip: true 94 | 95 | spacing: 5 96 | 97 | ScrollBar.vertical: ScrollBar { id: scrollBar; } 98 | 99 | delegate: RowLayout { 100 | width: logList.width - scrollBar.width 101 | 102 | spacing: headerLayout.spacing 103 | 104 | Label { 105 | Layout.preferredWidth: tsMetric.width 106 | 107 | text: model.timeStamp 108 | } 109 | 110 | Image { 111 | 112 | Layout.preferredWidth: typeLabel.width 113 | Layout.preferredHeight: tsMetric.height 114 | 115 | fillMode: Image.PreserveAspectFit 116 | horizontalAlignment: Image.AlignHCenter 117 | 118 | source: { 119 | switch (model.type) { 120 | default: 121 | case Log.INFORMATION: 122 | return Common.informationIcon 123 | case Log.WARNING: 124 | return Common.warningIcon 125 | case Log.ERROR: 126 | return Common.errorIcon 127 | } 128 | } 129 | } 130 | 131 | Label { 132 | Layout.fillWidth: true 133 | 134 | wrapMode: Text.Wrap 135 | 136 | text: model.context 137 | } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /client/qt/source/qml/Popups/ConnectionPopup.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | import QtQuick 2.15 19 | import QtQuick.Controls 2.15 20 | import QtQuick.Controls.Universal 2.15 21 | import QtQuick.Layouts 1.12 22 | 23 | import Qt.labs.settings 1.1 24 | 25 | import "../Widgets" as Widgets 26 | 27 | 28 | Widgets.ModalPopup { 29 | title: "Connection" 30 | 31 | widthRate: 2 32 | heightRate: 1.5 33 | 34 | context: Component { 35 | Item { 36 | id: parentItem 37 | 38 | implicitHeight: childrenRect.height 39 | 40 | Settings { 41 | id: connectionSettings 42 | 43 | property alias serverAddress: hostField.text 44 | property alias port: portField.text 45 | property alias autoConnect: autoConnectToggle.checked 46 | 47 | Component.onCompleted: { 48 | if (autoConnect) 49 | connect() 50 | } 51 | } 52 | 53 | function connect() { 54 | client.connect("wss://%1:%2".arg(hostField.length > 0 ? hostField.text : hostField.placeholderText) 55 | .arg(portField.length > 0 ? portField.text : portField.placeholderText)) 56 | } 57 | 58 | ColumnLayout { 59 | anchors.left: parent.left 60 | anchors.right: parent.right 61 | 62 | GridLayout { 63 | Layout.fillWidth: true 64 | Layout.fillHeight: true 65 | 66 | columns: 2 67 | 68 | enabled: !client.connected 69 | 70 | Label { 71 | text: qsTr("Host Address:") 72 | } 73 | 74 | TextField { 75 | id: hostField 76 | implicitWidth: ipMetric.width 77 | 78 | placeholderText: "127.0.0.1" 79 | 80 | TextMetrics { 81 | id: ipMetric 82 | text: " 255.255.255.255 " 83 | } 84 | } 85 | 86 | Label { 87 | 88 | text: qsTr("Port:") 89 | } 90 | 91 | TextField { 92 | id: portField 93 | placeholderText: "50000" 94 | 95 | validator: IntValidator {bottom: 0; top: 65535} 96 | } 97 | 98 | Label { 99 | text: qsTr("URL:") 100 | } 101 | 102 | Label { 103 | text: qsTr("wss://%1:%2").arg(hostField.length > 0 ? hostField.text : hostField.placeholderText) 104 | .arg(portField.length > 0 ? portField.text : portField.placeholderText) 105 | } 106 | } 107 | 108 | CheckBox { 109 | id: autoConnectToggle 110 | Layout.fillWidth: true 111 | text: qsTr("Auto connect") 112 | } 113 | 114 | RoundButton { 115 | Layout.fillWidth: true 116 | text: client.connected ? qsTr("DISCONNECT") : qsTr("CONNECT!") 117 | 118 | onClicked: { 119 | if (client.connected) 120 | client.disconnect() 121 | else 122 | connect() 123 | } 124 | } 125 | } 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /client/qt/source/Statistics/Statistics.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef STATISTICS_HPP 19 | #define STATISTICS_HPP 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | class StatisticsSettings; 29 | class SettingObject; 30 | 31 | namespace QtCharts 32 | { 33 | class QPieSeries; 34 | class QLineSeries; 35 | } 36 | 37 | namespace StatisticsTypes 38 | { 39 | template 40 | struct DataType; 41 | 42 | template<> 43 | struct DataType< QtCharts::QLineSeries * const > { 44 | using type = QPointF; 45 | 46 | using ctnrType = QVector< type >; 47 | }; 48 | 49 | template<> 50 | struct DataType< QtCharts::QPieSeries * const > { 51 | using type = QPair; 52 | 53 | using ctnrType = QVector< type >; 54 | }; 55 | } 56 | 57 | class Statistics : public QObject 58 | { 59 | Q_OBJECT 60 | 61 | Q_PROPERTY(QList settingModel READ settingModel NOTIFY settingModelChanged) 62 | Q_PROPERTY(StatisticsSettings* settings READ settings CONSTANT) 63 | 64 | public: 65 | enum SeriesType { 66 | RecognizedFacesPieSeries, 67 | RecognizedMaxPredictionObjectsPieSeries, 68 | TaggedFacesLineSeries, 69 | UntaggedFacesLineSeries, 70 | MaximumObjectPredictionRateLineSeries, 71 | InternetUsageSentCumulativeLineSeries, 72 | InternetUsageReceivedCumulativeLineSeries, 73 | InternetUsageSentLineSeries, 74 | InternetUsageReceivedLineSeries, 75 | FPSLineSeries 76 | }; 77 | Q_ENUM(SeriesType); 78 | 79 | 80 | explicit Statistics(QObject *parent = nullptr); 81 | ~Statistics(); 82 | 83 | Q_INVOKABLE bool registerSeries(SeriesType seriesType); 84 | Q_INVOKABLE bool deregisterSeries(SeriesType seriesType, bool _remove = true); 85 | 86 | Q_INVOKABLE bool attachSeries(QObject* object); 87 | Q_INVOKABLE bool detachSeries(QObject* object); 88 | 89 | StatisticsSettings* settings() const; 90 | QList settingModel() const; 91 | 92 | void addData(SeriesType seriesType, const QPointF& data); 93 | void incrementData(SeriesType seriesType, const QString& data); 94 | 95 | signals: 96 | void settingModelChanged(QList settingModel); 97 | 98 | private: 99 | void setupSettings(); 100 | 101 | struct Series { 102 | void* data = nullptr; 103 | 104 | QObject* ptr = nullptr; 105 | 106 | bool isAttached() { 107 | return (ptr != nullptr); 108 | } 109 | }; 110 | 111 | template 112 | QPair minmax(T data); 113 | 114 | void loadData(QtCharts::QLineSeries* object, 115 | StatisticsTypes::DataType::ctnrType * data); 116 | 117 | void loadData(QtCharts::QPieSeries* object, 118 | StatisticsTypes::DataType::ctnrType * data); 119 | 120 | void unloadData(QtCharts::QLineSeries* object, 121 | StatisticsTypes::DataType::ctnrType * data); 122 | 123 | void unloadData(QtCharts::QPieSeries* object, 124 | StatisticsTypes::DataType::ctnrType * data); 125 | 126 | QMap m_series; 127 | 128 | Series* getSeries(SeriesType seriesType); 129 | Series* getSeries(const QObject* object); 130 | 131 | QObject* getAverageSeries(QtCharts::QLineSeries* lineSeries); 132 | 133 | StatisticsSettings* m_settings; 134 | 135 | QList m_settingModel; 136 | 137 | std::optional getSeriesType(const QObject* object); 138 | }; 139 | 140 | #endif // STATISTICS_HPP 141 | -------------------------------------------------------------------------------- /client/qt/source/common/SettingObject.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #ifndef SETTINGOBJECT_H 20 | #define SETTINGOBJECT_H 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | 28 | class SettingObject : public QObject 29 | { 30 | Q_OBJECT 31 | 32 | Q_PROPERTY(QString description READ description CONSTANT) 33 | Q_PROPERTY(QVariantMap ctx READ ctx CONSTANT) 34 | Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged) 35 | 36 | Q_PROPERTY(QString keyType MEMBER keyType CONSTANT) 37 | Q_PROPERTY(QString keyDropDownCtx MEMBER keyDropDownCtx CONSTANT) 38 | Q_PROPERTY(QString keyMin MEMBER keyMin CONSTANT) 39 | Q_PROPERTY(QString keyMax MEMBER keyMax CONSTANT) 40 | 41 | public: 42 | inline static const QString keyType {"type"}; 43 | inline static const QString keyDropDownCtx {"model"}; 44 | inline static const QString keyMin {"min"}; 45 | inline static const QString keyMax {"max"}; 46 | inline static const QString keyText {"text"}; 47 | 48 | enum SettingType { 49 | TextField, 50 | TextFieldInt, 51 | Button, 52 | ToggleButton, 53 | DropDown, 54 | Slider 55 | }; 56 | Q_ENUM(SettingType) 57 | 58 | struct Setting { 59 | QString description; 60 | QVariantMap ctx; 61 | QPair property { nullptr, QMetaProperty() }; 62 | std::function slot = nullptr; 63 | }; 64 | 65 | static inline QPair makePropertyPair(QObject* parent, const char* propertyName) 66 | { 67 | assert(parent->property(propertyName).isValid()); 68 | 69 | return qMakePair(parent, 70 | parent->metaObject()->property(parent->metaObject()->indexOfProperty(propertyName))); 71 | } 72 | 73 | static inline void newSetting(QList& list, QObject* parent, const Setting& setting) 74 | { 75 | list.push_back(new SettingObject(parent, setting)); 76 | } 77 | 78 | 79 | private: 80 | Setting m_setting; 81 | 82 | public: 83 | inline explicit SettingObject(QObject *parent, const Setting& setting) 84 | : QObject(parent), 85 | m_setting(setting) 86 | { 87 | if (m_setting.property.second.isValid()) 88 | { 89 | if (m_setting.property.second.hasNotifySignal()) 90 | { 91 | connect(m_setting.property.first, 92 | m_setting.property.second.notifySignal(), 93 | this, 94 | SettingObject::staticMetaObject.property(SettingObject::staticMetaObject.indexOfProperty("value")) 95 | .notifySignal()); 96 | } 97 | } 98 | } 99 | 100 | inline QString description() const 101 | { 102 | return m_setting.description; 103 | } 104 | 105 | inline QVariant value() const 106 | { 107 | if (m_setting.property.second.isValid()) 108 | return m_setting.property.second.read(m_setting.property.first); 109 | else 110 | return QVariant(); 111 | } 112 | 113 | inline QVariantMap ctx() const 114 | { 115 | return m_setting.ctx; 116 | } 117 | 118 | inline void invokeSlot() 119 | { 120 | if (m_setting.slot) 121 | m_setting.slot(value()); 122 | } 123 | 124 | public slots: 125 | inline void setValue(const QVariant& value) 126 | { 127 | if (this->value() == value) 128 | return; 129 | 130 | if (m_setting.slot) 131 | { 132 | m_setting.slot(value); 133 | return; 134 | } 135 | else if (!m_setting.property.second.isWritable()) 136 | return; 137 | 138 | if ( m_setting.property.second.write(m_setting.property.first, value) ) 139 | emit valueChanged(); 140 | } 141 | 142 | signals: 143 | void valueChanged(); 144 | 145 | }; 146 | 147 | #endif // SETTINGOBJECT_H 148 | -------------------------------------------------------------------------------- /server/source/ClientDialog/ClientDialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-server 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "ClientDialog.h" 19 | #include "ui_ClientDialog.h" 20 | 21 | #include 22 | 23 | #include "Client/Client.h" 24 | #include "Server/Server.h" 25 | 26 | ClientDialog::ClientDialog(Client* client, QWidget *parent) : 27 | QDialog(parent), 28 | ui(new Ui::ClientDialog) 29 | { 30 | assert(client); 31 | 32 | ui->setupUi(this); 33 | 34 | QGraphicsScene* scene = new QGraphicsScene(ui->graphicsView); 35 | ui->graphicsView->setScene(scene); 36 | 37 | scene->addItem(&primaryDisplay); 38 | scene->addItem(&secondaryDisplay); 39 | scene->addItem(&tertiaryDisplay); 40 | 41 | secondaryDisplayCleaner.setInterval(3000); 42 | connect(&secondaryDisplayCleaner, &QTimer::timeout, this, [this]() { 43 | secondaryDisplay.setPixmap(QPixmap()); 44 | }); 45 | 46 | tertiaryDisplayCleaner.setInterval(3000); 47 | connect(&tertiaryDisplayCleaner, &QTimer::timeout, this, [this]() { 48 | tertiaryDisplay.setPixmap(QPixmap()); 49 | }); 50 | 51 | connect(client, &Client::primaryDisplayUpdated, this, &ClientDialog::updatePrimaryDisplay); 52 | connect(client, &Client::doneFace, this, &ClientDialog::drawFaceIdentificators); 53 | connect(client, &Client::doneObject, this, &ClientDialog::drawTextBox); 54 | 55 | connect(client, &Client::destroyed, this, &ClientDialog::accept); 56 | 57 | connect(client, &Client::log, this, &ClientDialog::print); 58 | } 59 | 60 | ClientDialog::~ClientDialog() 61 | { 62 | delete ui; 63 | } 64 | 65 | void ClientDialog::on_okButton_clicked() 66 | { 67 | accept(); 68 | } 69 | 70 | void ClientDialog::updatePrimaryDisplay(const QPixmap &pixmap) 71 | { 72 | Client *client = qobject_cast(sender()); 73 | 74 | if (!client) 75 | return; 76 | 77 | primaryDisplay.setPixmap(pixmap); 78 | } 79 | 80 | void ClientDialog::drawTextBox(const QVector > &list) 81 | { 82 | secondaryDisplayCleaner.stop(); 83 | 84 | QPixmap pixmap(primaryDisplay.pixmap().width(), primaryDisplay.pixmap().height()); 85 | pixmap.fill(Qt::transparent); 86 | 87 | int counter = 0; 88 | for (const auto& it : list) 89 | { 90 | QPainter paint(&pixmap); 91 | 92 | QColor colorLine(128, 0, 0, 200); 93 | QColor colorText(255, 255, 255, 255); 94 | 95 | QFont font; 96 | font.setPointSize(12); 97 | paint.setFont(font); 98 | 99 | const QString& str = QString("%1: %2").arg(it.first).arg(it.second); 100 | 101 | QFontMetrics fMetrics(paint.font()); 102 | QRect textRect(20, 20 + fMetrics.size(Qt::TextSingleLine, str).height() * counter, fMetrics.size(Qt::TextSingleLine, str).width(), fMetrics.size(Qt::TextSingleLine, str).height()); 103 | paint.fillRect(textRect, QBrush(colorLine)); 104 | 105 | paint.setPen(colorText); 106 | paint.drawText(textRect, str); 107 | 108 | ++counter; 109 | } 110 | 111 | tertiaryDisplay.setPixmap(pixmap); 112 | 113 | secondaryDisplayCleaner.start(); 114 | } 115 | 116 | void ClientDialog::drawFaceIdentificators(const QVector > &identificators) 117 | { 118 | tertiaryDisplayCleaner.stop(); 119 | 120 | QPixmap pixmap(primaryDisplay.pixmap().width(), primaryDisplay.pixmap().height()); 121 | pixmap.fill(Qt::transparent); 122 | for(const auto &it : identificators) 123 | { 124 | QPainter paint(&pixmap); 125 | 126 | QColor colorLine(128, 0, 0, 200); 127 | QColor colorText(255, 255, 255, 255); 128 | 129 | QFont font; 130 | font.setPointSize(18); 131 | paint.setFont(font); 132 | 133 | const QRect& rect = it.first; 134 | paint.setPen(QPen(colorLine, 3)); 135 | paint.drawRect(rect); 136 | 137 | const QString& str = it.second; 138 | 139 | QFontMetrics fMetrics(paint.font()); 140 | QRect textRect(rect.x(), rect.y() + rect.height(), fMetrics.size(Qt::TextSingleLine, str).width(), fMetrics.size(Qt::TextSingleLine, str).height()); 141 | paint.fillRect(textRect, QBrush(colorLine)); 142 | 143 | paint.setPen(colorText); 144 | paint.drawText(textRect, str); 145 | } 146 | 147 | secondaryDisplay.setPixmap(pixmap); 148 | 149 | tertiaryDisplayCleaner.start(); 150 | } 151 | 152 | void ClientDialog::print(const QString &message) 153 | { 154 | ui->clientLog->append(QString("[%1] %2
").arg(Server::generateDateTime(), message)); 155 | } 156 | -------------------------------------------------------------------------------- /server/source/SocketHandler/SocketHandler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-server 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "SocketHandler.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #include "Client/Client.h" 32 | 33 | #include "config.h" 34 | 35 | Q_DECLARE_METATYPE(QWebSocket*) 36 | 37 | SocketHandler::SocketHandler(QObject *parent, QSettings* config) 38 | : QObject(parent), 39 | m_config(config) 40 | { 41 | config->beginGroup(CONFIG_CRT); 42 | m_testMode = config->value(CONFIG_CRT_TESTMODE, CONFIG_CRT_DEFAULT_TESTMODE).toBool(); 43 | m_keyFile = config->value(CONFIG_CRT_KEY_LOCATION, CONFIG_CRT_DEFAULT_KEY_LOCATION).toString(); 44 | m_crtFile = config->value(CONFIG_CRT_CRT_LOCATION, CONFIG_CRT_DEFAULT_CRT_LOCATION).toString(); 45 | m_keyAlgorithm = config->value(CONFIG_CRT_KEYALGORITHM, CONFIG_CRT_DEFAULT_KEYALGORITHM).toInt(); 46 | m_encodingFormat = config->value(CONFIG_CRT_ENCODINGFORMAT, CONFIG_CRT_DEFAULT_ENCODINGFORMAT).toInt(); 47 | config->endGroup(); 48 | 49 | config->beginGroup(CONFIG_CONN); 50 | m_port = static_cast(config->value(CONFIG_CONN_PORT, CONFIG_CONN_DEFAULT_PORT).toUInt()); 51 | m_serverName = config->value(CONFIG_CONN_SERVERNAME, CONFIG_CONN_DEFAULT_SERVERNAME).toString(); 52 | config->endGroup(); 53 | 54 | webSocketServer = new QWebSocketServer(m_serverName, QWebSocketServer::SslMode::SecureMode, nullptr); 55 | webSocketServer->moveToThread(&socketThread); 56 | connect(&socketThread, &QThread::finished, webSocketServer, &QObject::deleteLater); 57 | socketThread.start(); 58 | 59 | QSslConfiguration sslConfiguration; 60 | QFile crtFile(m_crtFile); 61 | QFile keyFile(m_keyFile); 62 | crtFile.open(QIODevice::ReadOnly); 63 | keyFile.open(QIODevice::ReadOnly); 64 | QSslCertificate certificate(&crtFile, static_cast(m_encodingFormat)); 65 | QSslKey sslKey(&keyFile, static_cast(m_keyAlgorithm), static_cast(m_encodingFormat)); 66 | crtFile.close(); 67 | keyFile.close(); 68 | sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone); 69 | sslConfiguration.setLocalCertificate(certificate); 70 | sslConfiguration.setPrivateKey(sslKey); 71 | sslConfiguration.setProtocol(QSsl::TlsV1_3OrLater); 72 | 73 | QMetaObject::invokeMethod(webSocketServer, [this, sslConfiguration] () { 74 | webSocketServer->setSslConfiguration(sslConfiguration); 75 | 76 | if (webSocketServer->listen(QHostAddress::Any, m_port)) 77 | { 78 | connect(webSocketServer, &QWebSocketServer::newConnection, this, &SocketHandler::onNewConnection); 79 | connect(webSocketServer, &QWebSocketServer::sslErrors, this, &SocketHandler::onSslErrors); 80 | emit ("Started listening on port:" + QString::number(m_port)); 81 | } 82 | else 83 | { 84 | throw std::runtime_error("QWebSocketServer can not listen!"); 85 | } 86 | }, Qt::BlockingQueuedConnection); 87 | } 88 | 89 | SocketHandler::~SocketHandler() 90 | { 91 | QMetaObject::invokeMethod(webSocketServer, [this] () { 92 | webSocketServer->close(); 93 | emit log("Stopped listening."); 94 | }, Qt::BlockingQueuedConnection); 95 | 96 | 97 | socketThread.quit(); 98 | socketThread.wait(); 99 | } 100 | 101 | void SocketHandler::onNewConnection() 102 | { 103 | emit log("A client has connected!"); 104 | QWebSocket *socket = webSocketServer->nextPendingConnection(); 105 | 106 | connect(socket, &QWebSocket::disconnected, this, &SocketHandler::onDisconnect); 107 | 108 | Client *client = new Client(nullptr, socket, m_config); 109 | client->moveToThread(socket->thread()); 110 | 111 | emit newClient(client); 112 | } 113 | 114 | void SocketHandler::onSslErrors(const QList& errors) 115 | { 116 | if (!m_testMode) 117 | { 118 | QString errStr = "SSL Error:"; 119 | for (const auto &it : errors) 120 | { 121 | errStr += "\n" + it.errorString(); 122 | } 123 | 124 | throw std::runtime_error(errStr.toStdString().c_str()); 125 | } 126 | } 127 | 128 | void SocketHandler::onDisconnect() 129 | { 130 | QWebSocket *socket = qobject_cast(sender()); 131 | if (socket) 132 | { 133 | socket->deleteLater(); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /client/qt/source/qml/Popups/AboutPopup.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | import QtQuick 2.15 19 | import QtQuick.Controls 2.15 20 | import QtQuick.Controls.Universal 2.15 21 | 22 | import "../Widgets" as Widgets 23 | import ".." 24 | 25 | Widgets.ModalPopup { 26 | title: "About" 27 | 28 | context: Component { 29 | Label { 30 | id: aboutLabel 31 | 32 | textFormat: Text.StyledText 33 | 34 | wrapMode: Text.Wrap 35 | text: "

" + Common.title + "

" + 36 | "
    " + 37 | "
  • Address: github/fuzun/iot-facerecognition
  • " + 38 | "
  • License: GNU Affero GPL
  • " + 39 | "
  • Author: fuzun
  • " + 40 | "
  • Version: " + Qt.application.version + "
  • " + 41 | "
" + 42 | 43 | "

Used Open Source Projects:


" + 44 | 45 | "

Qt Framework Base

" + 46 | "
    " + 47 | "
  • Address: https://github.com/qt/qtbase" + 48 | "
  • Used under GNU LGPL Version 3 license
  • " + 49 | "
" + 50 | 51 | "

qtvirtualkeyboard

" + 52 | "

Qt Module - QtQuick virtual keyboard

" + 53 | "
    " + 54 | "
  • Address: https://github.com/qt/qtvirtualkeyboard" + 55 | "
  • Used under GNU GPL Version 3 license
  • " + 56 | "
" + 57 | 58 | "

qtcharts

" + 59 | "

Qt Module - QtCharts module

" + 60 | "
    " + 61 | "
  • Address: https://github.com/qt/qtcharts" + 62 | "
  • Used under GNU GPL Version 3 license
  • " + 63 | "
" + 64 | 65 | "

qtwebsockets

" + 66 | "

Qt Module - Qt WebSockets

" + 67 | "
    " + 68 | "
  • Address: https://github.com/qt/qtwebsockets" + 69 | "
  • Used under GNU LGPL Version 3 license
  • " + 70 | "
" + 71 | 72 | "

qtquickcontrols2

" + 73 | "

Qt Module - Qt Quick Controls 2

" + 74 | "
    " + 75 | "
  • Address: https://github.com/qt/qtquickcontrols2" + 76 | "
  • Used under GNU LGPL Version 3 license
  • " + 77 | "
" + 78 | 79 | "

OpenMaxIL-cpp

" + 80 | "

OpenMax IL C++ wrapper for RaspberryPi

" + 81 | "
    " + 82 | "
  • Address: https://github.com//dridri/OpenMaxIL-cpp" + 83 | "
  • Used under MIT License
  • " + 84 | "
" + 85 | 86 | "

SampleYUVRenderer

" + 87 | "

Very basic sketch of rendering YUV frames via Qt/OpenGL

" + 88 | "
    " + 89 | "
  • Address: https://github.com//MasterAler/SampleYUVRenderer" + 90 | "
  • Used under MIT License
  • " + 91 | "
" + 92 | 93 | "

Qt Official Docs

" + 94 | "

Scene Graph - OpenGL Under QML

" + 95 | "
    " + 96 | "
  • Address: https://doc-snapshots.qt.io/qt5-5.15/qtquick-scenegraph-openglunderqml-example.html" + 97 | "
  • Used under BSD License
  • " + 98 | "
" + 99 | 100 | "

yuv2rgb

" + 101 | "

C99 library for fast image conversion between yuv420p and rgb24

" + 102 | "
    " + 103 | "
  • Address: https://github.com/descampsa/yuv2rgb" + 104 | "
  • Used under BSD-3-Clause License
  • " + 105 | "
" + 106 | 107 | "

yuv2rgb

" + 108 | "

C99 library for fast image conversion between yuv420p and rgb24

" + 109 | "
    " + 110 | "
  • Address: https://github.com/descampsa/yuv2rgb" + 111 | "
  • Used under BSD-3-Clause License
  • " + 112 | "
" + 113 | 114 | "

libjpeg-turbo

" + 115 | "
    " + 116 | "
  • Address: https://github.com/libjpeg-turbo/libjpeg-turbo/blob/master" + 117 | "
  • Used under The Modified (3-clause) BSD License
  • " + 118 | "
" + 119 | 120 | "

Background Images

" + 121 | intf.readTextFile(Common.bgLicense) + 122 | 123 | "

Icons

" + 124 | intf.readTextFile(Common.iconLicense) 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /client/qt/source/Client/ClientSettings.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #ifndef CLIENTSETTINGS_H 20 | #define CLIENTSETTINGS_H 21 | 22 | #include "common/BaseSettings.hpp" 23 | 24 | class ClientSettings : public BaseSettings 25 | { 26 | Q_OBJECT 27 | 28 | Q_PROPERTY(bool objectDetectionEnabled READ objectDetectionEnabled WRITE setObjectDetectionEnabled NOTIFY objectDetectionEnabledChanged) 29 | Q_PROPERTY(size_t labelCount READ labelCount WRITE setLabelCount NOTIFY labelCountChanged) 30 | Q_PROPERTY(QString clientName READ clientName WRITE setClientName NOTIFY clientNameChanged) 31 | Q_PROPERTY(bool deterministicObjectDetection READ deterministicObjectDetection WRITE setDeterministicObjectDetection NOTIFY deterministicObjectDetectionChanged) 32 | Q_PROPERTY(bool faceRecognitionEnabled READ faceRecognitionEnabled WRITE setFaceRecognitionEnabled NOTIFY faceRecognitionEnabledChanged) 33 | Q_PROPERTY(bool ignoreSSLErrors READ ignoreSSLErrors WRITE setIgnoreSSLErrors NOTIFY ignoreSSLErrorsChanged) 34 | 35 | bool m_objectDetectionEnabled = true; 36 | size_t m_labelCount = 5; 37 | QString m_clientName {"Default"}; 38 | bool m_deterministicObjectDetection = false; 39 | bool m_faceRecognitionEnabled = true; 40 | bool m_ignoreSSLErrors = false; 41 | 42 | public: 43 | inline explicit ClientSettings(QObject *parent = nullptr, bool load = true) : BaseSettings(parent) 44 | { 45 | qRegisterMetaType(); 46 | 47 | if (!load) 48 | return; 49 | 50 | this->load(ClientSettings::staticMetaObject); 51 | } 52 | 53 | inline ~ClientSettings() 54 | { 55 | save(); 56 | } 57 | 58 | Q_INVOKABLE void save() 59 | { 60 | BaseSettings::save(ClientSettings::staticMetaObject); 61 | } 62 | 63 | Q_INVOKABLE void reset() 64 | { 65 | ClientSettings nonLoadedInstance(this, false); 66 | BaseSettings::reset(ClientSettings::staticMetaObject, &nonLoadedInstance); 67 | } 68 | 69 | inline bool objectDetectionEnabled() const 70 | { 71 | return m_objectDetectionEnabled; 72 | } 73 | 74 | inline size_t labelCount() const 75 | { 76 | return m_labelCount; 77 | } 78 | 79 | inline QString clientName() const 80 | { 81 | return m_clientName; 82 | } 83 | 84 | inline bool deterministicObjectDetection() const 85 | { 86 | return m_deterministicObjectDetection; 87 | } 88 | 89 | inline bool faceRecognitionEnabled() const 90 | { 91 | return m_faceRecognitionEnabled; 92 | } 93 | 94 | inline bool ignoreSSLErrors() const 95 | { 96 | return m_ignoreSSLErrors; 97 | } 98 | 99 | public slots: 100 | inline void setObjectDetectionEnabled(bool objectDetectionEnabled) 101 | { 102 | if (m_objectDetectionEnabled == objectDetectionEnabled) 103 | return; 104 | 105 | m_objectDetectionEnabled = objectDetectionEnabled; 106 | emit objectDetectionEnabledChanged(m_objectDetectionEnabled); 107 | } 108 | 109 | inline void setLabelCount(size_t labelCount) 110 | { 111 | if (m_labelCount == labelCount) 112 | return; 113 | 114 | m_labelCount = labelCount; 115 | emit labelCountChanged(m_labelCount); 116 | } 117 | 118 | inline void setClientName(const QString& clientName) 119 | { 120 | if (m_clientName == clientName) 121 | return; 122 | 123 | m_clientName = clientName; 124 | emit clientNameChanged(m_clientName); 125 | } 126 | 127 | inline void setDeterministicObjectDetection(bool deterministicObjectDetection) 128 | { 129 | if (m_deterministicObjectDetection == deterministicObjectDetection) 130 | return; 131 | 132 | m_deterministicObjectDetection = deterministicObjectDetection; 133 | emit deterministicObjectDetectionChanged(m_deterministicObjectDetection); 134 | } 135 | 136 | inline void setFaceRecognitionEnabled(bool faceRecognitionEnabled) 137 | { 138 | if (m_faceRecognitionEnabled == faceRecognitionEnabled) 139 | return; 140 | 141 | m_faceRecognitionEnabled = faceRecognitionEnabled; 142 | emit faceRecognitionEnabledChanged(m_faceRecognitionEnabled); 143 | } 144 | 145 | inline void setIgnoreSSLErrors(bool ignoreSSLErrors) 146 | { 147 | if (m_ignoreSSLErrors == ignoreSSLErrors) 148 | return; 149 | 150 | m_ignoreSSLErrors = ignoreSSLErrors; 151 | emit ignoreSSLErrorsChanged(m_ignoreSSLErrors); 152 | } 153 | 154 | signals: 155 | void objectDetectionEnabledChanged(bool objectDetectionEnabled); 156 | void labelCountChanged(size_t labelCount); 157 | void clientNameChanged(QString clientName); 158 | void deterministicObjectDetectionChanged(bool deterministicObjectDetection); 159 | void faceRecognitionEnabledChanged(bool faceRecognitionEnabled); 160 | void ignoreSSLErrorsChanged(bool ignoreSSLErrors); 161 | }; 162 | 163 | #endif // CLIENTSETTINGS_H 164 | -------------------------------------------------------------------------------- /client/qt/source/Application/Application.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #include "Application.hpp" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #ifdef NDEBUG 29 | #include 30 | #endif 31 | 32 | #include "common/Log.hpp" 33 | #include "common/SettingObject.hpp" 34 | #include "Client/Client.hpp" 35 | #include "Interface/Interface.hpp" 36 | #include "Interface/InterfaceSettings.hpp" 37 | #include "QMLGLYUVWidget/QMLGLYUVWidget.hpp" 38 | #include "Camera/CameraController.hpp" 39 | #include "Statistics/Statistics.hpp" 40 | 41 | #include "common/common.hpp" 42 | 43 | Application::Application(QObject *parent, QApplication* application) 44 | : QObject(parent) 45 | { 46 | QQuickStyle::setStyle("Universal"); 47 | 48 | Q_INIT_RESOURCE(qml); 49 | Q_INIT_RESOURCE(assets); 50 | 51 | qRegisterMetaType("size_t"); 52 | 53 | qmlRegisterType("com.iotfacerecognition.components", 1, 0, "YUVRendererWidget"); 54 | qmlRegisterUncreatableMetaObject(Log::staticMetaObject, "com.iotfacerecognition.log", 1, 0, "Log", "This type is uncreatable!"); 55 | qmlRegisterUncreatableType("com.iotfacerecognition.settings", 1, 0, "SettingObject", "This type is uncreatable!"); 56 | 57 | engine = new QQmlApplicationEngine(this); 58 | 59 | statistics = new Statistics(this); 60 | engine->rootContext()->setContextProperty("statistics", statistics); 61 | 62 | client = new Client(this, statistics); 63 | engine->rootContext()->setContextProperty("client", client); 64 | 65 | camera = new CameraController(this, statistics); 66 | engine->rootContext()->setContextProperty("camera", camera); 67 | 68 | connect(client, &Client::connectedChanged, this, [this]() { 69 | if (client->connected()) 70 | connect(camera, &CameraController::jpegReady, client, &Client::sendData); 71 | else 72 | disconnect(camera, &CameraController::jpegReady, client, &Client::sendData); 73 | }); 74 | 75 | interface = new Interface(this); 76 | engine->rootContext()->setContextProperty("intf", interface); 77 | connect(interface, &Interface::setLoggingToFile, this, &Application::setLoggingToFile); 78 | 79 | qRegisterMetaType(); 80 | connect(camera, &CameraController::log, interface, &Interface::log); 81 | connect(client, &Client::log, interface, &Interface::log); 82 | connect(interface, &Interface::log, this, &Application::log); 83 | 84 | const QUrl url(QStringLiteral("qrc:/source/qml/main.qml")); 85 | connect(engine, &QQmlApplicationEngine::objectCreated, 86 | application, [url](QObject *obj, const QUrl &objUrl) { 87 | if (!obj && url == objUrl) 88 | QCoreApplication::exit(-1); 89 | }, Qt::QueuedConnection); 90 | 91 | engine->load(url); 92 | } 93 | 94 | Application::~Application() 95 | { 96 | if(logStream) 97 | logStream->flush(); 98 | delete logStream; 99 | } 100 | 101 | void Application::log(const QVariant &str, Log::LogType type) 102 | { 103 | assert(type != Log::ERROR); 104 | 105 | const Log log(str, type); 106 | 107 | QString ctx = QString("[%1] %2: %3").arg(log.timeStamp(), log.typeStr(), log.ctx().toString()); 108 | 109 | if (logStream) 110 | *logStream << ctx; 111 | 112 | #ifndef NDEBUG 113 | qDebug() << ctx; 114 | #else 115 | std::string msg = ctx.toStdString(); 116 | 117 | switch (type) 118 | { 119 | case Log::LogType::ERROR: 120 | qCritical(msg.c_str()); 121 | if (!interface->settings()->testMode()) 122 | { 123 | throw std::runtime_error(msg.c_str()); 124 | } 125 | break; 126 | case Log::LogType::WARNING: 127 | qWarning(msg.c_str()); 128 | break; 129 | case Log::LogType::INFORMATION: 130 | default: 131 | qInfo(msg.c_str()); 132 | break; 133 | } 134 | #endif 135 | } 136 | 137 | void Application::setLoggingToFile(bool enabled) 138 | { 139 | if (enabled) 140 | { 141 | if (logFile) 142 | return; 143 | 144 | logFile = new QFile("log.txt", this); 145 | if(!logFile->open(QFile::Text | QFile::Append)) 146 | { 147 | log(tr("Could not open log output file!"), Log::ERROR); 148 | delete logFile; 149 | logFile = nullptr; 150 | } 151 | else 152 | { 153 | logStream = new QTextStream(logFile); 154 | } 155 | } 156 | else 157 | { 158 | if (!logFile) 159 | return; 160 | 161 | logStream->flush(); 162 | logFile->flush(); 163 | logFile->close(); 164 | 165 | delete logStream; 166 | logStream = nullptr; 167 | delete logFile; 168 | logFile = nullptr; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /client/qt/source/Camera/YUVProviderVideoSurface.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "YUVProviderVideoSurface.hpp" 19 | 20 | #include 21 | #include 22 | 23 | #ifdef TURBOJPEG_AVAILABLE 24 | #include "turbojpeg.h" 25 | #endif 26 | 27 | #include "yuv2rgb/yuv_rgb.h" 28 | 29 | #include "CameraSettings.hpp" 30 | #include "common/YUVFrame.hpp" 31 | 32 | YUVProviderVideoSurface::YUVProviderVideoSurface(QObject *parent, YUVFrame* frame, CameraSettings *settings) 33 | : QAbstractVideoSurface(parent), 34 | m_frame(frame), 35 | m_settings(settings) 36 | { 37 | assert(m_frame); 38 | assert(m_settings); 39 | 40 | #ifdef TURBOJPEG_AVAILABLE 41 | tjHandle = tjInitCompress(); 42 | #endif 43 | } 44 | 45 | YUVProviderVideoSurface::~YUVProviderVideoSurface() 46 | { 47 | #ifdef TURBOJPEG_AVAILABLE 48 | tjDestroy(tjHandle); 49 | #endif 50 | 51 | cleanBuffer(); 52 | } 53 | 54 | bool YUVProviderVideoSurface::present(const QVideoFrame &frame) 55 | { 56 | assert(m_frame); 57 | 58 | if (frame.pixelFormat() != QVideoFrame::Format_YUV420P 59 | && frame.pixelFormat() != QVideoFrame::Format_RGB32) 60 | { 61 | setError(IncorrectFormatError); 62 | return false; 63 | } 64 | 65 | if (!m_frame) 66 | return false; 67 | 68 | m_frame->lockForWrite(); 69 | 70 | QVideoFrame mapped = const_cast(frame); 71 | 72 | if(!mapped.isValid() || !mapped.map(QAbstractVideoBuffer::ReadOnly)) 73 | { 74 | setError(ResourceError); 75 | return false; 76 | } 77 | 78 | if (m_frame->buffer && (m_frame->width != mapped.width() || m_frame->height != mapped.height())) 79 | { 80 | cleanBuffer(); 81 | } 82 | 83 | if (!m_frame->buffer) 84 | { 85 | m_frame->width = mapped.width(); 86 | m_frame->height = mapped.height(); 87 | m_frame->buffer = new YUVFrame::BufferType[m_frame->size()]; 88 | } 89 | 90 | if (frame.pixelFormat() == QVideoFrame::Format_RGB32) 91 | { 92 | // convert to YUV420 93 | #ifdef _YUVRGB_SSE2_ 94 | rgb32_yuv420_sseu 95 | #else 96 | rgb32_yuv420_std 97 | #endif 98 | (frame.width(), 99 | frame.height(), 100 | frame.bits(), 101 | frame.width() * 4, 102 | m_frame->y().second, 103 | m_frame->v().second, 104 | m_frame->u().second, 105 | frame.width(), 106 | (frame.width() + 1) / 2, 107 | YCbCrType::YCBCR_709); 108 | } 109 | else if (frame.pixelFormat() == QVideoFrame::Format_YUV420P) 110 | { 111 | memcpy(m_frame->buffer, 112 | mapped.bits(), 113 | static_cast(mapped.mappedBytes()) > m_frame->size() ? m_frame->size() : mapped.mappedBytes()); 114 | } 115 | else 116 | { 117 | assert(false); 118 | } 119 | 120 | m_frame->unlock(); 121 | 122 | emit updated(); 123 | 124 | // Encode JPEG 125 | 126 | #ifdef TURBOJPEG_AVAILABLE 127 | unsigned char* jpegBuffer = nullptr; 128 | 129 | unsigned long bufSize; 130 | 131 | tjCompress2(tjHandle, 132 | mapped.bits(), 133 | mapped.width(), 134 | mapped.bytesPerLine(), 135 | mapped.height(), 136 | TJPF_BGRA, 137 | &jpegBuffer, 138 | &bufSize, 139 | TJSAMP_420, 140 | m_settings->jpegQuality(), 141 | TJFLAG_FASTDCT); 142 | 143 | if (jpegBuffer && bufSize > 0) 144 | { 145 | QByteArray bArray(bufSize, Qt::Initialization::Uninitialized); 146 | memcpy(bArray.data(), jpegBuffer, bufSize); 147 | emit jpegReady(bArray); 148 | 149 | tjFree(jpegBuffer); 150 | } 151 | 152 | #else 153 | const QImage img(mapped.bits(), 154 | mapped.width(), 155 | mapped.height(), 156 | QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat())); 157 | QByteArray bArray; 158 | QBuffer buffer(&bArray); 159 | img.save(&buffer, "JPEG"); 160 | emit jpegReady(bArray); 161 | 162 | #endif 163 | 164 | mapped.unmap(); 165 | 166 | return true; 167 | } 168 | 169 | void YUVProviderVideoSurface::cleanBuffer() 170 | { 171 | assert(m_frame); 172 | 173 | if (m_frame) 174 | { 175 | m_frame->lockForWrite(); 176 | if (m_frame->buffer) 177 | { 178 | delete[] static_cast(m_frame->buffer); 179 | m_frame->buffer = nullptr; 180 | } 181 | m_frame->unlock(); 182 | } 183 | } 184 | 185 | QList YUVProviderVideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const 186 | { 187 | QList ret; 188 | 189 | if (type == QAbstractVideoBuffer::NoHandle) 190 | return (ret << QVideoFrame::PixelFormat::Format_YUV420P << QVideoFrame::PixelFormat::Format_RGB32); 191 | else 192 | { 193 | return ret; 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /client/qt/source/qml/Widgets/ModalPopup.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | import QtQuick 2.15 19 | import QtQuick.Controls 2.15 20 | import QtQuick.Controls.Universal 2.15 21 | import QtQuick.Layouts 1.12 22 | 23 | import QtGraphicalEffects 1.0 24 | 25 | import ".." 26 | 27 | Popup { 28 | id: popup 29 | 30 | modal: true 31 | 32 | x: root.width / 2 - width / 2 33 | y: root.height / 2 - height / 2 - root.header.height 34 | 35 | property real widthRate: 1.5 36 | property real heightRate: 1.35 37 | 38 | width: root.width / widthRate 39 | height: root.height / heightRate 40 | 41 | property string title 42 | property Component context: undefined 43 | 44 | Component.onCompleted: { 45 | console.assert(context != null) 46 | } 47 | 48 | Connections { 49 | target: root.inputPanel 50 | 51 | function onActiveChanged() { 52 | const diff = (popup.y + root.header.height + popup.height - (root.inputPanelY)) 53 | if (root.inputPanel.active) 54 | popup.y -= diff 55 | else 56 | popup.y = Qt.binding(function() { return root.height / 2 - height / 2 - root.header.height }) 57 | } 58 | } 59 | 60 | contentItem: Item { 61 | 62 | ColumnLayout { 63 | anchors.fill: parent 64 | 65 | implicitWidth: childrenRect.width 66 | implicitHeight: childrenRect.height 67 | 68 | Label { 69 | id: titleLabel 70 | Layout.fillWidth: true 71 | text: title 72 | horizontalAlignment: Text.AlignHCenter 73 | 74 | visible: title.length > 0 75 | } 76 | 77 | Rectangle { 78 | Layout.fillWidth: true 79 | height: 2 80 | color: "lightgray" 81 | opacity: 0.5 82 | 83 | visible: titleLabel.visible 84 | } 85 | 86 | Flickable { 87 | Layout.fillWidth: true 88 | Layout.fillHeight: true 89 | 90 | readonly property bool contentExceedsNaturalHeight: ctxLoader.implicitHeight > height 91 | 92 | contentWidth: width 93 | contentHeight: contentExceedsNaturalHeight ? ctxLoader.implicitHeight : height 94 | 95 | ScrollBar.vertical: ScrollBar { id: scrollBar; visible: parent.contentExceedsNaturalHeight; width: visible ? implicitWidth : 0 } 96 | 97 | clip: true 98 | 99 | Loader { 100 | id: ctxLoader 101 | 102 | anchors.left: parent.left 103 | anchors.right: parent.right 104 | anchors.rightMargin: scrollBar.width 105 | anchors.verticalCenter: parent.verticalCenter 106 | 107 | sourceComponent: context 108 | 109 | Connections { 110 | target: ctxLoader.item 111 | 112 | ignoreUnknownSignals: true 113 | 114 | function onClosePopup() { 115 | popup.close() 116 | } 117 | } 118 | } 119 | } 120 | 121 | RoundButton { 122 | Layout.fillWidth: true 123 | 124 | text: "Close" 125 | 126 | onClicked: { 127 | popup.close() 128 | } 129 | } 130 | } 131 | } 132 | 133 | background: Item { 134 | FastBlur { 135 | id: bgBlur 136 | 137 | anchors.fill: parent 138 | 139 | radius: 0 140 | 141 | Behavior on radius { 142 | NumberAnimation { 143 | duration: 200 144 | easing.type: Easing.InSine 145 | } 146 | } 147 | 148 | Connections { 149 | target: popup 150 | 151 | function onVisibleChanged() { 152 | if (popup.visible) { 153 | if (!root.background.isBlurred) 154 | bgBlur.radius = 64 155 | } else { 156 | bgBlur.radius = 0 157 | } 158 | } 159 | } 160 | 161 | source: ShaderEffectSource { 162 | sourceItem: root.background 163 | sourceRect: Qt.rect(popup.x, popup.y + root.header.height, popup.width, 164 | popup.height) 165 | } 166 | } 167 | 168 | Rectangle { 169 | anchors.fill: parent 170 | color: Common.setColorAlpha(bgColor, 0.15) 171 | 172 | readonly property color bgColor: root.isThemeDark ? "darkgray" : "lightgray" 173 | readonly property color borderColor: bgColor //"#00ABA9" 174 | 175 | border.width: 2 176 | border.color: Common.setColorAlpha(borderColor, 0.85) 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /client/qt/source/yuv2rgb/yuv_rgb.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Adrien Descamps 2 | // Distributed under BSD 3-Clause License 3 | 4 | // Provide optimized functions to convert images from 8bits yuv420 to rgb24 format 5 | 6 | // There are a few slightly different variations of the YCbCr color space with different parameters that 7 | // change the conversion matrix. 8 | // The three most common YCbCr color space, defined by BT.601, BT.709 and JPEG standard are implemented here. 9 | // See the respective standards for details 10 | // The matrix values used are derived from http://www.equasys.de/colorconversion.html 11 | 12 | // YUV420 is stored as three separate channels, with U and V (Cb and Cr) subsampled by a 2 factor 13 | // For conversion from yuv to rgb, no interpolation is done, and the same UV value are used for 4 rgb pixels. This 14 | // is suboptimal for image quality, but by far the fastest method. 15 | 16 | // For all methods, width and height should be even, if not, the last row/column of the result image won't be affected. 17 | // For sse methods, if the width if not divisable by 32, the last (width%32) pixels of each line won't be affected. 18 | 19 | #include 20 | 21 | #ifdef _MSC_VER 22 | // MSVC does not have __SSE2__ macro 23 | #if (defined(_M_AMD64) || defined(_M_X64) || (_M_IX86_FP == 2)) 24 | #define _YUVRGB_SSE2_ 25 | #endif 26 | #else 27 | // For else than MSVC 28 | #ifdef __SSE2__ 29 | #define _YUVRGB_SSE2_ 30 | #endif // __SSE2__ 31 | #endif // _MSC_VER 32 | 33 | typedef enum 34 | { 35 | YCBCR_JPEG, 36 | YCBCR_601, 37 | YCBCR_709 38 | } YCbCrType; 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | // yuv to rgb, standard c implementation 45 | void yuv420_rgb24_std( 46 | uint32_t width, uint32_t height, 47 | const uint8_t *y, const uint8_t *u, const uint8_t *v, uint32_t y_stride, uint32_t uv_stride, 48 | uint8_t *rgb, uint32_t rgb_stride, 49 | YCbCrType yuv_type); 50 | 51 | // yuv to rgb, yuv in nv12 semi planar format 52 | void nv12_rgb24_std( 53 | uint32_t width, uint32_t height, 54 | const uint8_t *y, const uint8_t *uv, uint32_t y_stride, uint32_t uv_stride, 55 | uint8_t *rgb, uint32_t rgb_stride, 56 | YCbCrType yuv_type); 57 | 58 | // yuv to rgb, yuv in nv12 semi planar format 59 | void nv21_rgb24_std( 60 | uint32_t width, uint32_t height, 61 | const uint8_t *y, const uint8_t *uv, uint32_t y_stride, uint32_t uv_stride, 62 | uint8_t *rgb, uint32_t rgb_stride, 63 | YCbCrType yuv_type); 64 | 65 | // yuv to rgb, sse implementation 66 | // pointers must be 16 byte aligned, and strides must be divisable by 16 67 | void yuv420_rgb24_sse( 68 | uint32_t width, uint32_t height, 69 | const uint8_t *y, const uint8_t *u, const uint8_t *v, uint32_t y_stride, uint32_t uv_stride, 70 | uint8_t *rgb, uint32_t rgb_stride, 71 | YCbCrType yuv_type); 72 | 73 | // yuv to rgb, sse implementation 74 | // pointers do not need to be 16 byte aligned 75 | void yuv420_rgb24_sseu( 76 | uint32_t width, uint32_t height, 77 | const uint8_t *y, const uint8_t *u, const uint8_t *v, uint32_t y_stride, uint32_t uv_stride, 78 | uint8_t *rgb, uint32_t rgb_stride, 79 | YCbCrType yuv_type); 80 | 81 | // yuv nv12 to rgb, sse implementation 82 | // pointers must be 16 byte aligned, and strides must be divisable by 16 83 | void nv12_rgb24_sse( 84 | uint32_t width, uint32_t height, 85 | const uint8_t *y, const uint8_t *uv, uint32_t y_stride, uint32_t uv_stride, 86 | uint8_t *rgb, uint32_t rgb_stride, 87 | YCbCrType yuv_type); 88 | 89 | // yuv nv12 to rgb, sse implementation 90 | // pointers do not need to be 16 byte aligned 91 | void nv12_rgb24_sseu( 92 | uint32_t width, uint32_t height, 93 | const uint8_t *y, const uint8_t *uv, uint32_t y_stride, uint32_t uv_stride, 94 | uint8_t *rgb, uint32_t rgb_stride, 95 | YCbCrType yuv_type); 96 | 97 | // yuv nv21 to rgb, sse implementation 98 | // pointers must be 16 byte aligned, and strides must be divisable by 16 99 | void nv21_rgb24_sse( 100 | uint32_t width, uint32_t height, 101 | const uint8_t *y, const uint8_t *uv, uint32_t y_stride, uint32_t uv_stride, 102 | uint8_t *rgb, uint32_t rgb_stride, 103 | YCbCrType yuv_type); 104 | 105 | // yuv nv21 to rgb, sse implementation 106 | // pointers do not need to be 16 byte aligned 107 | void nv21_rgb24_sseu( 108 | uint32_t width, uint32_t height, 109 | const uint8_t *y, const uint8_t *uv, uint32_t y_stride, uint32_t uv_stride, 110 | uint8_t *rgb, uint32_t rgb_stride, 111 | YCbCrType yuv_type); 112 | 113 | 114 | 115 | 116 | // rgb to yuv, standard c implementation 117 | void rgb24_yuv420_std( 118 | uint32_t width, uint32_t height, 119 | const uint8_t *rgb, uint32_t rgb_stride, 120 | uint8_t *y, uint8_t *u, uint8_t *v, uint32_t y_stride, uint32_t uv_stride, 121 | YCbCrType yuv_type); 122 | 123 | // rgb to yuv, sse implementation 124 | // pointers must be 16 byte aligned, and strides must be divisible by 16 125 | void rgb24_yuv420_sse( 126 | uint32_t width, uint32_t height, 127 | const uint8_t *rgb, uint32_t rgb_stride, 128 | uint8_t *y, uint8_t *u, uint8_t *v, uint32_t y_stride, uint32_t uv_stride, 129 | YCbCrType yuv_type); 130 | 131 | // rgb to yuv, sse implementation 132 | // pointers do not need to be 16 byte aligned 133 | void rgb24_yuv420_sseu( 134 | uint32_t width, uint32_t height, 135 | const uint8_t *rgb, uint32_t rgb_stride, 136 | uint8_t *y, uint8_t *u, uint8_t *v, uint32_t y_stride, uint32_t uv_stride, 137 | YCbCrType yuv_type); 138 | 139 | // rgba to yuv, standard c implementation 140 | // alpha channel is ignored 141 | void rgb32_yuv420_std( 142 | uint32_t width, uint32_t height, 143 | const uint8_t *rgba, uint32_t rgba_stride, 144 | uint8_t *y, uint8_t *u, uint8_t *v, uint32_t y_stride, uint32_t uv_stride, 145 | YCbCrType yuv_type); 146 | 147 | // rgba to yuv, sse implementation 148 | // pointers must be 16 byte aligned, and strides must be divisible by 16 149 | // alpha channel is ignored 150 | void rgb32_yuv420_sse( 151 | uint32_t width, uint32_t height, 152 | const uint8_t *rgba, uint32_t rgba_stride, 153 | uint8_t *y, uint8_t *u, uint8_t *v, uint32_t y_stride, uint32_t uv_stride, 154 | YCbCrType yuv_type); 155 | 156 | // rgba to yuv, sse implementation 157 | // pointers do not need to be 16 byte aligned 158 | // alpha channel is ignored 159 | void rgb32_yuv420_sseu( 160 | uint32_t width, uint32_t height, 161 | const uint8_t *rgba, uint32_t rgba_stride, 162 | uint8_t *y, uint8_t *u, uint8_t *v, uint32_t y_stride, uint32_t uv_stride, 163 | YCbCrType yuv_type); 164 | 165 | #ifdef __cplusplus 166 | } 167 | #endif 168 | -------------------------------------------------------------------------------- /client/qt/source/qml/Views/MainView.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-client-qt 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | import QtQuick 2.15 19 | import QtQuick.Controls 2.15 20 | import QtQuick.Controls.Universal 2.15 21 | 22 | import QtGraphicalEffects 1.0 23 | 24 | import ".." 25 | import "../Popups" 26 | 27 | Item { 28 | id: mainView 29 | 30 | readonly property string title: Common.title 31 | 32 | signal viewChangeRequest(string view) 33 | 34 | AboutPopup { id: aboutPopup } 35 | SendMessagePopup { id: sendMessagePopup } 36 | 37 | readonly property real buttonWidth: Math.max(96, root.width / 8.5) 38 | readonly property real buttonHeight: Math.max(128, root.height / 3.75) 39 | 40 | component ViewButton: Button { 41 | id: button 42 | 43 | display: AbstractButton.TextUnderIcon 44 | icon.height: buttonWidth * 0.75 45 | icon.width: buttonWidth * 0.75 46 | 47 | icon.color: "transparent" 48 | 49 | implicitHeight: buttonHeight 50 | implicitWidth: buttonWidth 51 | 52 | background: Item { 53 | 54 | RectangularGlow { 55 | anchors.fill: parent 56 | glowRadius: button.pressed ? 12 : 2 57 | spread: 0.2 58 | color: "#00ABA9" 59 | visible: button.pressed 60 | 61 | Behavior on glowRadius { 62 | NumberAnimation { duration: 75; easing.type: Easing.InOutSine } 63 | } 64 | } 65 | FastBlur { 66 | anchors.fill: parent 67 | 68 | radius: 48 69 | 70 | source: ShaderEffectSource { 71 | readonly property point mappedPoint: Qt.point(button.x, button.y) 72 | 73 | sourceItem: root.background 74 | sourceRect: Qt.rect(mappedPoint.x - flickable.contentX, mappedPoint.y - flickable.contentY + root.header.height, button.width, 75 | button.height) 76 | } 77 | } 78 | 79 | Rectangle { 80 | anchors.fill: parent 81 | color: Common.setColorAlpha(bgColor, 0.1) 82 | 83 | readonly property color bgColor: root.isThemeDark ? "darkgray" : "lightgray" 84 | readonly property color borderColor: bgColor //"#00ABA9" 85 | 86 | border.width: 2 87 | border.color: Common.setColorAlpha(borderColor, 0.85) 88 | } 89 | 90 | Rectangle { 91 | anchors.fill: parent 92 | color: "lightgray" 93 | 94 | opacity: 0.5 95 | 96 | visible: button.pressed 97 | } 98 | } 99 | } 100 | 101 | Image { 102 | anchors.right: parent.right 103 | anchors.bottom: parent.bottom 104 | anchors.rightMargin: width * 0.25 105 | anchors.bottomMargin: anchors.rightMargin 106 | 107 | asynchronous: true 108 | antialiasing: true 109 | 110 | width: implicitWidth * 0.175 111 | height: implicitHeight * 0.175 112 | 113 | source: Common.builtWithQt 114 | } 115 | 116 | Flickable { 117 | id: flickable 118 | anchors.fill: parent 119 | 120 | contentWidth: width 121 | contentHeight: flow.height 122 | 123 | ScrollBar.vertical: ScrollBar { 124 | visible: flickable.contentHeight > flickable.height 125 | policy: ScrollBar.AlwaysOn 126 | } 127 | 128 | Flow { 129 | id: flow 130 | anchors.left: parent.left 131 | anchors.right: parent.right 132 | 133 | padding: buttonWidth / 2 134 | spacing: padding 135 | 136 | ViewButton { 137 | text: "Camera" 138 | 139 | icon.source: Common.cameraIcon 140 | 141 | onClicked: { 142 | viewChangeRequest(Common.cameraView) 143 | } 144 | } 145 | 146 | ViewButton { 147 | text: "Logs" 148 | 149 | icon.source: Common.logIcon 150 | 151 | onClicked: { 152 | viewChangeRequest(Common.logView) 153 | } 154 | } 155 | 156 | ViewButton { 157 | text: "Settings" 158 | 159 | icon.source: Common.settingsIcon 160 | 161 | onClicked: { 162 | viewChangeRequest(Common.settingsView) 163 | } 164 | } 165 | 166 | ViewButton { 167 | enabled: client.connected 168 | 169 | text: "Send\nMessage" 170 | 171 | icon.source: Common.messageIcon 172 | 173 | onClicked: { 174 | sendMessagePopup.open() 175 | } 176 | } 177 | 178 | ViewButton { 179 | text: qsTr("Statistics") 180 | 181 | icon.source: Common.statisticsIcon 182 | 183 | onClicked: { 184 | viewChangeRequest(Common.statisticsView) 185 | } 186 | } 187 | 188 | ViewButton { 189 | text: "About" 190 | 191 | icon.source: Common.aboutIcon 192 | 193 | onClicked: { 194 | aboutPopup.open() 195 | } 196 | } 197 | 198 | ViewButton { 199 | text: "Shutdown" 200 | 201 | icon.source: Common.shutdownIcon 202 | 203 | onClicked: { 204 | Qt.quit() 205 | } 206 | } 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /server/source/DLIBWorker/DLIBWorker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * iot-facerecognition-server 3 | * Copyright (C) 2021 - fuzun 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef DLIBWORKER_H 19 | #define DLIBWORKER_H 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | class DLIBWorker : public QObject 32 | { 33 | Q_OBJECT 34 | 35 | friend class Client; 36 | 37 | public: 38 | using Face = std::tuple>; 39 | using Object = Face; 40 | using Cluster = std::pair>; 41 | 42 | private: 43 | // 44 | 45 | // (dnn_face_recognition_ex.cpp): 46 | template