Files
chicken-counting-sukawarna-det/cpp/include/chicken_counter/batch_discovery.hpp
T
2026-07-22 00:03:02 +07:00

103 lines
3.4 KiB
C++

#pragma once
#include <filesystem>
#include <iostream>
#include <regex>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include "chicken_counter/config.hpp"
namespace cc {
struct CameraDiscoveryResult {
std::unordered_map<std::string, std::string> found;
std::unordered_map<std::string, std::string> skipped;
};
inline std::string replace_glob_placeholder(const std::string& pattern, int num) {
std::string s = pattern;
std::string token = "{num}";
size_t pos = s.find(token);
if (pos != std::string::npos) {
s.replace(pos, token.size(), std::to_string(num));
}
return s;
}
inline std::vector<std::string> glob_filenames(const std::string& dir, const std::string& pattern) {
namespace fs = std::filesystem;
std::vector<std::string> matches;
std::string regex_str = "^";
for (char c : pattern) {
if (c == '*') regex_str += ".*";
else if (c == '?') regex_str += ".";
else if (c == '.' || c == '[' || c == ']' || c == '(' || c == ')' || c == '{' || c == '}')
regex_str += std::string("\\") + c;
else regex_str += c;
}
regex_str += "$";
std::regex re(regex_str);
for (auto& entry : fs::directory_iterator(dir)) {
if (!entry.is_regular_file()) continue;
std::string fname = entry.path().filename().string();
if (std::regex_match(fname, re))
matches.push_back(entry.path().string());
}
std::sort(matches.begin(), matches.end());
return matches;
}
inline CameraDiscoveryResult discover_camera_videos(
const std::string& day_dir,
const BatchSettings& settings)
{
namespace fs = std::filesystem;
if (!fs::is_directory(day_dir))
throw std::runtime_error("Daily input folder does not exist: " + day_dir);
CameraDiscoveryResult result;
int total = static_cast<int>(settings.cameras.size());
using pair_t = std::pair<std::string, CameraPreset>;
std::vector<pair_t> sorted_cams(settings.cameras.begin(), settings.cameras.end());
std::sort(sorted_cams.begin(), sorted_cams.end(),
[](const pair_t& a, const pair_t& b) { return a.second.camera_num < b.second.camera_num; });
for (const auto& [camera_id, preset] : sorted_cams) {
std::string pattern = replace_glob_placeholder(settings.batch.camera_glob, preset.camera_num);
auto matches = glob_filenames(day_dir, pattern);
if (matches.empty()) {
result.skipped[camera_id] = "video_not_found";
continue;
}
if (matches.size() > 1) {
result.skipped[camera_id] = "multiple_matches";
continue;
}
result.found[camera_id] = matches[0];
}
if (result.found.empty()) {
std::string summary;
for (const auto& [id, reason] : result.skipped) summary += id + " (" + reason + "), ";
throw std::runtime_error("No camera videos found in " + day_dir + ". Skipped: " + summary);
}
int found_count = static_cast<int>(result.found.size());
if (!result.skipped.empty()) {
std::string summary;
for (const auto& [id, reason] : result.skipped) summary += id + " (" + reason + "), ";
std::cerr << "[batch] discovered " << found_count << "/" << total
<< " cameras; skipped: " << summary << "\n";
} else {
std::cerr << "[batch] discovered " << found_count << "/" << total << " cameras\n";
}
return result;
}
} // namespace cc