SOMHunter Core
dataset-features.h
Go to the documentation of this file.
1 /* This file is part of SOMHunter.
2  *
3  * Copyright (C) 2021 Frantisek Mejzlik <frankmejzlik@protonmail.com>
4  * Mirek Kratochvil <exa.exa@gmail.com>
5  * Patrik Vesely <prtrikvesely@gmail.com>
6  *
7  * SOMHunter is free software: you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License as published by the Free
9  * Software Foundation, either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * SOMHunter is distributed in the hope that it will be useful, but WITHOUT ANY
13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU General Public License along with
18  * SOMHunter. If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #ifndef DATASET_FEATURES_H_
22 #define DATASET_FEATURES_H_
23 
24 #include "dataset-frames.h"
25 // ---
26 #include <cmath>
27 #include <exception>
28 #include <fstream>
29 #include <map>
30 #include <queue>
31 // ---
32 #include "common.h"
33 #include "distances.hpp"
34 
35 namespace sh {
39 template <typename SETT>
41  // *** METHODS ***
42 public:
43  FrameFeatures() = delete;
44  FrameFeatures(const DatasetFrames& frames, const SETT& config);
45 
46  // ---
47 
48  size_t size() const { return _size; }
49  size_t dim() const { return _dim; }
50  const float* fv(size_t i) const { return _data.data() + _dim * i; }
51 
52  std::vector<FrameId> get_top_knn(const DatasetFrames& _dataset_frames, FrameId id, size_t per_vid_limit = 0,
53  size_t from_shot_limit = 0) const;
54 
55  std::vector<FrameId> get_top_knn(const DatasetFrames& _dataset_frames, FrameId id,
56  std::function<bool(FrameId ID)> pred, size_t per_vid_limit = 0,
57  size_t from_shot_limit = 0) const;
58 
59  float d_manhattan(size_t i, size_t j) const;
60  float d_sqeucl(size_t i, size_t j) const;
61  float d_eucl(size_t i, size_t j) const;
62  float d_dot_normalized(size_t i, size_t j) const;
63  float d_cos(size_t i, size_t j) const;
64 
65  // *** MEMBER VARIABLES ***
66 private:
68  std::size_t _size;
70  std::size_t _dim;
72  std::vector<float> _data;
73 };
74 
77 
82 public:
83  DatasetFeatures(const DatasetFrames& frames, const Settings& config)
84  : primary{ frames, config.datasets.primary_features },
85  secondary{ frames, config.datasets.secondary_features } {};
86 
87 public:
90 };
91 
92 template <typename SETT>
93 FrameFeatures<SETT>::FrameFeatures(const DatasetFrames& p, const SETT& config) : _size{ 0 }, _dim{ 0 } {
94  // If no features are provided
95  if (config.features_file.empty()) {
96  SHLOG_W("No features provided for '" << utils::type_name<SETT>() << "'...");
97  return;
98  }
99 
100  SHLOG_D("Loading dataset features from '" << config.features_file << "'...");
101 
102  _size = p.size();
103  _dim = config._dim;
104 
105  _data.resize(_dim * _size);
106  std::ifstream in(config.features_file, std::ios::binary);
107  if (!in.good()) {
108  std::string msg{ "Error opening features file '" + config.features_file + "'!" };
109  SHLOG_E(msg);
110  throw std::runtime_error(msg);
111  }
112 
113  // Skip the header
114  in.ignore(config.features_file_data_off);
115 
116  if (!in.read(reinterpret_cast<char*>(_data.data()), sizeof(float) * _data.size())) {
117  std::string msg{ "Feature matrix reading problems at '" + config.features_file + "'!" };
118  SHLOG_E(msg);
119  throw std::runtime_error(msg);
120  } else {
121  SHLOG_S("Successfully loaded " << _size << " frame features of dimension " << config._dim << ".");
122  }
123 
124  // Detect the incomplete read!
125  if (in.rdbuf()->in_avail() != 0) {
126  std::string msg{ "Incomplete read of the '" + config.features_file + "' file!" };
127  SHLOG_E(msg);
128  throw std::runtime_error(msg);
129  }
130 }
131 
132 template <typename SETT>
133 std::vector<FrameId> FrameFeatures<SETT>::get_top_knn(const DatasetFrames& _dataset_frames, FrameId id,
134  size_t per_vid_limit, size_t from_shot_limit) const {
135  return get_top_knn(
136  _dataset_frames, id, [](FrameId /*frame_ID*/) { return true; }, per_vid_limit, from_shot_limit);
137 }
138 
139 template <typename SETT>
140 std::vector<FrameId> FrameFeatures<SETT>::get_top_knn(const DatasetFrames& _dataset_frames, FrameId id,
141  std::function<bool(FrameId ID)> pred, size_t per_vid_limit,
142  size_t from_shot_limit) const {
143  if (per_vid_limit == 0) per_vid_limit = _dataset_frames.size();
144 
145  if (from_shot_limit == 0) from_shot_limit = _dataset_frames.size();
146 
147  auto cmp = [](const std::pair<FrameId, float>& left, const std::pair<FrameId, float>& right) {
148  return left.second > right.second;
149  };
150 
151  std::priority_queue<std::pair<FrameId, float>, std::vector<std::pair<FrameId, float>>, decltype(cmp)> q3(cmp);
152 
153  for (FrameId i{ 0 }; i < _size; ++i) {
154  auto d = d_dot_normalized(id, i);
155  q3.emplace(i, d);
156  }
157 
158  std::vector<FrameId> res;
159  res.reserve(TOPKNN_LIMIT);
160 
161  size_t num_videos = _dataset_frames.get_num_videos();
162  std::vector<size_t> per_vid_frame_hist(num_videos, 0);
163  std::map<VideoId, std::map<ShotId, size_t>> frames_per_shot;
164 
165  while (res.size() < TOPKNN_LIMIT && !q3.empty()) {
166  auto [adept_ID, f]{ q3.top() };
167 
168  if (q3.empty()) break;
169 
170  q3.pop();
171 
172  auto vf = _dataset_frames.get_frame(adept_ID);
173 
174  // If we have already enough from this video
175  if (per_vid_frame_hist[vf.video_ID] >= per_vid_limit) continue;
176 
177  // If we have already enough from this shot
178  if (frames_per_shot[vf.video_ID][vf.shot_ID] >= from_shot_limit) continue;
179 
180  // Only if predicate is true
181  if (pred(adept_ID)) {
182  res.emplace_back(adept_ID);
183  per_vid_frame_hist[vf.video_ID]++;
184  frames_per_shot[vf.video_ID][vf.shot_ID]++;
185  }
186  }
187 
188  return res;
189 }
190 
191 template <typename SETT>
192 float FrameFeatures<SETT>::d_manhattan(size_t i, size_t j) const {
193  return ::d_manhattan(fv(i), fv(j), _dim);
194 }
195 
196 template <typename SETT>
197 float FrameFeatures<SETT>::d_sqeucl(size_t i, size_t j) const {
198  return ::d_sqeucl(fv(i), fv(j), _dim);
199 }
200 
201 template <typename SETT>
202 float FrameFeatures<SETT>::d_eucl(size_t i, size_t j) const {
203  return sqrtf(d_sqeucl(i, j));
204 }
205 
206 template <typename SETT>
207 float FrameFeatures<SETT>::d_dot_normalized(size_t i, size_t j) const {
208  return 1 - ::d_dot_normalized(fv(i), fv(j), _dim);
209 }
210 
211 template <typename SETT>
212 float FrameFeatures<SETT>::d_cos(size_t i, size_t j) const {
213  float s = 0, w1 = 0, w2 = 0;
214  const float *iv = fv(i), *jv = fv(j);
215  for (size_t d = 0; d < _dim; ++d) {
216  s += iv[d] * jv[d];
217  w1 += utils::square(iv[d]);
218  w2 += utils::square(jv[d]);
219  }
220  if (w1 == 0 && w2 == 0) return 0;
221  return 1 - s / sqrtf(w1 * w2);
222 }
223 
224 }; // namespace sh
225 
226 #endif // DATASET_FEATURES_H_
Represents all available feature sets.
Definition: dataset-features.h:81
PrimaryFrameFeatures primary
Definition: dataset-features.h:85
SecondaryFrameFeatures secondary
Definition: dataset-features.h:89
DatasetFeatures(const DatasetFrames &frames, const Settings &config)
Definition: dataset-features.h:83
Definition: dataset-frames.h:162
size_t get_num_videos() const
Definition: dataset-frames.h:182
size_t size() const
Definition: dataset-frames.h:194
VideoFrame & get_frame(FrameId i)
Definition: dataset-frames.h:184
Represents one set of features for the given dataset.
Definition: dataset-features.h:40
size_t size() const
Definition: dataset-features.h:48
FrameFeatures(const DatasetFrames &frames, const SETT &config)
Definition: dataset-features.h:93
float d_dot_normalized(size_t i, size_t j) const
Definition: dataset-features.h:207
float d_sqeucl(size_t i, size_t j) const
Definition: dataset-features.h:197
size_t dim() const
Definition: dataset-features.h:49
std::vector< float > _data
Raw flat data matrix (row-wise).
Definition: dataset-features.h:72
FrameFeatures()=delete
float d_eucl(size_t i, size_t j) const
Definition: dataset-features.h:202
std::vector< FrameId > get_top_knn(const DatasetFrames &_dataset_frames, FrameId id, std::function< bool(FrameId ID)> pred, size_t per_vid_limit=0, size_t from_shot_limit=0) const
Definition: dataset-features.h:140
const float * fv(size_t i) const
Definition: dataset-features.h:50
float d_cos(size_t i, size_t j) const
Definition: dataset-features.h:212
std::size_t _size
Number of rows (i.e.
Definition: dataset-features.h:68
float d_manhattan(size_t i, size_t j) const
Definition: dataset-features.h:192
std::size_t _dim
Number of vector components.
Definition: dataset-features.h:70
std::vector< FrameId > get_top_knn(const DatasetFrames &_dataset_frames, FrameId id, size_t per_vid_limit=0, size_t from_shot_limit=0) const
Definition: dataset-features.h:133
File implementing distance calculations on vectors.
Definition: common-types.h:33
unsigned long FrameId
Definition: common-types.h:75
#define TOPKNN_LIMIT
Definition: static-config.h:69
#define SHLOG_E(x)
Definition: static-logger.hpp:157
#define SHLOG_S(x)
Definition: static-logger.hpp:173
#define SHLOG_W(x)
Definition: static-logger.hpp:165
#define SHLOG_D(x)
Definition: static-logger.hpp:179
Parsed current config of the core.
Definition: settings.h:190