@@ -112,16 +112,18 @@ static inline int getGaussianKernelSize(float sigma) {
112
112
/* ************************************************************************* */
113
113
/* *
114
114
* @brief This function computes a scalar non-linear diffusion step
115
- * @param Ld Base image in the evolution
116
- * @param c Conductivity image
115
+ * @param Lt Base image in the evolution
116
+ * @param Lf Conductivity image
117
117
* @param Lstep Output image that gives the difference between the current
118
118
* Ld and the next Ld being evolved
119
+ * @param row_begin row where to start
120
+ * @param row_end last row to fill exclusive. the range is [row_begin, row_end).
119
121
* @note Forward Euler Scheme 3x3 stencil
120
122
* The function c is a scalar value that depends on the gradient norm
121
123
* dL_by_ds = d(c dL_by_dx)_by_dx + d(c dL_by_dy)_by_dy
122
124
*/
123
125
static inline void
124
- nld_step_scalar_one_lane (const cv:: Mat& Lt, const cv:: Mat& Lf, cv:: Mat& Lstep, int idx , int skip )
126
+ nld_step_scalar_one_lane (const Mat& Lt, const Mat& Lf, Mat& Lstep, int row_begin , int row_end )
125
127
{
126
128
CV_INSTRUMENT_REGION ()
127
129
/* The labeling scheme for this five star stencil:
@@ -132,7 +134,7 @@ nld_step_scalar_one_lane(const cv::Mat& Lt, const cv::Mat& Lf, cv::Mat& Lstep, i
132
134
133
135
Lstep.create (Lt.size (), Lt.type ());
134
136
const int cols = Lt.cols - 2 ;
135
- int row = idx ;
137
+ int row = row_begin ;
136
138
137
139
const float *lt_a, *lt_c, *lt_b;
138
140
const float *lf_a, *lf_c, *lf_b;
@@ -151,11 +153,12 @@ nld_step_scalar_one_lane(const cv::Mat& Lt, const cv::Mat& Lf, cv::Mat& Lstep, i
151
153
(lf_c[j] + lf_c[j - 1 ])*(lt_c[j - 1 ] - lt_c[j]) +
152
154
(lf_c[j] + lf_b[j ])*(lt_b[j ] - lt_c[j]);
153
155
}
154
- row += skip ;
156
+ ++row ;
155
157
}
156
158
157
159
// Process the middle rows
158
- for (; row < Lt.rows - 1 ; row += skip)
160
+ int middle_end = std::min (Lt.rows - 1 , row_end);
161
+ for (; row < middle_end; ++row)
159
162
{
160
163
lt_a = Lt.ptr <float >(row - 1 );
161
164
lf_a = Lf.ptr <float >(row - 1 );
@@ -189,8 +192,8 @@ nld_step_scalar_one_lane(const cv::Mat& Lt, const cv::Mat& Lf, cv::Mat& Lstep, i
189
192
(lf_c[cols] + lf_a[cols ])*(lt_a[cols ] - lt_c[cols]);
190
193
}
191
194
192
- // Process the bottom row
193
- if (row == Lt.rows - 1 ) {
195
+ // Process the bottom row (row == Lt.rows - 1)
196
+ if (row_end == Lt.rows ) {
194
197
lt_a = Lt.ptr <float >(row - 1 ) + 1 ; /* Skip the left-most column by +1 */
195
198
lf_a = Lf.ptr <float >(row - 1 ) + 1 ;
196
199
lt_c = Lt.ptr <float >(row ) + 1 ;
@@ -205,6 +208,24 @@ nld_step_scalar_one_lane(const cv::Mat& Lt, const cv::Mat& Lf, cv::Mat& Lstep, i
205
208
}
206
209
}
207
210
211
+ class NonLinearScalarDiffusionStep : public ParallelLoopBody
212
+ {
213
+ public:
214
+ NonLinearScalarDiffusionStep (const Mat& Lt, const Mat& Lf, Mat& Lstep)
215
+ : Lt_(&Lt), Lf_(&Lf), Lstep_(&Lstep)
216
+ {}
217
+
218
+ void operator ()(const Range& range) const
219
+ {
220
+ nld_step_scalar_one_lane (*Lt_, *Lf_, *Lstep_, range.start , range.end );
221
+ }
222
+
223
+ private:
224
+ const Mat* Lt_;
225
+ const Mat* Lf_;
226
+ Mat* Lstep_;
227
+ };
228
+
208
229
/* *
209
230
* @brief This method creates the nonlinear scale space for a given image
210
231
* @param img Input image for which the nonlinear scale space needs to be created
@@ -288,7 +309,9 @@ int AKAZEFeatures::Create_Nonlinear_Scale_Space(const Mat& img)
288
309
// Perform Fast Explicit Diffusion on Lt
289
310
std::vector<float > &tsteps = tsteps_[i - 1 ];
290
311
for (size_t j = 0 ; j < tsteps.size (); j++) {
291
- nld_step_scalar_one_lane (e.Lt , Lflow, Lstep, 0 , 1 );
312
+ // Lstep must be preallocated before this parallel loop
313
+ parallel_for_ (Range (0 , e.Lt .rows ), NonLinearScalarDiffusionStep (e.Lt , Lflow, Lstep),
314
+ (double )e.Lt .total ()/(1 << 16 ));
292
315
const float step_size = tsteps[j];
293
316
e.Lt += Lstep * (0 .5f * step_size);
294
317
}
0 commit comments