11#if CV_VERSION_MAJOR >= 5
12#include <opencv2/geometry.hpp>
21 const cv::Mat& reference_image) {
22 if (std::filesystem::exists(params.
roifile)) {
26 LOG_WARN <<
"ROI file not found, creating full ROI";
32 mat_t* matfp = Mat_Open(roi_file.c_str(), MAT_ACC_RDONLY);
34 LOG_ERROR <<
"Failed to open ROI file: " << roi_file;
39 matvar_t* refmask_var = Mat_VarRead(matfp,
"refmask");
41 LOG_ERROR <<
"Variable 'refmask' not found in " << roi_file;
48 if (refmask_var->class_type == MAT_C_UINT8 && refmask_var->rank == 2) {
49 size_t height = refmask_var->dims[0];
50 size_t width = refmask_var->dims[1];
52 roi_mask = cv::Mat(height, width, CV_8UC1);
53 const uint8_t* data =
static_cast<const uint8_t*
>(refmask_var->data);
56 bool is_logical = (refmask_var->isLogical != 0);
59 for (
size_t y = 0; y < height; ++y) {
60 for (
size_t x = 0; x < width; ++x) {
61 uint8_t value = data[x * height + y];
63 roi_mask.at<uint8_t>(y, x) = is_logical ? (value * 255) : value;
68 LOG_DEBUG <<
" Loaded logical mask (scaled 0/1 to 0/255)";
71 LOG_WARN <<
"Unexpected refmask type (class=" << refmask_var->class_type
72 <<
", rank=" << refmask_var->rank <<
")";
75 Mat_VarFree(refmask_var);
84 mat_t* matfp = Mat_Open(seed_file.c_str(), MAT_ACC_RDONLY);
86 LOG_ERROR <<
"Failed to open seed file: " << seed_file;
91 matvar_t* seed_var = Mat_VarRead(matfp,
"seed_point");
93 LOG_ERROR <<
"Variable 'seed_point' not found in " << seed_file;
99 if (seed_var->rank >= 1 && seed_var->data) {
100 size_t num_elements = 1;
101 for (
int i = 0; i < seed_var->rank; i++) {
102 num_elements *= seed_var->dims[i];
105 if (num_elements >= 2) {
107 if (seed_var->data_type == MAT_T_UINT16 || seed_var->data_type == MAT_T_INT16) {
108 const uint16_t* data =
static_cast<const uint16_t*
>(seed_var->data);
109 seed.
pw = {
static_cast<int>(data[0]),
static_cast<int>(data[1])};
110 }
else if (seed_var->data_type == MAT_T_DOUBLE) {
111 const double* data =
static_cast<const double*
>(seed_var->data);
112 seed.
pw = {
static_cast<int>(data[0]),
static_cast<int>(data[1])};
113 }
else if (seed_var->data_type == MAT_T_SINGLE) {
114 const float* data =
static_cast<const float*
>(seed_var->data);
115 seed.
pw = {
static_cast<int>(data[0]),
static_cast<int>(data[1])};
117 LOG_WARN <<
"Unexpected seed_point data type: " << seed_var->data_type;
119 const uint16_t* data =
static_cast<const uint16_t*
>(seed_var->data);
120 seed.
pw = {
static_cast<int>(data[0]),
static_cast<int>(data[1])};
122 LOG_DEBUG <<
" Loaded seed point: (" << seed.
pw[0] <<
", " << seed.
pw[1] <<
")";
126 Mat_VarFree(seed_var);
133 const cv::Mat& roi_mask) {
134 if (std::filesystem::exists(params.
seedfile)) {
138 LOG_WARN <<
"Seed file not found, creating default seed at ROI center";
150 int subset_spacing) {
151 double scalefactor =
static_cast<double>(subset_spacing + 1);
153 static_cast<int>(std::round(pixel_coords[0] / scalefactor)),
154 static_cast<int>(std::round(pixel_coords[1] / scalefactor))
162 int subset_spacing) {
163 double scalefactor =
static_cast<double>(subset_spacing + 1);
165 static_cast<int>(std::round(subset_coords[0] * scalefactor)),
166 static_cast<int>(std::round(subset_coords[1] * scalefactor))
171 const cv::Mat& U_mapped,
172 const cv::Mat& V_mapped) {
174 int x =
static_cast<int>(std::round(point_sw[0]));
175 int y =
static_cast<int>(std::round(point_sw[1]));
180 if (x < 0 || x >= U_mapped.cols || y < 0 || y >= U_mapped.rows) {
181 LOG_ERROR <<
"Point coordinates out of bounds: (" << x <<
", " << y <<
")";
186 double u = U_mapped.at<
double>(y, x);
187 double v = V_mapped.at<
double>(y, x);
194 static_cast<int>(std::round(point_sw[0] + u)),
195 static_cast<int>(std::round(point_sw[1] + v))
200 cv::Mat& refmask_REF,
201 cv::Mat& refmask_trial,
204 int subset_spacing) {
205 mat_t* matfp = Mat_Open(matching_file.c_str(), MAT_ACC_RDONLY);
207 LOG_ERROR <<
"Failed to open matching file: " << matching_file;
211 LOG_INFO <<
"Loading matching results from: " << matching_file;
217 Mat_VarFree(ref_roi_mask);
218 LOG_DEBUG <<
" Loaded reference ROI mask: " << refmask_REF.size();
220 LOG_WARN <<
" Could not load reference_save.roi.mask";
227 Mat_VarFree(cur_roi_mask);
228 LOG_DEBUG <<
" Loaded current ROI mask: " << refmask_trial.size();
230 LOG_WARN <<
" Could not load current_save.roi.mask";
235 if (u_cell && u_cell->class_type == MAT_C_CELL) {
240 LOG_DEBUG <<
" Loaded U displacements: " << U_mapped.size();
244 LOG_WARN <<
" Could not load plot_u_ref_formatted";
249 if (v_cell && v_cell->class_type == MAT_C_CELL) {
254 LOG_DEBUG <<
" Loaded V displacements: " << V_mapped.size();
258 LOG_WARN <<
" Could not load plot_v_ref_formatted";
263 bool success = !refmask_REF.empty() && !refmask_trial.empty();
265 LOG_INFO <<
"Successfully loaded matching results";
272 LOG_INFO <<
"Creating full ROI (all pixels valid)";
273 return cv::Mat::ones(image_size, CV_8UC1) * 255;
277 cv::Point2f center = computeROICenterOfMass(roi_mask);
278 return {
static_cast<int>(center.x),
static_cast<int>(center.y)};
282 const auto& mask = roi.get_mask();
283 size_t height = mask.height();
284 size_t width = mask.width();
286 cv::Mat cv_mask(height, width, CV_8UC1);
288 for (
size_t y = 0; y < height; ++y) {
289 for (
size_t x = 0; x < width; ++x) {
290 cv_mask.at<uint8_t>(y, x) = mask(y, x) ? 255 : 0;
299 size_t height = mask.rows;
300 size_t width = mask.cols;
302 ncorr::Array2D<bool> bool_mask(height, width);
304 for (
size_t y = 0; y < height; ++y) {
305 for (
size_t x = 0; x < width; ++x) {
306 bool_mask(y, x) = (mask.at<uint8_t>(y, x) > 0);
310 return ncorr::ROI2D(bool_mask);
313cv::Point2f ROIManager::computeROICenterOfMass(
const cv::Mat& roi_mask) {
314 cv::Moments m = cv::moments(roi_mask,
true);
318 return cv::Point2f(roi_mask.cols / 2.0f, roi_mask.rows / 2.0f);
321 return cv::Point2f(m.m10 / m.m00, m.m01 / m.m00);
static cv::Mat readImage(matvar_t *var)
Read image from matvar.
static matvar_t * getCellElement(matvar_t *var, size_t index)
Get cell from cell array.
static matvar_t * readNestedField(mat_t *matfp, const std::string &path)
Read a nested struct field (e.g., "data_dic_save.dispinfo.radius")
static std::vector< int > mapSubset2Pixel(const std::vector< int > &subset_coords, int subset_spacing)
Map subset coordinates to pixel coordinates Equivalent to map_subset2pixel.m.
static std::vector< int > findROICenter(const cv::Mat &roi_mask)
Find center of ROI mask.
static std::vector< int > mapPointCoordinate(const std::vector< int > &point_sw, const cv::Mat &U_mapped, const cv::Mat &V_mapped)
Map point coordinates using displacement fields Equivalent to map_pointcoordinate....
static SeedPoint loadSeedFromMat(const std::string &seed_file)
Load seed point from MAT file.
static std::vector< int > mapPixel2Subset(const std::vector< int > &pixel_coords, int subset_spacing)
Map pixel coordinates to subset coordinates Equivalent to map_pixel2subset.m.
static cv::Mat loadROIFromMat(const std::string &roi_file)
Load ROI mask from MAT file.
static ncorr::ROI2D matToNcorrROI(const cv::Mat &mask)
Convert OpenCV Mat to ncorr ROI2D.
static SeedPoint loadOrCreateSeed(const BaseParameters ¶ms, const cv::Mat &roi_mask)
Load or create seed point If seed file doesn't exist, creates a default seed point at ROI center.
static bool loadMatchingResults(const std::string &matching_file, cv::Mat &refmask_REF, cv::Mat &refmask_trial, cv::Mat &U_mapped, cv::Mat &V_mapped, int subset_spacing)
Load matching results from MAT file Extracts ROI masks and displacement fields from matching file.
static cv::Mat loadOrCreateROI(const BaseParameters ¶ms, const cv::Mat &reference_image)
Load or create ROI mask If ROI file doesn't exist, creates a full-image ROI Equivalent to checking an...
static cv::Mat createFullROI(const cv::Size &image_size)
Create default ROI mask (full image)
static cv::Mat ncorrROIToMat(const ncorr::ROI2D &roi)
Convert ncorr ROI2D to OpenCV Mat.
Lightweight, dependency-free logging facility for CPPxDIC.
DataSerializer - Abstract base class for format-agnostic DIC data I/O.
Base parameters structure Contains fundamental paths and settings for DIC analysis Equivalent to base...
Seed point structure Stores seed points in both pixel world (pw) and subset world (sw) coordinates.