31TEST_CASE(
"Recover Gaussian displacement and centroid",
"[improc::imageXCorrDiscrete]" )
33 GIVEN(
"two Gaussians" )
35 WHEN(
"the target is shifted from a centered reference" )
48 REQUIRE( xcf.
refIm( refIm ) == 0 );
49 xcf.m_peakMethod = mx::improc::xcorrPeakMethod::centroid;
51 REQUIRE( xcf( x, y, im2 ) == 0 );
55 xcf.
ccIm().maxCoeff( &xPeak, &yPeak );
56 REQUIRE( xPeak == 9 );
57 REQUIRE( yPeak == 9 );
58 REQUIRE_THAT( x, Catch::Matchers::WithinAbs( 4, 1e-8 ) );
59 REQUIRE_THAT( y, Catch::Matchers::WithinAbs( 4, 1e-8 ) );
60 REQUIRE( std::isfinite( x ) );
61 REQUIRE( std::isfinite( y ) );
64 WHEN(
"the target has an asymmetric signed shift" )
69 centered.data(), centered.rows(), centered.cols(), 0., 1.0, 31.5, 31.5, 2 );
71 shifted.data(), shifted.rows(), shifted.cols(), 0., 1.0, 35.5, 28.5, 2 );
75 REQUIRE( xcf.
refIm( reference ) == 0 );
76 xcf.m_peakMethod = mx::improc::xcorrPeakMethod::centroid;
80 REQUIRE( xcf( x, y, shifted ) == 0 );
84 xcf.
ccIm().maxCoeff( &xPeak, &yPeak );
85 REQUIRE( xPeak == 9 );
86 REQUIRE( yPeak == 2 );
87 REQUIRE_THAT( x, Catch::Matchers::WithinAbs( 4, 1e-8 ) );
88 REQUIRE_THAT( y, Catch::Matchers::WithinAbs( -3, 1e-8 ) );
89 REQUIRE( std::isfinite( x ) );
90 REQUIRE( std::isfinite( y ) );
93 WHEN(
"the target has zero shift" )
97 target.data(), target.rows(), target.cols(), 0., 1.0, 31.5, 31.5, 2 );
101 REQUIRE( xcf.
refIm( reference ) == 0 );
102 xcf.m_peakMethod = mx::improc::xcorrPeakMethod::centroid;
106 REQUIRE( xcf( x, y, target ) == 0 );
110 xcf.
ccIm().maxCoeff( &xPeak, &yPeak );
111 REQUIRE( xPeak == 5 );
112 REQUIRE( yPeak == 5 );
113 REQUIRE_THAT( x, Catch::Matchers::WithinAbs( 0, 1e-8 ) );
114 REQUIRE_THAT( y, Catch::Matchers::WithinAbs( 0, 1e-8 ) );
115 REQUIRE( std::isfinite( x ) );
116 REQUIRE( std::isfinite( y ) );
118 WHEN(
"geometric quarter" )
128 REQUIRE_THAT( x, Catch::Matchers::WithinAbs( 15.5, 1e-8 ) );
129 REQUIRE_THAT( y, Catch::Matchers::WithinAbs( 15.5, 1e-8 ) );
132 WHEN(
"automatic lags span only valid target blocks" )
136 target.data(), target.rows(), target.cols(), 0., 1.0, 4.0, 4.5, 1.5 );
140 REQUIRE( xcf.
refIm( reference ) == 0 );
143 REQUIRE( xcf( x, y, target ) == 0 );
144 REQUIRE( xcf.
ccIm().rows() == 5 );
145 REQUIRE( xcf.
ccIm().cols() == 5 );
148 xcf.
ccIm().maxCoeff( &xPeak, &yPeak );
149 REQUIRE( xPeak == 2 );
150 REQUIRE( yPeak == 2 );
151 REQUIRE( std::isfinite( x ) );
152 REQUIRE( std::isfinite( y ) );
155 WHEN(
"interpolation uses the lag range allowed by the image dimensions" )
160 centered.data(), centered.rows(), centered.cols(), 0., 1.0, 31.5, 31.5, 2 );
162 shifted.data(), shifted.rows(), shifted.cols(), 0., 1.0, 32.5, 31.5, 2 );
166 REQUIRE( xcf.
refIm( reference ) == 0 );
167 xcf.m_peakMethod = mx::improc::xcorrPeakMethod::interp;
171 REQUIRE( xcf( x, y, shifted ) == 0 );
172 REQUIRE( xcf.
ccIm().rows() == 5 );
173 REQUIRE( xcf.
ccIm().cols() == 5 );
174 REQUIRE( xcf.
magIm().rows() == 41 );
175 REQUIRE( xcf.
magIm().cols() == 41 );
176 REQUIRE_THAT( x, Catch::Matchers::WithinAbs( 1, 0.11 ) );
177 REQUIRE_THAT( y, Catch::Matchers::WithinAbs( 0, 0.11 ) );
178 REQUIRE( std::isfinite( x ) );
179 REQUIRE( std::isfinite( y ) );
182 WHEN(
"interpolation falls back safely for a three-sample lag range" )
187 centered.data(), centered.rows(), centered.cols(), 0., 1.0, 31.5, 31.5, 2 );
189 shifted.data(), shifted.rows(), shifted.cols(), 0., 1.0, 32.5, 31.5, 2 );
193 REQUIRE( xcf.
refIm( reference ) == 0 );
194 xcf.m_peakMethod = mx::improc::xcorrPeakMethod::interp;
198 REQUIRE( xcf( x, y, centered ) == 0 );
199 REQUIRE( xcf.
ccIm().rows() == 3 );
200 REQUIRE( xcf.
ccIm().cols() == 3 );
201 REQUIRE( xcf.
magIm().size() == 0 );
202 REQUIRE_THAT( x, Catch::Matchers::WithinAbs( 0, 1e-8 ) );
203 REQUIRE_THAT( y, Catch::Matchers::WithinAbs( 0, 1e-8 ) );
205 REQUIRE( xcf( x, y, shifted ) == 0 );
206 REQUIRE( xcf.
magIm().size() == 0 );
207 REQUIRE_THAT( x, Catch::Matchers::WithinAbs( 1, 1e-8 ) );
208 REQUIRE_THAT( y, Catch::Matchers::WithinAbs( 0, 1e-8 ) );
209 REQUIRE( std::isfinite( x ) );
210 REQUIRE( std::isfinite( y ) );
213 WHEN(
"interpolation falls back safely for a boundary correlation peak" )
219 centered.data(), centered.rows(), centered.cols(), 0., 1.0, 31.5, 31.5, 2 );
221 shiftedNegative.rows(),
222 shiftedNegative.cols(),
229 shiftedPositive.rows(),
230 shiftedPositive.cols(),
239 REQUIRE( xcf.
refIm( reference ) == 0 );
240 xcf.m_peakMethod = mx::improc::xcorrPeakMethod::interp;
244 REQUIRE( xcf( x, y, shiftedNegative ) == 0 );
245 REQUIRE( xcf.
ccIm().rows() == 5 );
246 REQUIRE( xcf.
ccIm().cols() == 5 );
247 REQUIRE( xcf.
magIm().size() == 0 );
248 REQUIRE_THAT( x, Catch::Matchers::WithinAbs( -2, 1e-8 ) );
249 REQUIRE_THAT( y, Catch::Matchers::WithinAbs( 0, 1e-8 ) );
251 REQUIRE( xcf( x, y, shiftedPositive ) == 0 );
252 REQUIRE( xcf.
magIm().size() == 0 );
253 REQUIRE_THAT( x, Catch::Matchers::WithinAbs( 2, 1e-8 ) );
254 REQUIRE_THAT( y, Catch::Matchers::WithinAbs( 0, 1e-8 ) );
255 REQUIRE( std::isfinite( x ) );
256 REQUIRE( std::isfinite( y ) );
259 WHEN(
"interpolation falls back safely for a negative correlation surface" )
263 for(
int row = 0; row < target.rows(); ++row )
265 for(
int col = 0; col < target.cols(); ++col )
267 target( row, col ) = row + 0.2 * col + 1.2 * std::sin( row + 0.3 * col );
270 for(
int row = 0; row < reference.rows(); ++row )
272 for(
int col = 0; col < reference.cols(); ++col )
274 reference( row, col ) = -( row + 0.2 * col );
279 REQUIRE( xcf.
refIm( reference ) == 0 );
280 xcf.m_peakMethod = mx::improc::xcorrPeakMethod::interp;
284 REQUIRE( xcf( x, y, target ) == 0 );
285 REQUIRE( xcf.
ccIm().rows() == 5 );
286 REQUIRE( xcf.
ccIm().cols() == 5 );
290 REQUIRE( xcf.
ccIm().maxCoeff( &xPeak, &yPeak ) < 0 );
291 REQUIRE( xPeak == 1 );
292 REQUIRE( yPeak == 3 );
293 REQUIRE( xcf.
magIm().size() == 0 );
294 REQUIRE_THAT( x, Catch::Matchers::WithinAbs( -1, 1e-8 ) );
295 REQUIRE_THAT( y, Catch::Matchers::WithinAbs( 1, 1e-8 ) );
296 REQUIRE( std::isfinite( x ) );
297 REQUIRE( std::isfinite( y ) );
300 WHEN(
"a mask differs from the reference in exactly one dimension" )
309 REQUIRE( xcf.
maskIm( wrongRows ) == 0 );
310 REQUIRE( xcf.
refIm( reference ) == -1 );
314 REQUIRE( xcf.
maskIm( wrongCols ) == 0 );
315 REQUIRE( xcf.
refIm( reference ) == -1 );