From: APTX Date: Sat, 28 Apr 2018 09:33:02 +0000 (+0900) Subject: Move annotation detection to separate thread X-Git-Url: https://gitweb.tyo.aptx.org/?a=commitdiff_plain;h=ce3ab942b5242841eed93f1a9795edfbb567470c;p=aniplayer.git Move annotation detection to separate thread --- diff --git a/core/annotationmodel.cpp b/core/annotationmodel.cpp index edeaf74..a1bf838 100644 --- a/core/annotationmodel.cpp +++ b/core/annotationmodel.cpp @@ -10,7 +10,7 @@ void AnnotationModel::setAnnotations( } QHash AnnotationModel::roleNames() const { -static QHash roles{ + static QHash roles{ {Qt::DisplayRole, "text"}, {AnnotationX, "annotationX"}, {AnnotationY, "annotationY"}, diff --git a/featureplugins/feature_annotations/CMakeLists.txt b/featureplugins/feature_annotations/CMakeLists.txt index 8a8d5ca..cb2db02 100644 --- a/featureplugins/feature_annotations/CMakeLists.txt +++ b/featureplugins/feature_annotations/CMakeLists.txt @@ -4,6 +4,7 @@ project(feature_annotations) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Core Gui + Concurrent ) find_package(dlib CONFIG REQUIRED) @@ -17,6 +18,7 @@ endif() set(feature_annotations_LIBS Qt5::Core Qt5::Gui + Qt5::Concurrent ${DLIB_LIBRARY_NAME} pluginapi ) diff --git a/featureplugins/feature_annotations/featureannotations.cpp b/featureplugins/feature_annotations/featureannotations.cpp index 73314fe..729c571 100644 --- a/featureplugins/feature_annotations/featureannotations.cpp +++ b/featureplugins/feature_annotations/featureannotations.cpp @@ -1,39 +1,58 @@ #include "featureannotations.h" -#include #include +#include Q_LOGGING_CATEGORY(annotationsCategory, "Annotations") +Q_LOGGING_CATEGORY(annotationsVerboseCategory, "Annotations.verbose") #include #include +#include +#include + // random windows.h defines #undef interface using namespace std; using namespace dlib; +template +using con5d = con; +template +using con5 = con; -template using con5d = con; -template using con5 = con; +template +using downsampler_r = relu>>>>>>>>; +template using rcon5_r = relu>>; -template using downsampler_r = relu>>>>>>>>; -template using rcon5_r = relu>>; - -using detection_net_type = loss_mmod>>>>>>>; +using detection_net_type = + loss_mmod>>>>>>>; namespace { detection_net_type net; -} +bool valid = false; +} // namespace FeatureAnnoations::FeatureAnnoations(QObject *parent) : QObject{parent} { - deserialize("C:/_C/anime_face_recognition/mmod_network.dat") >> net; + try { + deserialize("C:/_C/anime_face_recognition/mmod_network.dat") >> net; + valid = true; + } catch (const std::exception &ex) { + qCWarning(annotationsCategory) + << "Failed to read neural network. Error:" << ex.what(); + } } FeaturePluginInstance * FeatureAnnoations::createInstance(QObject *instance, - PlayerFeaturePlauginInterface *interface) { + PlayerFeaturePlauginInterface *interface) { + if (!valid) + throw std::exception{"Network failed to initialize"}; return new FeatureAnnoationsInstance(instance, interface); } @@ -42,53 +61,80 @@ FeatureAnnoationsInstance::FeatureAnnoationsInstance( : FeaturePluginInstance{instance, player} { qCDebug(annotationsCategory) << "Registering with instance" << instance; - connect(instance, SIGNAL(frameChanged(const QImage &)), - this, SLOT(onFrameChanged(const QImage &))); + connect(instance, SIGNAL(frameChanged(const QImage &)), this, + SLOT(onFrameChanged(const QImage &))); + connect(&m_watcher, SIGNAL(finished()), this, SLOT(onResultReady())); m_fpsTimer.setInterval(1000); connect(&m_fpsTimer, &QTimer::timeout, [&]() { - qCDebug(annotationsCategory) << "Did" << m_fpsCounter - << "frames per seoncd"; + qCDebug(annotationsCategory) + << "Did" << m_fpsCounter << "frames per seoncd"; m_fpsCounter = 0; }); m_fpsTimer.start(); } -void FeatureAnnoationsInstance::onFrameChanged(const QImage &image) -{ - qCDebug(annotationsCategory) << "Frame changed! " << image.size() << image.format(); - if (image.size().isEmpty()) return; - try { - matrix img{image.size().height(), image.size().width()}; - - const auto *imageData = reinterpret_cast(image.bits()); - auto size = img.size(); - - std::transform(imageData, imageData + size, img.begin(), - [](const QRgb &d) { - return rgb_pixel{static_cast(qRed(d)), - static_cast(qGreen(d)), - static_cast(qBlue(d))}; - }); - - //dlib::save_bmp(img, "testimage.bmp"); - - auto dets = net(img); - PlayerFeaturePlauginInterface::AnnotationList al; - for (auto&& d : dets) - al << PlayerFeaturePlauginInterface::Annotation{ - static_cast(d.rect.left()) / image.size().width(), - static_cast(d.rect.top()) / image.size().height(), - static_cast(d.rect.right() - d.rect.left()) / image.size().width(), - static_cast(d.rect.bottom() - d.rect.top()) / image.size().height(), - "red", - "" - }; - m_playerInterface->featureSetAnnotations(al); - ++m_fpsCounter; - - } catch(const std::exception &ex) { - qCDebug(annotationsCategory) << "Exception: " << ex.what(); - } +void FeatureAnnoationsInstance::onFrameChanged(const QImage &image) { + qCDebug(annotationsVerboseCategory) + << "Frame changed! " << image.size() << image.format(); + if (image.size().isEmpty()) + return; + + if (m_watcher.isRunning()) + return; + + qCDebug(annotationsVerboseCategory) << "Starting annotation detection..."; + + auto future = QtConcurrent::run( + [](QImage image) -> PlayerFeaturePlauginInterface::AnnotationList { + try { + const int maxHeight{600}; + if (image.size().height() > maxHeight) + image = image.scaledToHeight(maxHeight, Qt::FastTransformation); + + matrix img{image.size().height(), image.size().width()}; + + const auto *imageData = reinterpret_cast(image.bits()); + auto size = img.size(); + + std::transform( + imageData, imageData + size, img.begin(), [](const QRgb &d) { + return rgb_pixel{static_cast(qRed(d)), + static_cast(qGreen(d)), + static_cast(qBlue(d))}; + }); + + // dlib::save_bmp(img, "testimage.bmp"); + + auto dets = net(img); + PlayerFeaturePlauginInterface::AnnotationList al; + for (auto &&d : dets) + al << PlayerFeaturePlauginInterface::Annotation{ + static_cast(d.rect.left()) / image.size().width(), + static_cast(d.rect.top()) / image.size().height(), + static_cast(d.rect.right() - d.rect.left()) / + image.size().width(), + static_cast(d.rect.bottom() - d.rect.top()) / + image.size().height(), + "red", + ""}; + + qCDebug(annotationsVerboseCategory) + << "Found" << al.size() << "annotations"; + return al; + + } catch (const std::exception &ex) { + qCWarning(annotationsCategory) << "Exception: " << ex.what(); + } + return {}; + }, + std::move(image)); + + m_watcher.setFuture(future); +} + +void FeatureAnnoationsInstance::onResultReady() { + ++m_fpsCounter; + m_playerInterface->featureSetAnnotations(m_watcher.result()); } diff --git a/featureplugins/feature_annotations/featureannotations.h b/featureplugins/feature_annotations/featureannotations.h index 06e6f33..898ad91 100644 --- a/featureplugins/feature_annotations/featureannotations.h +++ b/featureplugins/feature_annotations/featureannotations.h @@ -7,6 +7,7 @@ #include #include +#include #include "aniplayer/featurepluginbase.h" #include "aniplayer/playerfeatureplugininterface.h" @@ -34,12 +35,15 @@ public: private slots: void onFrameChanged(const QImage &); + void onResultReady(); + private: int m_fid; QString m_path; double m_duration; QTimer m_fpsTimer; int m_fpsCounter = 0; + QFutureWatcher m_watcher; }; #endif // FeatureAnnoations_H