CppNCorr
C++ ncorr Digital Image Correlation engine
Loading...
Searching...
No Matches
frame_reader.h
Go to the documentation of this file.
1#pragma once
27#include <algorithm>
28#include <cctype>
29#include <cerrno>
30#include <cstring>
31#include <stdexcept>
32#include <string>
33#include <vector>
34
35#include <dirent.h>
36#include <sys/stat.h>
37
38namespace ncorr {
39
46inline const std::vector<std::string>& image_extensions() {
47 static const std::vector<std::string> kImageExtensions = {".png", ".tif", ".tiff",
48 ".bmp", ".jpg", ".jpeg"};
49 return kImageExtensions;
50}
51
60inline bool has_image_extension(const std::string& lower_name) {
61 for (const std::string& ext : image_extensions()) {
62 if (lower_name.size() > ext.size() &&
63 lower_name.compare(lower_name.size() - ext.size(), ext.size(), ext) == 0) {
64 return true;
65 }
66 }
67 return false;
68}
69
81inline bool natural_less(const std::string& a, const std::string& b) {
82 size_t i = 0, j = 0;
83 while (i < a.size() && j < b.size()) {
84 if (std::isdigit(static_cast<unsigned char>(a[i])) &&
85 std::isdigit(static_cast<unsigned char>(b[j]))) {
86 // Compare two runs of digits by numeric value (skip leading zeros).
87 size_t ai = i, bj = j;
88 while (ai < a.size() && std::isdigit(static_cast<unsigned char>(a[ai]))) ++ai;
89 while (bj < b.size() && std::isdigit(static_cast<unsigned char>(b[bj]))) ++bj;
90 std::string da = a.substr(i, ai - i);
91 std::string db = b.substr(j, bj - j);
92 da.erase(0, da.find_first_not_of('0'));
93 db.erase(0, db.find_first_not_of('0'));
94 if (da.size() != db.size()) return da.size() < db.size();
95 if (da != db) return da < db;
96 i = ai;
97 j = bj;
98 } else {
99 if (a[i] != b[j]) return a[i] < b[j];
100 ++i;
101 ++j;
102 }
103 }
104 return a.size() < b.size();
105}
106
122inline std::vector<std::string> discover_frames(const std::string& folder,
123 const std::string& ref_path,
124 const std::string& roi_path) {
125 std::vector<std::string> frames;
126 DIR* dir = opendir(folder.c_str());
127 if (!dir) {
128 throw std::runtime_error("Cannot open folder '" + folder + "': " + std::strerror(errno));
129 }
130
131 // Get basenames to exclude.
132 std::string roi_basename = "";
133 std::string ref_basename = "";
134 if (!roi_path.empty()) {
135 size_t pos = roi_path.find_last_of("/\\");
136 roi_basename = (pos != std::string::npos) ? roi_path.substr(pos + 1) : roi_path;
137 }
138 if (!ref_path.empty()) {
139 size_t pos = ref_path.find_last_of("/\\");
140 ref_basename = (pos != std::string::npos) ? ref_path.substr(pos + 1) : ref_path;
141 }
142
143 struct dirent* entry;
144 while ((entry = readdir(dir)) != nullptr) {
145 std::string name = entry->d_name;
146
147 // Skip empty names (defensive) and hidden files / "." / ".." entries.
148 if (name.empty() || name[0] == '.') continue;
149
150 // Skip nested sub-directories: only regular files are valid frames.
151 std::string full_path = folder + "/" + name;
152 struct stat st;
153 if (stat(full_path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) continue;
154
155 // Check for image extensions (case-insensitive, length-safe).
156 std::string lower_name = name;
157 std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(),
158 [](unsigned char c) { return std::tolower(c); });
159
160 if (!has_image_extension(lower_name)) continue;
161
162 // Skip reserved roi.png / ref.png by default.
163 if (lower_name == "roi.png") continue;
164 if (lower_name == "ref.png") continue;
165
166 // Skip explicitly specified roi and ref files.
167 if (!roi_basename.empty() && name == roi_basename) continue;
168 if (!ref_basename.empty() && name == ref_basename) continue;
169
170 frames.push_back(full_path);
171 }
172 closedir(dir);
173
174 // Sort frames naturally (handles both padded and unpadded numbered files).
175 std::sort(frames.begin(), frames.end(), natural_less);
176
177 return frames;
178}
179
180} // namespace ncorr
bool has_image_extension(const std::string &lower_name)
Test whether a (lowercased) filename ends with a supported image extension.
const std::vector< std::string > & image_extensions()
Supported image extensions (lowercase, including the leading dot).
bool natural_less(const std::string &a, const std::string &b)
Natural (human) ordering comparison for filenames.
std::vector< std::string > discover_frames(const std::string &folder, const std::string &ref_path, const std::string &roi_path)
Discover the deformed-frame image files inside folder.