|
#pragma once
|
|
|
|
#include "IAsyncContext.h"
|
|
#include "IDescriptor.h"
|
|
|
|
namespace fsdk {
|
|
|
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
|
DECLARE_SMARTPTR(IStaticDescriptorStorage);
|
|
DECLARE_SMARTPTR(IDynamicDescriptorStorage);
|
|
DECLARE_SMARTPTR(IIndex);
|
|
DECLARE_SMARTPTR(IDenseIndex);
|
|
DECLARE_SMARTPTR(IDynamicIndex);
|
|
DECLARE_SMARTPTR(IIndexBuilder);
|
|
#endif
|
|
|
|
/// Intergral type used as identification of descriptor in internal storage.
|
|
using DescriptorId = size_t;
|
|
|
|
/**
|
|
* @brief Result of index search.
|
|
* */
|
|
struct SearchResult : MatchingResult {
|
|
/// Identificator of descriptor in some storage.
|
|
DescriptorId index;
|
|
|
|
/// Default constructor.
|
|
SearchResult() noexcept
|
|
: MatchingResult()
|
|
, index(std::numeric_limits<DescriptorId>::max())
|
|
{}
|
|
|
|
/**
|
|
* @brief Construct structure with parameters.
|
|
* @param [in] distance Distance between descriptors.
|
|
* @param [in] similarity Similarity between descriptors.
|
|
* @param [in] index Index of found descriptors in some storage.
|
|
* */
|
|
SearchResult(
|
|
float distance,
|
|
float similarity,
|
|
DescriptorId index) noexcept
|
|
: MatchingResult(distance, similarity)
|
|
, index(index)
|
|
{}
|
|
};
|
|
|
|
/**
|
|
* @brief Static descriptor storage interface.
|
|
* @details You may think of it as read only access to some internal container.
|
|
* */
|
|
struct IStaticDescriptorStorage {
|
|
/**
|
|
* @brief Requests descriptor data out of internal storage.
|
|
* @param [in] index Identification value of some descriptor. Might be received either
|
|
* by using @see IDynamicDescriptorStorage::append methods, or as output of
|
|
* @see IIndex::search query. Must be less than @see size().
|
|
* @param [out] descriptor Ptr to created descriptor object with correctly set
|
|
* version and length. Only changes data of passed descriptor.
|
|
* @return Result with error code.
|
|
* @see IDescriptor, DescriptorId, Result and FSDKError for details.
|
|
* */
|
|
virtual Result<FSDKError> descriptorByIndex(
|
|
const DescriptorId index,
|
|
IDescriptor* descriptor) const noexcept = 0;
|
|
|
|
/**
|
|
* @brief Return version of stored descriptors.
|
|
* @return Version of stored descriptors. If not initialized, 0 is returned.
|
|
* */
|
|
virtual uint32_t getDescriptorVersion() const noexcept = 0;
|
|
|
|
/**
|
|
* @brief Return size of internal storage.
|
|
* @return Size of internal storage. If not initialized, 0 is returned.
|
|
* */
|
|
virtual uint64_t size() const noexcept = 0;
|
|
};
|
|
|
|
/**
|
|
* @brief Dynamic descriptor storage interface.
|
|
* @details You may think of it as read+write access to some internal container.
|
|
* */
|
|
struct IDynamicDescriptorStorage
|
|
: IStaticDescriptorStorage {
|
|
/**
|
|
* @brief Appends descriptor to internal storage.
|
|
* If used on @see IDynamicIndex graph updates itself too.
|
|
* @param [in] descriptor Ptr to created descriptor with correct length, version
|
|
* and data.
|
|
* @return ResultValue with error code and identification
|
|
* of appended descriptor. Such identification might be used to query descriptor
|
|
* with @see IStaticDescriptorStorage::descriptorByIndex or remove it from storage
|
|
* with @see removeDescriptor.
|
|
* @see IDescriptor, DescriptorId, ResultValue and FSDKError for details.
|
|
* */
|
|
virtual ResultValue<FSDKError, DescriptorId> appendDescriptor(
|
|
const IDescriptor* descriptor) noexcept = 0;
|
|
|
|
/**
|
|
* @brief Appends batch of descriptors to internal storage.
|
|
* If used on @see IDynamicIndex graph updates itself too.
|
|
* @param [in] batch Batch of descriptors with correct length, version and data.
|
|
* @return ResultValue with error code and identification
|
|
* of the first appended descriptor. Other descriptors from batch are appended
|
|
* sequentially in the same order as they are in the batch. Such identification
|
|
* might be used to query descriptor with
|
|
* @see IStaticDescriptorStorage::descriptorByIndex or remove it from storage
|
|
* with @see removeDescriptor.
|
|
* @see IDescriptorBatch, DescriptorId, ResultValue and FSDKError for details.
|
|
* */
|
|
virtual ResultValue<FSDKError, DescriptorId> appendBatch(
|
|
const IDescriptorBatch* batch) noexcept = 0;
|
|
|
|
/**
|
|
* @brief Removes descriptor out of internal storage.
|
|
* If used on @see IDynamicIndex graph updates itself too.
|
|
* @note IMPORTANT: If used on @see IDynamicIndex it will NOT actually erase
|
|
* descriptor with given index out of internal storage. Instead, it will
|
|
* remove it out of graph, so it is not searchable.
|
|
* @note If used on @see IIndexBuilder, it WILL actually erase it. But beware:
|
|
* if your storage is big enough performance might be very poor, because
|
|
* descriptors are stored sequentially in vector-like data structure, so every
|
|
* element after erased will be moved.
|
|
* @param [in] index Identification of descriptors position in internal storage.
|
|
* Is received by using append methods or @IIndex::search.
|
|
* @return Result with error code.
|
|
* @see DescriptorId, Result and FSDKError for details.
|
|
* */
|
|
virtual Result<FSDKError> removeDescriptor(const DescriptorId index) noexcept = 0;
|
|
};
|
|
|
|
/**
|
|
* @brief Base index interface.
|
|
* @details You may think of index as some data structure optimized for search queries.
|
|
* */
|
|
struct IIndex
|
|
: IRefCounted {
|
|
/**
|
|
* @brief Search for descriptors with the shorter distance to passed descriptor.
|
|
* @param [in] reference Descriptor to match against index.
|
|
* @param [in] maxResultsCount Maximum count of results. It is upper bound value, it
|
|
* does not guarantee to return exactly this amount of results.
|
|
* @param [out] results C-Array of at least @see maxResultsCount size. Is filled with
|
|
* query results.
|
|
* @return ResultValue with error code and count of found descriptors.
|
|
* @see IDescriptor, SearchResult, ResultValue and FSDKError for details.
|
|
* */
|
|
virtual ResultValue<FSDKError, int> search(
|
|
const IDescriptor* reference,
|
|
int maxResultsCount,
|
|
SearchResult* results) const noexcept = 0;
|
|
};
|
|
|
|
/**
|
|
* @brief Dense (read only) index interface.
|
|
* */
|
|
struct IDenseIndex
|
|
: IStaticDescriptorStorage
|
|
, IIndex {
|
|
|
|
};
|
|
|
|
/**
|
|
* @brief Dynamic index interface.
|
|
* */
|
|
struct IDynamicIndex
|
|
: IDynamicDescriptorStorage
|
|
, IIndex {
|
|
/**
|
|
* @brief Saves index as dense.
|
|
* @details To load saved index use @see IFaceEngine::loadDenseIndex method.
|
|
* Dense index cannot be loaded as dynamic.
|
|
* @param [in] path Path to file to be created and filled with index data. Any
|
|
* extension is acceptable.
|
|
* @return Result with error code.
|
|
* @see Result and FSDKError for details.
|
|
* */
|
|
virtual Result<FSDKError> saveToDenseIndex(const char* path) const noexcept = 0;
|
|
|
|
/**
|
|
* @brief Saves index as dynamic.
|
|
* @details To load saved index use @see IFaceEngine::loadDynamicIndex method.
|
|
* Dynamic index cannot be loaded as dense.
|
|
* @param [in] path Path to file to be created and filled with index data. Any
|
|
* extension is acceptable.
|
|
* @return Result with error code.
|
|
* @see Result and FSDKError for details.
|
|
* */
|
|
virtual Result<FSDKError> saveToDynamicIndex(const char* path) const noexcept = 0;
|
|
|
|
/**
|
|
* @brief Returns count of indexed descriptors.
|
|
* @details You may wonder why this method exists if IDynamicIndex already
|
|
* inherits IStaticDescriptorStorage::size method. The reason is that
|
|
* @see IDynamicDescriptorStorage::removeDescriptor behaves differently on
|
|
* @see IIndexBuild and IDynamicIndex. On builder it does actually erases
|
|
* descriptor out of internal storage, but it does not erase it if used on
|
|
* IDynamicIndex. The reason is that graph data structure relies on indexes
|
|
* being constant, so removeDescriptor only removes it out of graph, so it is not
|
|
* discoverable by @see IIndex::search. So this methods returns actuall data
|
|
* storage size minus count of removed descriptors.
|
|
* @return Count of indexed descriptors.
|
|
* */
|
|
virtual uint64_t countOfIndexedDescriptors() const noexcept = 0;
|
|
};
|
|
|
|
/**
|
|
* @brief Progress tracker interface.
|
|
* @details Implement this interface to be able to get progress info on some operation.
|
|
* */
|
|
struct IProgressTracker {
|
|
/**
|
|
* @brief Function is called on some operation progress change.
|
|
* @param [in] completion float value in [0..1] range.
|
|
* */
|
|
virtual void progress(const float completion) const noexcept = 0;
|
|
};
|
|
|
|
/**
|
|
* @brief Index builder interface.
|
|
* */
|
|
struct IIndexBuilder
|
|
: IDynamicDescriptorStorage
|
|
, IRefCounted {
|
|
/**
|
|
* @brief Builds index with every descriptor appended. Blocks until completed.
|
|
* @details Is very heavy method in terms of computing load.
|
|
* @param [in] progressTracker Some object that is being reported to with progress.
|
|
* If its nullptr, dont report progress.
|
|
* @return ResultValue with error code and created index object.
|
|
* @see IProgressTracker, IDynamicIndex, ResultValue and FSDKError for details.
|
|
* */
|
|
virtual ResultValue<FSDKError, IDynamicIndex*> buildIndex(
|
|
const IProgressTracker* const progressTracker = nullptr) noexcept = 0;
|
|
|
|
/**
|
|
* @brief Builds index with every descriptor appended. Non blocking operation.
|
|
* @details Is very heavy method in terms of computing load.
|
|
* @param [in] asyncContext Asynchronous context to run build on.
|
|
* @param [in] progressTracker Some object that is being reported to with progress.
|
|
* If its nullptr, dont report progress.
|
|
* @return ResultValue with error code and created index object.
|
|
* @see IAsyncContext, IProgressTracker, Future, IDynamicIndex, ResultValue and FSDKError for details.
|
|
* */
|
|
virtual ResultValue<FSDKError, Future<ResultValue<FSDKError, IDynamicIndex*>>>
|
|
buildIndexAsync(
|
|
IAsyncContext* const asyncContext,
|
|
const IProgressTracker* const progressTracker = nullptr) noexcept = 0;
|
|
};
|
|
|
|
|
|
}
|
|
|