File indexing completed on 2025-01-05 03:58:06
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2010-06-21 0007 * Description : GUI test program for FacesEngine 0008 * 0009 * SPDX-FileCopyrightText: 2010-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * SPDX-FileCopyrightText: 2010 by Alex Jironkin <alexjironkin at gmail dot com> 0011 * SPDX-FileCopyrightText: 2010 by Aditya Bhatt <adityabhatt1991 at gmail dot com> 0012 * 0013 * SPDX-License-Identifier: GPL-2.0-or-later 0014 * 0015 * ============================================================ */ 0016 0017 #include "demomainwindow.h" 0018 #include "ui_demomainwindow.h" 0019 0020 // Qt includes 0021 0022 #include <QGraphicsScene> 0023 #include <QGraphicsView> 0024 #include <QGraphicsPixmapItem> 0025 #include <QElapsedTimer> 0026 #include <QStandardPaths> 0027 0028 // Local includes 0029 0030 #include "digikam_debug.h" 0031 #include "facialrecognition_wrapper.h" 0032 #include "facedetector.h" 0033 #include "demofaceitem.h" 0034 #include "dfiledialog.h" 0035 0036 using namespace std; 0037 using namespace Digikam; 0038 0039 namespace FaceEngineDemo 0040 { 0041 0042 // -------------------------------------------------------------------------------------------------- 0043 0044 class Q_DECL_HIDDEN MainWindow::Private 0045 { 0046 public: 0047 0048 explicit Private() 0049 : ui (nullptr), 0050 myScene (nullptr), 0051 myView (nullptr), 0052 lastPhotoItem (nullptr), 0053 detector (nullptr), 0054 scale (0.0) 0055 { 0056 } 0057 0058 Ui::MainWindow* ui; 0059 QGraphicsScene* myScene; 0060 QGraphicsView* myView; 0061 QGraphicsPixmapItem* lastPhotoItem; 0062 QList<FaceItem*> faceitems; 0063 0064 FacialRecognitionWrapper database; 0065 FaceDetector* detector; 0066 QImage currentPhoto; 0067 double scale; 0068 QString lastFileOpenPath; 0069 }; 0070 0071 MainWindow::MainWindow(QWidget* const parent) 0072 : QMainWindow(parent), 0073 d(new Private) 0074 { 0075 d->ui = new Ui::MainWindow; 0076 d->ui->setupUi(this); 0077 d->ui->recogniseBtn->setEnabled(false); 0078 d->ui->updateDatabaseBtn->setEnabled(false); 0079 d->ui->detectFacesBtn->setEnabled(false); 0080 d->ui->configLocation->setReadOnly(true); 0081 0082 connect(d->ui->openImageBtn, SIGNAL(clicked()), 0083 this, SLOT(slotOpenImage())); 0084 0085 connect(d->ui->accuracySlider, SIGNAL(valueChanged(int)), 0086 this, SLOT(slotUpdateAccuracy())); 0087 0088 connect(d->ui->sensitivitySlider, SIGNAL(valueChanged(int)), 0089 this, SLOT(slotUpdateSensitivity())); 0090 0091 connect(d->ui->detectFacesBtn, SIGNAL(clicked()), 0092 this, SLOT(slotDetectFaces())); 0093 0094 connect(d->ui->recogniseBtn, SIGNAL(clicked()), 0095 this, SLOT(slotRecognise())); 0096 0097 connect(d->ui->updateDatabaseBtn, SIGNAL(clicked()), 0098 this, SLOT(slotUpdateDatabase())); 0099 0100 d->myScene = new QGraphicsScene(); 0101 QGridLayout* const layout = new QGridLayout; 0102 d->myView = new QGraphicsView(d->myScene); 0103 0104 d->myView->setCacheMode(QGraphicsView::CacheBackground); 0105 d->myScene->setItemIndexMethod(QGraphicsScene::NoIndex); 0106 0107 setMouseTracking(true); 0108 layout->addWidget(d->myView); 0109 0110 d->ui->widget->setLayout(layout); 0111 0112 d->myView->show(); 0113 0114 d->detector = new FaceDetector(); 0115 0116 d->ui->accuracySlider->setValue(80); 0117 d->ui->sensitivitySlider->setValue(80); 0118 0119 d->lastFileOpenPath = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).first(); 0120 } 0121 0122 MainWindow::~MainWindow() 0123 { 0124 delete d->ui; 0125 delete d->detector; 0126 delete d; 0127 } 0128 0129 void MainWindow::changeEvent(QEvent* e) 0130 { 0131 QMainWindow::changeEvent(e); 0132 0133 switch (e->type()) 0134 { 0135 case QEvent::LanguageChange: 0136 { 0137 d->ui->retranslateUi(this); 0138 break; 0139 } 0140 0141 default: 0142 { 0143 break; 0144 } 0145 } 0146 } 0147 0148 void MainWindow::clearScene() 0149 { 0150 QList<QGraphicsItem*> list = d->myScene->items(); 0151 0152 for (int i = 0 ; i < list.size() ; ++i) 0153 { 0154 d->myScene->removeItem(list.at(i)); 0155 } 0156 } 0157 0158 void MainWindow::slotOpenImage() 0159 { 0160 QString file = DFileDialog::getOpenFileName(this, QLatin1String("Select Image to Open"), 0161 d->lastFileOpenPath, 0162 QString::fromLatin1("Image Files (*.png *.jpg *.bmp *.pgm)")); 0163 0164 if (file.isEmpty()) 0165 { 0166 return; 0167 } 0168 0169 d->lastFileOpenPath = QFileInfo(file).absolutePath(); 0170 0171 clearScene(); 0172 0173 qCDebug(DIGIKAM_TESTS_LOG) << "Opened file " << file; 0174 0175 d->currentPhoto.load(file); 0176 d->lastPhotoItem = new QGraphicsPixmapItem(QPixmap::fromImage(d->currentPhoto)); 0177 0178 if ((1.0 * d->ui->widget->width() / d->currentPhoto.width()) < (1.0 * d->ui->widget->height() / d->currentPhoto.height())) 0179 { 0180 d->scale = 1.0 * d->ui->widget->width() / d->currentPhoto.width(); 0181 } 0182 else 0183 { 0184 d->scale = 1.0 * d->ui->widget->height() / d->currentPhoto.height(); 0185 } 0186 0187 d->lastPhotoItem->setScale(d->scale); 0188 0189 d->myScene->addItem(d->lastPhotoItem); 0190 d->ui->detectFacesBtn->setEnabled(true); 0191 } 0192 0193 void MainWindow::slotDetectFaces() 0194 { 0195 setCursor(Qt::WaitCursor); 0196 0197 QList<QRectF> currentFaces = d->detector->detectFaces(d->currentPhoto); 0198 0199 qCDebug(DIGIKAM_TESTS_LOG) << "FacesEngine detected : " << currentFaces.size() << " faces."; 0200 qCDebug(DIGIKAM_TESTS_LOG) << "Coordinates of detected faces : "; 0201 0202 Q_FOREACH (const QRectF& r, currentFaces) 0203 { 0204 qCDebug(DIGIKAM_TESTS_LOG) << r; 0205 } 0206 0207 Q_FOREACH (FaceItem* const item, d->faceitems) 0208 { 0209 item->setVisible(false); 0210 } 0211 0212 d->faceitems.clear(); 0213 0214 for (int i = 0 ; i < currentFaces.size() ; ++i) 0215 { 0216 QRect face = d->detector->toAbsoluteRect(currentFaces[i], d->currentPhoto.size()); 0217 d->faceitems.append(new FaceItem(nullptr, d->myScene, face, d->scale)); 0218 qCDebug(DIGIKAM_TESTS_LOG) << face; 0219 } 0220 0221 d->ui->recogniseBtn->setEnabled(true); 0222 d->ui->updateDatabaseBtn->setEnabled(true); 0223 0224 unsetCursor(); 0225 } 0226 0227 void MainWindow::slotUpdateAccuracy() 0228 { 0229 int value = d->ui->accuracySlider->value(); 0230 d->detector->setParameter(QString::fromLatin1("accuracy"), value/100.0); 0231 } 0232 0233 void MainWindow::slotUpdateSensitivity() 0234 { 0235 int value = d->ui->sensitivitySlider->value(); 0236 d->detector->setParameter(QString::fromLatin1("sensitivity"), value); 0237 } 0238 0239 void MainWindow::slotRecognise() 0240 { 0241 setCursor(Qt::WaitCursor); 0242 0243 int i = 0; 0244 0245 Q_FOREACH (FaceItem* const item, d->faceitems) 0246 { 0247 QElapsedTimer timer; 0248 timer.start(); 0249 0250 QImage* face = new QImage(); 0251 *face = d->currentPhoto.copy(item->originalRect()); 0252 0253 Identity identity = d->database.recognizeFace(face); 0254 int elapsed = timer.elapsed(); 0255 0256 qCDebug(DIGIKAM_TESTS_LOG) << "Recognition took " << elapsed << " for Face #" << i+1; 0257 0258 if (!identity.isNull()) 0259 { 0260 item->suggest(identity.attribute(QString::fromLatin1("name"))); 0261 0262 qCDebug(DIGIKAM_TESTS_LOG) << "Face #" << i+1 << " is closest to the person with ID " << identity.id() 0263 << " and name "<< identity.attribute(QString::fromLatin1("name")); 0264 } 0265 else 0266 { 0267 qCDebug(DIGIKAM_TESTS_LOG) << "Face #" << i+1 << " : no Identity match from database."; 0268 } 0269 0270 i++; 0271 } 0272 0273 unsetCursor(); 0274 } 0275 0276 void MainWindow::slotUpdateDatabase() 0277 { 0278 setCursor(Qt::WaitCursor); 0279 0280 int i = 0; 0281 0282 Q_FOREACH (FaceItem* const item, d->faceitems) 0283 { 0284 if (item->text() != QString::fromLatin1("?")) 0285 { 0286 QElapsedTimer timer; 0287 timer.start(); 0288 0289 QString name = item->text(); 0290 qCDebug(DIGIKAM_TESTS_LOG) << "Face #" << i+1 << ": training name '" << name << "'"; 0291 0292 Identity identity = d->database.findIdentity(QString::fromLatin1("name"), name); 0293 0294 if (identity.isNull()) 0295 { 0296 QMultiMap<QString, QString> attributes; 0297 attributes.insert(QString::fromLatin1("name"), name); 0298 identity = d->database.addIdentity(attributes); 0299 qCDebug(DIGIKAM_TESTS_LOG) << "Adding new identity ID " << identity.id() << " to database for name " << name; 0300 } 0301 else 0302 { 0303 qCDebug(DIGIKAM_TESTS_LOG) << "Found existing identity ID " << identity.id() << " from database for name " << name; 0304 } 0305 0306 QImage* face = new QImage(); 0307 *face = d->currentPhoto.copy(item->originalRect()); 0308 0309 d->database.train(identity, face, QString::fromLatin1("test application")); 0310 0311 int elapsed = timer.elapsed(); 0312 0313 qCDebug(DIGIKAM_TESTS_LOG) << "Training took " << elapsed << " for Face #" << i+1; 0314 } 0315 0316 ++i; 0317 } 0318 0319 unsetCursor(); 0320 } 0321 0322 } // namespace FaceEngineDemo 0323 0324 #include "moc_demomainwindow.cpp"