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;
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)
149 cv::cvtColor(frame, frame, cv::COLOR_BGR2RGB);
152 this->frameHeight * this->frameWidth *
static_cast<unsigned int>(frame.channels()));
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;
192visionx::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)
292 requiredPrefix = filename.substr(0, filename.find(
'*'));
293 requiredSuffix = filename.substr(filename.find(
'*') + 1, filename.length());
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;
324visionx::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();
390 if (simox::alg::starts_with(currentFile, this->requiredPrefix) and
391 simox::alg::ends_with(currentFile, this->requiredSuffix))
393 this->framePaths.push_back(de->path());
398 std::sort(this->framePaths.begin(), this->framePaths.end(), naturalSortComparator);
402visionx::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);
ImageSequencePlaybackStrategy()
Default constructor to manually setup later.
virtual void setCurrentFrame(unsigned int frame) override
Sets the frame from there the playback should resume afterwards (seek)
virtual void stopPlayback() override
Stops the playback.
virtual unsigned int getFrameWidth() const override
Gets the width of a frame in pixel.
virtual unsigned int getFps() const override
Gets the amount of frames per second of the recording.
virtual bool hasNextFrame() const override
Indicates whether the recording has a consecutive frame.
virtual unsigned int getFrameCount() const override
Gets the total amout of frames in the recording.
virtual unsigned int getCurrentFrame() const override
Gets the current frame index of the playback.
virtual bool getNextFrame(void *buffer) override
Writes the next frame into a buffer of any form (RGB)
virtual ~ImageSequencePlaybackStrategy() override
Destructor.
virtual void startPlayback(const std::filesystem::path &filePath) override
Starts the playback.
virtual bool isPlayingBack() const override
Indicates whether the instance is configured to be able to play back.
virtual unsigned int getFrameHeight() const override
Gets the height of a frame in pixel.
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
double a(double t, double a0, double j)