25 #define DEFAULT_FPS 30
36 #include <opencv2/core/core.hpp>
37 #include <opencv2/highgui/highgui.hpp>
38 #include <opencv2/imgproc/imgproc.hpp>
41 #include <SimoxUtility/algorithm/string/string_tools.h>
48 this->playingBack =
false;
49 this->currentFrame = 0;
54 const std::filesystem::path& filePath)
56 this->playingBack =
false;
57 this->currentFrame = 0;
59 this->startPlayback(filePath);
70 return this->playingBack;
77 <<
"FPS cannot be reconstructed from a bare image sequence. Using a pre-set default of "
86 return this->frameCount;
92 return this->frameHeight;
98 return this->frameWidth;
104 this->currentFrame = frame;
110 return this->currentFrame;
116 return this->currentFrame < this->frameCount;
121 const std::filesystem::path& filePath)
123 this->initBasePathPrefixSuffix(filePath);
124 this->initFramePaths();
125 this->initFrameDimensions();
127 this->frameCount =
static_cast<unsigned int>(this->framePaths.size());
129 this->playingBack =
true;
136 if (this->currentFrame >= this->frameCount)
143 if (!this->getNextFrame(frame))
149 cv::cvtColor(frame, frame, cv::COLOR_BGR2RGB);
152 this->frameHeight * this->frameWidth *
static_cast<unsigned int>(frame.channels()));
161 return this->getNextFrame(buffer.pixels);
167 buffer = cv::imread(this->framePaths[this->currentFrame++].
string());
170 if (buffer.data ==
nullptr)
176 if (
static_cast<unsigned int>(buffer.size().height) != this->frameHeight or
177 static_cast<unsigned int>(buffer.size().width) != this->frameWidth)
188 this->playingBack =
false;
192 visionx::imrec::strats::ImageSequencePlaybackStrategy::initBasePathPrefixSuffix(
193 const std::filesystem::path& filePath)
196 auto findCommonPrefix = [](
const std::string& s1,
const std::string& s2) -> std::string
198 std::string commonPrefix =
"";
200 for (
unsigned int i = 0; i < s1.length() and i < s2.length(); ++i)
204 commonPrefix += s1[i];
214 auto findCommonSuffix = [](
const std::string& s1,
const std::string& s2) -> std::string
216 std::string commonSuffix =
"";
218 for (
unsigned int i = 1; i <= s1.length() and i <= s2.length(); ++i)
220 if (s1[s1.length() - i] == s2[s2.length() - i])
222 commonSuffix = s1[s1.length() - i] + commonSuffix;
234 std::filesystem::path basePath;
235 std::string requiredPrefix =
"";
236 std::string requiredSuffix =
"";
239 if (std::filesystem::is_directory(filePath))
242 basePath = std::filesystem::canonical(filePath);
245 std::string prefixCandidate =
"";
246 std::string suffixCandidate =
"";
247 bool candidatesInitialised =
false;
250 for (
auto de = std::filesystem::directory_iterator(basePath);
251 de != std::filesystem::directory_iterator{};
254 const std::string currentFile = de->path().filename().string();
258 if (!candidatesInitialised)
260 prefixCandidate = currentFile;
261 suffixCandidate = currentFile;
262 candidatesInitialised =
true;
266 prefixCandidate = findCommonPrefix(prefixCandidate, currentFile);
267 suffixCandidate = findCommonSuffix(suffixCandidate, currentFile);
272 requiredPrefix = prefixCandidate;
273 requiredSuffix = suffixCandidate;
279 basePath = std::filesystem::canonical(filePath.parent_path());
282 std::string
filename = filePath.filename().string();
283 const unsigned int wildcardCount =
284 static_cast<unsigned int>(std::count(
filename.begin(),
filename.end(),
'*'));
290 if (wildcardCount == 1)
299 std::string prefixCandidate =
filename;
300 std::string suffixCandidate =
filename;
303 for (
auto de = std::filesystem::directory_iterator(basePath);
304 de != std::filesystem::directory_iterator{};
307 const std::string currentFile = de->path().filename().string();
308 prefixCandidate = findCommonPrefix(prefixCandidate, currentFile);
309 suffixCandidate = findCommonSuffix(suffixCandidate, currentFile);
313 requiredPrefix = prefixCandidate;
314 requiredSuffix = suffixCandidate;
318 this->basePath = basePath;
319 this->requiredPrefix = requiredPrefix;
320 this->requiredSuffix = requiredSuffix;
324 visionx::imrec::strats::ImageSequencePlaybackStrategy::initFramePaths()
327 unsigned long prefixLength = requiredPrefix.length();
328 unsigned long suffixLength = requiredSuffix.length();
329 auto naturalSortComparator = [prefixLength,
330 suffixLength](
const std::filesystem::path&
a,
331 const std::filesystem::path& b) ->
bool
333 std::string as =
a.filename().string();
334 std::string bs = b.filename().string();
335 unsigned long normalisation = 2;
336 as = as.substr(prefixLength, as.length() - (suffixLength + normalisation));
337 bs = bs.substr(prefixLength, bs.length() - (suffixLength + normalisation));
340 if (as.length() == bs.length())
346 while (as.length() > 0 and bs.length() > 0)
348 unsigned int asi = 0;
349 unsigned int bsi = 0;
350 std::stringstream(as) >> asi;
351 std::stringstream(bs) >> bsi;
354 if (as[0] == bs[0] and asi == bsi)
356 unsigned int decimals = 1;
363 as = as.substr(decimals, as.length());
364 bs = bs.substr(decimals, bs.length());
367 else if ((asi > 0 or (asi == 0 and as[0] ==
'0')) and
368 (bsi > 0 or (bsi == 0 and bs[0] ==
'0')))
375 return as[0] < bs[0];
379 return as.length() < bs.length();
383 for (
auto de = std::filesystem::directory_iterator(basePath);
384 de != std::filesystem::directory_iterator{};
387 const std::string currentFile = de->path().filename().string();
393 this->framePaths.push_back(de->path());
398 std::sort(this->framePaths.begin(), this->framePaths.end(), naturalSortComparator);
402 visionx::imrec::strats::ImageSequencePlaybackStrategy::initFrameDimensions()
404 const std::filesystem::path probe = this->framePaths.at(0);
405 cv::Mat frameImage = cv::imread(probe.string());
408 <<
"Failed loading first frame. Image file corrupted?";
410 this->frameHeight =
static_cast<unsigned int>(frameImage.size().height);
411 this->frameWidth =
static_cast<unsigned int>(frameImage.size().width);