CppNCorr
C++ ncorr Digital Image Correlation engine
Loading...
Searching...
No Matches
session.cpp
Go to the documentation of this file.
1
18#include "ncorr/session.h"
19
20#include "ncorr.h"
21
22#include <opencv2/opencv.hpp>
23
24#include <cmath>
25#include <limits>
26#include <sstream>
27#include <stdexcept>
28
29namespace ncorr {
30
31namespace {
32
33// Wrap a (row-major, interleaved 8-bit) ImageBuffer into an owning cv::Mat. The
34// clone() decouples the cv::Mat from the caller's storage so the session can
35// outlive the original buffer.
36cv::Mat to_owning_mat(const ImageBuffer& b) {
37 return cv::Mat(b.height, b.width, CV_8UC(b.channels), const_cast<std::uint8_t*>(b.data))
38 .clone();
39}
40
41} // namespace
42
43// ---------------------------------------------------------------------------
44// Private implementation (PIMPL). Holds the cached reference Image2D, its
45// geometry, and the optional ROI2D.
46// ---------------------------------------------------------------------------
49
50 bool has_reference = false;
52 int ref_width = 0;
53 int ref_height = 0;
54
55 bool has_roi = false;
57
58 explicit Impl(const SessionConfig& cfg) : config(cfg) {}
59};
60
61NcorrSession::NcorrSession(const SessionConfig& config) : impl_(std::make_unique<Impl>(config)) {}
62
64
65NcorrSession::NcorrSession(NcorrSession&&) noexcept = default;
66NcorrSession& NcorrSession::operator=(NcorrSession&&) noexcept = default;
67
68void NcorrSession::set_reference(const ImageBuffer& ref) {
69 if (!ref.valid()) {
70 throw std::invalid_argument(
71 "NcorrSession::set_reference: invalid ImageBuffer (null data or "
72 "non-positive dimensions).");
73 }
74 impl_->ref_img = Image2D(to_owning_mat(ref));
75 impl_->ref_width = ref.width;
76 impl_->ref_height = ref.height;
77 impl_->has_reference = true;
78 // A new reference invalidates any previously set ROI.
79 impl_->has_roi = false;
80}
81
82void NcorrSession::set_roi(const ImageBuffer& roi_mask) {
83 if (!roi_mask.valid()) {
84 throw std::invalid_argument("NcorrSession::set_roi: invalid ROI mask ImageBuffer.");
85 }
86 if (impl_->has_reference &&
87 (roi_mask.width != impl_->ref_width || roi_mask.height != impl_->ref_height)) {
88 throw std::invalid_argument(
89 "NcorrSession::set_roi: ROI mask geometry does not match the "
90 "reference frame.");
91 }
92 Array2D<double> gs = Image2D(to_owning_mat(roi_mask)).get_gs();
93 impl_->roi = ROI2D(gs > 0.5);
94 impl_->has_roi = true;
95}
96
98 if (!impl_->has_reference) {
99 throw std::logic_error(
100 "NcorrSession::process_frame: no reference frame set; call "
101 "set_reference() first.");
102 }
103
104 DICResult result;
105 result.valid = false;
106
107 if (!def.valid()) {
108 result.message = "process_frame: invalid deformed ImageBuffer.";
109 return result;
110 }
111 if (def.width != impl_->ref_width || def.height != impl_->ref_height) {
112 result.message = "process_frame: deformed frame geometry does not match reference.";
113 return result;
114 }
115
116 try {
117 Image2D def_img(to_owning_mat(def));
118
119 ROI2D roi = impl_->has_roi
120 ? impl_->roi
121 : ROI2D(Array2D<bool>(impl_->ref_height, impl_->ref_width, true));
122
123 std::vector<Image2D> imgs{impl_->ref_img, def_img};
124
125 DIC_analysis_input in(imgs, roi, impl_->config.scalefactor,
127 impl_->config.subregion_radius, impl_->config.num_threads,
128 DIC_analysis_config::NO_UPDATE, impl_->config.debug);
129
131 if (out.disps.empty()) {
132 result.message = "process_frame: DIC produced no displacement fields.";
133 return result;
134 }
135
136 const Disp2D& disp = out.disps.front();
137 const Array2D<double>& u_arr = disp.get_u().get_array();
138 const Array2D<double>& v_arr = disp.get_v().get_array();
139 const Array2D<double>& cc_arr = disp.get_cc().get_array();
140 const Array2D<bool>& mask = disp.get_roi().get_mask();
141
142 const int h = u_arr.height();
143 const int w = u_arr.width();
144 result.width = w;
145 result.height = h;
146
147 const double nan = std::numeric_limits<double>::quiet_NaN();
148 const std::size_t n = static_cast<std::size_t>(w) * h;
149 result.u.assign(n, nan);
150 result.v.assign(n, nan);
151 result.corrcoef.assign(n, nan);
152
153 for (int i = 0; i < h; ++i) {
154 for (int j = 0; j < w; ++j) {
155 if (i < mask.height() && j < mask.width() && mask(i, j)) {
156 const std::size_t idx = static_cast<std::size_t>(i) * w + j;
157 if (i < u_arr.height() && j < u_arr.width()) result.u[idx] = u_arr(i, j);
158 if (i < v_arr.height() && j < v_arr.width()) result.v[idx] = v_arr(i, j);
159 if (i < cc_arr.height() && j < cc_arr.width())
160 result.corrcoef[idx] = cc_arr(i, j);
161 }
162 }
163 }
164
165 result.valid = true;
166 result.message.clear();
167 return result;
168 } catch (const std::exception& e) {
169 result.valid = false;
170 result.message = std::string("process_frame: DIC failed: ") + e.what();
171 return result;
172 }
173}
174
176 return impl_->has_reference;
177}
178
179} // namespace ncorr
difference_type width() const
Definition Array2D.h:410
difference_type height() const
Definition Array2D.h:409
const Array2D< double > & get_array() const
Definition Data2D.h:64
const Data2D & get_u() const
Definition Disp2D.h:65
const ROI2D & get_roi() const
Definition Disp2D.h:67
const Data2D & get_v() const
Definition Disp2D.h:64
const Data2D & get_cc() const
Definition Disp2D.h:66
Array2D< double > get_gs() const
Definition Image2D.cpp:134
Drives an in-memory Digital Image Correlation session.
Definition session.h:138
void set_roi(const ImageBuffer &roi_mask)
Optionally supply a region-of-interest mask.
Definition session.cpp:82
~NcorrSession()
Destructor (defined in session.cpp because of the PIMPL).
bool has_reference() const
Definition session.cpp:175
DICResult process_frame(const ImageBuffer &def)
Push a deformed frame and run DIC against the reference.
Definition session.cpp:97
NcorrSession(const SessionConfig &config=SessionConfig())
Construct a session with the given configuration.
Definition session.cpp:61
const Array2D< bool > & get_mask() const
Definition ROI2D.h:81
@ QUINTIC_BSPLINE_PRECOMPUTE
DIC_analysis_output DIC_analysis(const DIC_analysis_input &)
Definition ncorr.cpp:2718
In-memory DIC session API for CppNCorr.
Result of running DIC on a single deformed frame.
Definition session.h:84
int height
Height of the displacement fields, in reduced-grid samples.
Definition session.h:88
std::vector< double > v
Vertical Lagrangian displacement (v), pixels, row-major. NaN outside ROI.
Definition session.h:92
bool valid
True if the frame was processed successfully.
Definition session.h:96
int width
Width of the displacement fields, in reduced-grid samples.
Definition session.h:86
std::vector< double > u
Horizontal Lagrangian displacement (u), pixels, row-major. NaN outside ROI.
Definition session.h:90
std::vector< double > corrcoef
Per-point correlation coefficient, row-major, size width*height. NaN outside ROI.
Definition session.h:94
std::string message
Human-readable status / error message (empty on success).
Definition session.h:98
std::vector< Disp2D > disps
Definition ncorr.h:274
Thin, non-owning view over a raw image in memory.
Definition session.h:40
int width
Image width in pixels.
Definition session.h:44
int height
Image height in pixels.
Definition session.h:46
bool valid() const
Definition session.h:64
Impl(const SessionConfig &cfg)
Definition session.cpp:58
Configuration for an in-memory DIC session.
Definition session.h:107