diff --git a/NFIQ2/NFIQ2Algorithm/include/nfiq2_algorithm.hpp b/NFIQ2/NFIQ2Algorithm/include/nfiq2_algorithm.hpp index 2ea4df0d..c4090e87 100644 --- a/NFIQ2/NFIQ2Algorithm/include/nfiq2_algorithm.hpp +++ b/NFIQ2/NFIQ2Algorithm/include/nfiq2_algorithm.hpp @@ -20,6 +20,10 @@ #include #include +#ifdef __ANDROID__ +#include +#endif + namespace NFIQ2 { /** @@ -48,6 +52,10 @@ class Algorithm { * The md5 checksum of the provided file. */ Algorithm(const std::string &fileName, const std::string &fileHash); +#ifdef __ANDROID__ + Algorithm(AAssetManager *assets, const std::string &fileName, + const std::string &fileHash); +#endif /** * @brief diff --git a/NFIQ2/NFIQ2Algorithm/include/prediction/RandomForestML.h b/NFIQ2/NFIQ2Algorithm/include/prediction/RandomForestML.h index 21d619af..8aabf63a 100644 --- a/NFIQ2/NFIQ2Algorithm/include/prediction/RandomForestML.h +++ b/NFIQ2/NFIQ2Algorithm/include/prediction/RandomForestML.h @@ -8,6 +8,10 @@ #include #include +#ifdef __ANDROID__ +#include +#endif + namespace NFIQ2 { namespace Prediction { /** @@ -35,6 +39,13 @@ class RandomForestML { std::string initModule(const std::string &fileName, const std::string &fileHash); +#ifdef __ANDROID__ + /** Initialize model from Android AAR (When not using embedded + * parameters). */ + std::string initModule(AAssetManager *assets, + const std::string &fileName, const std::string &fileHash); +#endif + /** * Compute NFIQ2 quality score based on model and provided * QualityFeatureData. diff --git a/NFIQ2/NFIQ2Algorithm/src/nfiq2/nfiq2_algorithm.cpp b/NFIQ2/NFIQ2Algorithm/src/nfiq2/nfiq2_algorithm.cpp index 969e47ea..0eb153fe 100644 --- a/NFIQ2/NFIQ2Algorithm/src/nfiq2/nfiq2_algorithm.cpp +++ b/NFIQ2/NFIQ2Algorithm/src/nfiq2/nfiq2_algorithm.cpp @@ -20,6 +20,14 @@ NFIQ2::Algorithm::Algorithm(const NFIQ2::ModelInfo &modelInfoObj) { } +#ifdef __ANDROID__ +NFIQ2::Algorithm::Algorithm(AAssetManager *assets, const std::string &fileName, + const std::string &fileHash) + : pimpl { new NFIQ2::Algorithm::Impl(assets, fileName, fileHash) } +{ +} +#endif + NFIQ2::Algorithm::Algorithm(const Algorithm &rhs) : pimpl(new Impl(*rhs.pimpl)) { diff --git a/NFIQ2/NFIQ2Algorithm/src/nfiq2/nfiq2_algorithm_impl.cpp b/NFIQ2/NFIQ2Algorithm/src/nfiq2/nfiq2_algorithm_impl.cpp index 9b4f7c37..c5496f68 100644 --- a/NFIQ2/NFIQ2Algorithm/src/nfiq2/nfiq2_algorithm_impl.cpp +++ b/NFIQ2/NFIQ2Algorithm/src/nfiq2/nfiq2_algorithm_impl.cpp @@ -54,6 +54,34 @@ NFIQ2::Algorithm::Impl::Impl(const std::string &fileName, } } +#ifdef __ANDROID__ +NFIQ2::Algorithm::Impl::Impl(AAssetManager *assets, const std::string &fileName, + const std::string &fileHash) + : initialized { false } +{ + // init RF module that takes some time to load the parameters + try { + this->m_parameterHash = m_RandomForestML.initModule(assets, + fileName, fileHash); + this->initialized = true; + } catch (const cv::Exception &e) { + throw Exception(NFIQ2::ErrorCode::BadArguments, + "Could not initialize random forest parameters with " + "external file. Most likely, the file does not exist. " + "Check the path (" + + fileName + ") and hash (" + fileHash + + ") (initial error: " + e.msg + ")."); + } catch (const NFIQ2::Exception &e) { + throw Exception(NFIQ2::ErrorCode::BadArguments, + "Could not initialize random forest parameters with " + "external file. Most likely, the hash is not correct. " + "Check the path (" + + fileName + ") and hash (" + fileHash + + ") (initial error: " + e.what() + ")."); + } +} +#endif + NFIQ2::Algorithm::Impl::~Impl() = default; double diff --git a/NFIQ2/NFIQ2Algorithm/src/nfiq2/nfiq2_algorithm_impl.hpp b/NFIQ2/NFIQ2Algorithm/src/nfiq2/nfiq2_algorithm_impl.hpp index 0ac84346..fa158a4a 100644 --- a/NFIQ2/NFIQ2Algorithm/src/nfiq2/nfiq2_algorithm_impl.hpp +++ b/NFIQ2/NFIQ2Algorithm/src/nfiq2/nfiq2_algorithm_impl.hpp @@ -41,6 +41,22 @@ class Algorithm::Impl { */ Impl(const std::string &fileName, const std::string &fileHash); +#ifdef __ANDROID__ + /** + * @brief + * Constructor that loads random forest parameters from AAR. + * + * @param assets + * The Android Asset Manager, provided by the App. + * @param fileName + * The file path containing the random forest model. + * @param fileHash + * The md5 checksum of the provided file. + */ + Impl(AAssetManager *assets, const std::string &fileName, + const std::string &fileHash); +#endif + /** Destructor. */ virtual ~Impl(); diff --git a/NFIQ2/NFIQ2Algorithm/src/prediction/RandomForestML.cpp b/NFIQ2/NFIQ2Algorithm/src/prediction/RandomForestML.cpp index 1fe768c7..d4348683 100644 --- a/NFIQ2/NFIQ2Algorithm/src/prediction/RandomForestML.cpp +++ b/NFIQ2/NFIQ2Algorithm/src/prediction/RandomForestML.cpp @@ -123,6 +123,63 @@ NFIQ2::Prediction::RandomForestML::initModule(const std::string &fileName, return hash; } +#ifdef __ANDROID__ +std::string +NFIQ2::Prediction::RandomForestML::initModule(AAssetManager *assets, + const std::string &fileName, const std::string &fileHash) +{ + if (assets == nullptr) { + throw NFIQ2::Exception(NFIQ2::ErrorCode::BadArguments, + "Prediction::RandomForestML::initModule: AAssetManager is null"); + } + if (fileName.empty()) { + throw NFIQ2::Exception(NFIQ2::ErrorCode::BadArguments, + "Prediction::RandomForestML::initModule: " + "file name is empty"); + } + if (fileHash.empty()) { + throw NFIQ2::Exception(NFIQ2::ErrorCode::BadArguments, + "Prediction::RandomForestML::initModule: " + "hash value is empty"); + } + AAsset *asset = AAssetManager_open(assets, fileName.c_str(), + AASSET_MODE_STREAMING); + if (asset == nullptr) { + throw NFIQ2::Exception(NFIQ2::ErrorCode::InvalidConfiguration, + "Prediction::RandomForestML::initModule: " + "requested asset not found"); + } + // reading the file with the asset manager + std::stringstream ss; + char buffer[BUFSIZ + 1]; // BUFSIZ defined in stdio.h + int cnt = AAsset_read(asset, buffer, BUFSIZ); + while (cnt > 0 && cnt <= BUFSIZ) { + buffer[cnt] = 0; // add terminating '\0' + ss << buffer; + cnt = AAsset_read(asset, buffer, BUFSIZ); + } + AAsset_close(asset); + // verify the read data and initialize model + std::string params = ss.str(); + if (params.size() == 0) { + throw NFIQ2::Exception(NFIQ2::ErrorCode::InvalidConfiguration, + "The trained network could not be initialized!" + "Invalid model"); + } + // calculate and compare the hash + std::string hash = calculateHashString(params); + if (fileHash.compare(hash) != 0) { + m_pTrainedRF->clear(); + throw NFIQ2::Exception(NFIQ2::ErrorCode::InvalidConfiguration, + "The trained network could not be initialized! " + "Error: " + + hash); + } + initModule(params); + return hash; +} +#endif + void NFIQ2::Prediction::RandomForestML::evaluate( const std::unordered_map &features, diff --git a/NFIQ2/NFIQ2Api/CMakeLists.txt b/NFIQ2/NFIQ2Api/CMakeLists.txt index ca100e9b..8e672c11 100644 --- a/NFIQ2/NFIQ2Api/CMakeLists.txt +++ b/NFIQ2/NFIQ2Api/CMakeLists.txt @@ -85,6 +85,7 @@ elseif("${TARGET_PLATFORM}" MATCHES "android*") find_package(Threads REQUIRED) set( PROJECT_LIBS ${PROJECT_LIBS} ${CMAKE_THREAD_LIBS_INIT} + android log ) else()