You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

501 lines
20 KiB

1 year ago
  1. /**
  2. * @file IDescriptor.h
  3. * @brief Descriptor extractor and matcher interfaces.
  4. * @copyright VisionLabs LLC
  5. * @date 25.06.2014
  6. * */
  7. #pragma once
  8. #include "IObject.h"
  9. #include "IDetector.h"
  10. #include "FSDKError.h"
  11. #include "Types.h"
  12. #include <limits>
  13. namespace fsdk {
  14. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  15. DECLARE_SMARTPTR(IDescriptor);
  16. DECLARE_SMARTPTR(IDescriptorBatch);
  17. DECLARE_SMARTPTR(IDescriptorMatcher);
  18. DECLARE_SMARTPTR(IDescriptorExtractor);
  19. #endif
  20. /**
  21. * @defgroup DescriptorProcessingGroup Descriptor extractor
  22. * @brief Descriptor extractor public interfaces and related types and structures.
  23. * @{
  24. * */
  25. /**
  26. * @brief Result of descriptor matching.
  27. * */
  28. struct MatchingResult {
  29. float distance; //!< distance between descriptor vectors.
  30. float similarity; //!< similarity (normalized in [0..1] range).
  31. /**
  32. * @brief Initializes result to default values.
  33. * */
  34. MatchingResult(void) noexcept
  35. : distance(std::numeric_limits<float>::infinity())
  36. , similarity(0.f)
  37. {}
  38. /**
  39. * @brief Initializes result.
  40. * @param [in] distance distance value.
  41. * @param [in] similarity similarity value.
  42. * */
  43. MatchingResult(
  44. float distance,
  45. float similarity) noexcept
  46. : distance(distance)
  47. , similarity(similarity)
  48. {}
  49. };
  50. /**
  51. * @brief Descriptor type enum.
  52. * Determines which type of descriptor to use.
  53. * */
  54. enum DescriptorType {
  55. DT_FACE, //!< face descriptor.
  56. DT_HUMAN //!< human descriptor.
  57. };
  58. /**
  59. * @brief Minimum descriptor model version.
  60. * Determines which minimum version of descriptor to use.
  61. * */
  62. enum DescriptorVersion : uint32_t {
  63. DV_MIN_FACE_DESCRIPTOR_VERSION = 46, //!< face descriptor.
  64. DV_MIN_HUMAN_DESCRIPTOR_VERSION = 102 //!< human descriptor.
  65. };
  66. /**
  67. * @brief Human descriptor model versions.
  68. * Determines which version of human descriptor to use.
  69. * */
  70. enum HumanDescriptorVersion : uint32_t {
  71. HDV_TRACKER_HUMAN_DESCRIPTOR_VERSION = 102, //!< human descriptor for tracking of people, light and fast version.
  72. HDV_PRECISE_HUMAN_DESCRIPTOR_VERSION = 103, //!< precise human descriptor, heavy and slow.
  73. HDV_REGULAR_HUMAN_DESCRIPTOR_VERSION = 104, //!< regular human descriptor.
  74. };
  75. /**
  76. * @brief Descriptor interface.
  77. * @details Used for matching.
  78. * */
  79. struct IDescriptor : IDataStorageObject {
  80. /**
  81. * @brief Get algorithm model version this descriptor was created with.
  82. * @return Version as integral number.
  83. * */
  84. virtual uint32_t getModelVersion() const noexcept = 0;
  85. /**
  86. * @brief Get type of descriptor.
  87. * @return type as enum.
  88. * @see DescriptorType for details.
  89. * */
  90. virtual DescriptorType getDescriptorType() const noexcept = 0;
  91. /**
  92. * @brief return size of descriptor in bytes.
  93. * @return size of descriptor in bytes.
  94. * @note This method is thread safe.
  95. * */
  96. virtual uint32_t getDescriptorLength() const noexcept = 0;
  97. /**
  98. * @brief Copy descriptor data to user provided buffer.
  99. * @param [out] buffer user provided buffer.
  100. * @return true if OK, and false if ERROR.
  101. * @note This method is thread safe.
  102. * @note buffer must be preallocated by client code.
  103. * */
  104. virtual bool getDescriptor(uint8_t* buffer) const noexcept = 0;
  105. /**
  106. * @brief Copy descriptor from user providedbuffer.
  107. * @param [in] buffer user provided buffer.
  108. */
  109. virtual void setDescriptor(const uint8_t* buffer) noexcept = 0;
  110. };
  111. /**
  112. * @brief Descriptor batch interface.
  113. * @details Used for matching large continous sets of descriptors.
  114. *
  115. * A batch is created with a reserved memory for descriptors that can not be later extended. Thus descriptors can be
  116. * add()'ed until the memory reservation is exceeded.
  117. *
  118. * Memory reservation size can be obtained via getMaxCount() function. The batch me be reset via clear() function.
  119. * It does not deallocate memory reservation. Instead, it resets internal counter allowing to re-populate the batch
  120. * via add() again.
  121. * */
  122. struct IDescriptorBatch : IDataStorageObject {
  123. /**
  124. * @brief Descriptor batch error enumeration.
  125. * @details Used for descriptor batch related errors indication.
  126. * */
  127. enum class Error : uint32_t {
  128. Ok, //!< No error.
  129. InvalidInput, //!< Invalid input (Ex: null pointer while a valid object is expected).
  130. BatchFull, //!< Batch is full.
  131. Incompatible, //!< Trying to add an incompatible descriptor.
  132. Internal, //!< An internal processing error (Ex: memopry allocation or misalignment).
  133. IoError, //!< Error while trying open/read/write file.
  134. OutOfRange, //!< Error while accessing descriptor out of range.
  135. };
  136. /**
  137. * @brief Add a descriptor to the batch.
  138. * @param [in] descriptor descriptor to add. Descriptor data is copied and to internal reference is held, thus
  139. * it is safe to release the source descriptor object later.
  140. * @return Result with one of the error codes specified by DescriptorBatchError.
  141. * @see IDescriptor, Result and Error for details.
  142. * */
  143. virtual Result<Error> add(IDescriptor* descriptor) noexcept = 0;
  144. /**
  145. * @brief Add a given descriptor batch content to the current batch. Descriptors to copy
  146. * from the source batch are selected based on offset parameter.
  147. * @param [in] batch batch to take content from. All descriptors from the input batch
  148. * are copied to the buffer of the current batch. So it is safe
  149. * to release the source descriptor batch object later.
  150. * @param [in] offset offset of descriptors to copy.
  151. * @return Result with one of the error codes specified by DescriptorBatchError.
  152. * @see IDescriptorBatch, Result and Error for details.
  153. * @note Current batch should have enough free space to place all descriptors
  154. * from the input batch.
  155. * @note All selected descriptors from the source batch will be placed right after all
  156. * descriptors in the current batch.
  157. * @note All selected descriptors from the input batch are copied to the buffer
  158. * of the current batch. So it is safe to release the source descriptor batch object later.
  159. * */
  160. virtual Result<Error> add(IDescriptorBatch* batch, uint32_t offset = 0) noexcept = 0;
  161. /**
  162. * @brief Add a descriptor batch content to the batch. Descriptors to copy
  163. * from the source bath are selected based on count and offset parameters.
  164. * @param [in] batch batch to take content from.
  165. * @param [in] offset offset of descriptors to copy.
  166. * @param [in] count count of descriptors to copy.
  167. * @return Result with one of the error codes specified by DescriptorBatchError.
  168. * @see IDescriptorBatch, Result and Error for details.
  169. * @note Current batch should have enough free space to place all descriptors
  170. * from the input batch.
  171. * @note All selected descriptors from the source batch will be placed right after all
  172. * descriptors in the current batch.
  173. * @note All selected descriptors from the input batch are copied to the buffer
  174. * of the current batch. So it is safe to release the source descriptor batch object later.
  175. * */
  176. virtual Result<Error> add(IDescriptorBatch* batch, uint32_t offset, uint32_t count) noexcept = 0;
  177. /**
  178. * @brief Remove a descriptor from batch.
  179. * @details Remove descriptor by swapping it with the last descriptor in batch. This breaks descriptor order.
  180. * @param [in] index descriptor index.
  181. * @return Result with one of the error codes specified by DescriptorBatchError.
  182. * @see Result and Error for details.
  183. * */
  184. virtual Result<Error> removeFast(uint32_t index) noexcept = 0;
  185. /**
  186. * @brief Remove a descriptor from batch.
  187. * @details Remove descriptor by shifting all the following descriptors back. This preserves descriptor order.
  188. * @param [in] index descriptor index.
  189. * @return Result with one of the error codes specified by DescriptorBatchError.
  190. * @see Result and Error for details.
  191. * */
  192. virtual Result<Error> removeSlow(uint32_t index) noexcept = 0;
  193. /**
  194. * @brief Load a descriptor/descriptors from archive and add it to the batch.
  195. * @note This method supports both serialized IDescriptorBatch and IDescriptor.
  196. * @param [in] archive archive to read from.
  197. * @return MultiError result with codes specified by DescriptorBatchError and SerializationError.
  198. * @note This method pass exceptions from user defined IArchive, but doesnt throw its own
  199. * @see Result, IArchive, ISerializableObject::Error, Error and MultiError for details.
  200. * */
  201. virtual Result<MultiError<ISerializableObject::Error,Error>> loadAndAdd(IArchive* archive) = 0;
  202. /**
  203. * @brief Get maximum number of descriptors in this batch.
  204. * @return maximum number of descriptors in this batch.
  205. * */
  206. virtual uint32_t getMaxCount() const noexcept = 0;
  207. /**
  208. * @brief Get actual number of descriptors in this batch.
  209. * @return actual number of descriptors in this batch.
  210. * */
  211. virtual uint32_t getCount() const noexcept = 0;
  212. /**
  213. * @brief Get algorithm model version the descriptors in this batch were created with.
  214. * @note This function only makes sense when there is at least one descriptor in the batch. It will return 0 if
  215. * the batch is empty.
  216. * @return Version as integral number.
  217. * */
  218. virtual uint32_t getModelVersion() const noexcept = 0;
  219. /**
  220. * @brief Get type of descriptor.
  221. * @note This function only makes sense when there is at least one descriptor in the batch.
  222. * @return type as enum.
  223. * @see DescriptorType for details.
  224. * */
  225. virtual DescriptorType getDescriptorType() const noexcept = 0;
  226. /**
  227. * @brief Get length of one descriptor. Specified by version of descriptors in batch.
  228. * @return Length of one descriptor in batch.
  229. * */
  230. virtual uint32_t getDescriptorLength() const noexcept = 0;
  231. /**
  232. * @brief Get descriptor from batch by index with copying.
  233. * @param [in] index descriptor index in batch.
  234. * @return ResultValue with error code and IDescriptorPtr instance.
  235. * @see IDescriptorPtr, ResultValue and FSDKError for details.
  236. * */
  237. virtual ResultValue<FSDKError, IDescriptorPtr> getDescriptorSlow(uint32_t index) const noexcept = 0;
  238. /**
  239. * @brief Get descriptor from batch by index without copying.
  240. * @param [in] index descriptor index in batch.
  241. * @return ResultValue with error code and IDescriptorPtr instance.
  242. * @see IDescriptorPtr, ResultValue and FSDKError for details.
  243. * @note If you change achived descriptor - corresponded descriptor in batch will be changed.
  244. * */
  245. virtual ResultValue<FSDKError, IDescriptorPtr> getDescriptorFast(uint32_t index) noexcept = 0;
  246. };
  247. /**
  248. * @brief Specialized for DescriptorBatchError.
  249. * */
  250. template<>
  251. struct ErrorTraits<IDescriptorBatch::Error> {
  252. static bool isOk(IDescriptorBatch::Error error) noexcept {
  253. return error == IDescriptorBatch::Error::Ok;
  254. }
  255. static const char* toString (IDescriptorBatch::Error error) noexcept {
  256. switch(error) {
  257. case IDescriptorBatch::Error::Ok: return "Ok";
  258. case IDescriptorBatch::Error::IoError: return "Error during reading/writing";
  259. case IDescriptorBatch::Error::Internal: return "Internal error";
  260. case IDescriptorBatch::Error::BatchFull: return "Batch is full";
  261. case IDescriptorBatch::Error::OutOfRange: return "Descriptor out of range";
  262. case IDescriptorBatch::Error::Incompatible: return "Incompatible descriptor";
  263. case IDescriptorBatch::Error::InvalidInput: return "Invalid input";
  264. default: return "Unknown error";
  265. }
  266. }
  267. };
  268. /**
  269. * @brief Descriptor extractor interface.
  270. * @details Extracts face descriptors from images. The descriptors can be later used for face matching.
  271. * */
  272. struct IDescriptorExtractor : IRefCounted {
  273. /**
  274. * @brief Extract descriptor from a warped image.
  275. * @param [in] warp image with warped face or human warp.
  276. * @note Warp should be a valid 250x250 image in R8G8B8 format for DT_FACE descriptor type.
  277. * @note Warp should be a valid 128x256 image in R8G8B8 format for DT_HUMAN descriptor type.
  278. * @param [out] descriptor descriptor to fill with data.
  279. * @return ResultValue with error code and score of descriptor normalized in range [0, 1]
  280. * 1 - face on the input warp; 0 - garbage on the input warp.
  281. * @note human descriptor does not support garbage score, 1.0 will be returned.
  282. * @see Image, IDescriptor, ResultValue and FSDKError for details.
  283. * @note warp format must be R8G8B8, @see Format.
  284. * */
  285. virtual ResultValue<FSDKError, float>
  286. extractFromWarpedImage(
  287. const Image& warp,
  288. IDescriptor* descriptor) const noexcept = 0;
  289. /**
  290. * @brief Extract batch of descriptors from a batch of images and perform aggregation.
  291. * @param [in] warps span of images with warped faces or human warps.
  292. * @note Warps should be in R8G8B8 format, with size 250x250 for DT_FACE descriptor type.
  293. * @note Warps should be in R8G8B8 format, with size 128x256 for DT_HUMAN descriptor type.
  294. * @param [out] descriptorBatch descriptor batch to fill with data.
  295. * @note DT_HUMAN descriptor does not support garbage score.
  296. * @param [out] aggregation descriptor with aggregation based on descriptor batch.
  297. * @param [out] garbageScoreBatch span of descriptor scores normalized in range [0, 1]
  298. * 1 - face on the input warp; 0 - garbage on the input warp.
  299. * @note human descriptor does not support garbage score, 1.0 will be returned.
  300. * @return ResultValue with error code and aggregated garbage score.
  301. * @see Span, Image, IDescriptor, IDescriptorBatch, ResultValue and FSDKError for details.
  302. * @note warps format must be R8G8B8, @see Format.
  303. * @note all spans should be based on user owned continuous collections.
  304. * @note all spans should be equal size.
  305. * */
  306. virtual ResultValue<FSDKError, float>
  307. extractFromWarpedImageBatch(
  308. Span<const Image> warps,
  309. IDescriptorBatch* descriptorBatch,
  310. IDescriptor* aggregation,
  311. Span<float> garbageScoreBatch) const noexcept = 0;
  312. /**
  313. * @brief Extract batch of descriptors from a batch of images.
  314. * @param [in] warps span of images with warped faces or human warps.
  315. * @note Warps should be in R8G8B8 format, with size 250x250 for DT_FACE descriptor type.
  316. * @note Warps should be in R8G8B8 format, with size 128x256 for DT_HUMAN descriptor type.
  317. * @param [out] descriptorBatch descriptor batch to fill with data.
  318. * @param [out] garbageScoreBatch span of descriptor scores normalized in range [0, 1]
  319. * 1 - face on the input warp; 0 - garbage on the input warp. DT_HUMAN descriptor does not support garbage score.
  320. * In a case of DT_HUMAN descriptor, you'll get batch filled by 1.0.
  321. * @return Result with error code.
  322. * @see Span, Image, IDescriptorBatch, Result and FSDKError for details.
  323. * @note warps format must be R8G8B8, @see Format.
  324. * @note all spans should be based on user owned continuous collections.
  325. * @note all spans should be equal size.
  326. * */
  327. virtual Result<FSDKError>
  328. extractFromWarpedImageBatch(
  329. Span<const Image> warps,
  330. IDescriptorBatch* descriptorBatch,
  331. Span<float> garbageScoreBatch) const noexcept = 0;
  332. /**
  333. * @brief Validate input of multiple frames in a single function call.
  334. * @param [in] warps span of images with warped faces or human warps.
  335. * @param [out] errors output span of errors for each image.
  336. * @return Result with error code.
  337. * @see Span, Image, Result and FSDKError for details.
  338. * @note warps format must be R8G8B8, @see Format.
  339. * @note all spans should be based on user owned continuous collections.
  340. * @note all spans should be equal size.
  341. * */
  342. virtual Result<FSDKError>
  343. validate(
  344. Span<const Image> warps,
  345. Span<Result<FSDKError>> errors) const noexcept = 0;
  346. /**
  347. * @brief Get algorithm model version this extractor works with.
  348. * @return Version as integral number.
  349. * */
  350. virtual uint32_t getModelVersion() const noexcept = 0;
  351. /**
  352. * @brief Get type of descriptor this extractor works with.
  353. * @return type as enum @see DescriptorType.
  354. * */
  355. virtual DescriptorType getDescriptorType() const noexcept = 0;
  356. /**
  357. * @brief Common aliases for BestShotQuality asynchronous interface.
  358. * */
  359. using FutureResult = vlc::future<float>;
  360. /**
  361. * @brief Asynchronously extract batch of descriptors from a batch of images.
  362. * @param [in] warps span of images with warped faces or human warps.
  363. * @note Warps should be in R8G8B8 format, with size 250x250 for DT_FACE descriptor type.
  364. * @note Warps should be in R8G8B8 format, with size 128x256 for DT_HUMAN descriptor type.
  365. * @param [out] descriptorBatch descriptor batch to fill with data.
  366. * @param [out] aggregation descriptor with aggregation based on descriptor batch.
  367. * @param [out] garbageScoreBatch span of descriptor scores normalized in range [0, 1]
  368. * 1 - face on the input warp; 0 - garbage on the input warp. DT_HUMAN descriptor does not support garbage score.
  369. * In a case of DT_HUMAN descriptor, you'll get batch filled by 1.0.
  370. * @return Result with error code and aggregated garbage score.
  371. * @see Span, Image, IDescriptorBatch, Result and FSDKError for details.
  372. * @note warps format must be R8G8B8, @see Format.
  373. * @note all spans should be based on user owned continuous collections.
  374. * @note all spans should be equal size.
  375. * @note this method is experimental and interface may be changed in the future.
  376. * @note this method is not marked as noexcept and may throw an exception.
  377. * */
  378. virtual FutureResult extractFromWarpedImageBatchAsync(
  379. Span<const Image> warps,
  380. IDescriptorBatch* descriptorBatch,
  381. IDescriptor* aggregation,
  382. Span<float> garbageScoreBatch) const = 0;
  383. };
  384. /**
  385. * @brief Descriptor matcher interface.
  386. * @details Matches descriptors 1:1 and 1:M (@see IDescriptor and IDescriptorBatch interfaces).
  387. *
  388. * As a result of the matching process the calling site gets a MatchingResult (or several of them in case of 1:M
  389. * matching). The MatchingResult structure contains distance and similarity metrics.
  390. *
  391. * Distance is measured in abstract units and tends to 0 for similar descriptors and to infinity for different ones.
  392. * Similarity is the opposite metric and shows probability of two descriptors belonging to the same person; therfore
  393. * it is normalized to [0..1] range.
  394. *
  395. * @see MatchingResult for details.
  396. * */
  397. struct IDescriptorMatcher : IRefCounted {
  398. /**
  399. * @brief Match descriptors 1:1.
  400. * @param [in] first first descriptor.
  401. * @param [in] second second descriptor.
  402. * @return ResultValue with error code and matching result.
  403. * @see MatchingResult, IDescriptor, ResultValue and FSDKError for details.
  404. * */
  405. virtual ResultValue<
  406. FSDKError,
  407. MatchingResult>
  408. match(
  409. const IDescriptor* first,
  410. const IDescriptor* second) noexcept = 0;
  411. /**
  412. * @brief Match descriptors 1:M.
  413. * @details Matches a reference descriptor to a batch of candidate descriptors. The results are layed out in the
  414. * same order as the candidate descriptors in the batch.
  415. * @param [in] reference the reference descriptor.
  416. * @param [in] candidates the candidate descriptor batch to match with the reference.
  417. * @param [out] results span of matching results.
  418. * @note Length of `results` must be at least the same as the length of the candidates batch.
  419. * @see IDescriptorBatch::getMaxCount().
  420. * @return Result with error code.
  421. * @see Span, MatchingResult, IDescriptor, IDescriptorBatch, Result and FSDKError for details.
  422. * @note all spans should be based on user owned continuous collections.
  423. * */
  424. virtual Result<FSDKError>
  425. match(
  426. const IDescriptor* reference,
  427. const IDescriptorBatch* candidates,
  428. Span<MatchingResult> results) noexcept = 0;
  429. /**
  430. * @brief Get algorithm model version this matcher works with.
  431. * @return Version as integral number.
  432. * */
  433. virtual uint32_t getModelVersion() const noexcept = 0;
  434. /**
  435. * @brief Calculates similarity based on distance.
  436. * @details The method gets distance from `distances`[i].distances.
  437. * and assigns the result to `distances`[i].similarity.
  438. * @param [in] dinstances is a mutable span of matching results with calculated distances.
  439. * @return Result with error code.
  440. * @see Span, MatchingResult, Result and FSDKError for details.
  441. * @note all spans should be based on user owned continuous collections.
  442. * */
  443. virtual Result<FSDKError> calcSimilarity(Span<MatchingResult> distances) const noexcept = 0;
  444. /**
  445. * @brief Calculates distance from similarity.
  446. * @details The method gets similarity from `similarities`[i].similarity
  447. * and assigns the result to `similarities`[i].distance.
  448. * @param [in] similarities is a mutable span of matching results with calculated similarity.
  449. * @return Result with error code.
  450. * @see Span, MatchingResult, Result and FSDKError for details.
  451. * @note all spans should be based on user owned continuous collections.
  452. * */
  453. virtual Result<FSDKError> calcDistance(Span<MatchingResult> similarities) const noexcept = 0;
  454. };
  455. /** @} */
  456. }