@@ -233,6 +233,65 @@ class NonLinearScalarDiffusionStep : public ParallelLoopBody
233
233
float step_size_;
234
234
};
235
235
236
+ /* *
237
+ * @brief This function computes a good empirical value for the k contrast factor
238
+ * given two gradient images, the percentile (0-1), the temporal storage to hold
239
+ * gradient norms and the histogram bins
240
+ * @param Lx Horizontal gradient of the input image
241
+ * @param Ly Vertical gradient of the input image
242
+ * @param nbins Number of histogram bins
243
+ * @return k contrast factor
244
+ */
245
+ static inline float
246
+ compute_kcontrast (const cv::Mat& Lx, const cv::Mat& Ly, float perc, int nbins)
247
+ {
248
+ CV_INSTRUMENT_REGION ()
249
+
250
+ CV_Assert (nbins > 2 );
251
+ CV_Assert (!Lx.empty ());
252
+
253
+ // temporary square roots of dot product
254
+ Mat modgs (Lx.rows - 2 , Lx.cols - 2 , CV_32F);
255
+ const int total = modgs.cols * modgs.rows ;
256
+ float *modg = modgs.ptr <float >();
257
+
258
+ for (int i = 1 ; i < Lx.rows - 1 ; i++) {
259
+ const float *lx = Lx.ptr <float >(i) + 1 ;
260
+ const float *ly = Ly.ptr <float >(i) + 1 ;
261
+ const int cols = Lx.cols - 2 ;
262
+
263
+ for (int j = 0 ; j < cols; j++)
264
+ *modg++ = sqrtf (lx[j] * lx[j] + ly[j] * ly[j]);
265
+ }
266
+ modg = modgs.ptr <float >();
267
+
268
+ // Get the maximum
269
+ float hmax = *std::max_element (modg, modg + total);
270
+
271
+ if (hmax == 0 .0f )
272
+ return 0 .03f ; // e.g. a blank image
273
+
274
+ // Compute the bin numbers: the value range [0, hmax] -> [0, nbins-1]
275
+ modgs *= (nbins - 1 ) / hmax;
276
+
277
+ // Count up histogram
278
+ std::vector<int > hist (nbins, 0 );
279
+ for (int i = 0 ; i < total; i++)
280
+ hist[(int )modg[i]]++;
281
+
282
+ // Now find the perc of the histogram percentile
283
+ const int nthreshold = (int )((total - hist[0 ]) * perc); // Exclude hist[0] as background
284
+ int nelements = 0 ;
285
+ for (int k = 1 ; k < nbins; k++) {
286
+ if (nelements >= nthreshold)
287
+ return (float )hmax * k / nbins;
288
+
289
+ nelements += hist[k];
290
+ }
291
+
292
+ return 0 .03f ;
293
+ }
294
+
236
295
/* *
237
296
* @brief This method creates the nonlinear scale space for a given image
238
297
* @param img Input image for which the nonlinear scale space needs to be created
@@ -253,21 +312,15 @@ int AKAZEFeatures::Create_Nonlinear_Scale_Space(const Mat& img)
253
312
return 0 ;
254
313
}
255
314
256
- // First compute the kcontrast factor
257
- float kcontrast = compute_k_percentile (img, options_.kcontrast_percentile , 1 .0f , options_.kcontrast_nbins , 0 , 0 );
258
-
259
- // temporaries for diffusity computation, to reuse the same memory to improve locality
260
- Size base_size = evolution_[0 ].Lt .size ();
261
- // buffers
262
- Mat Lx_buf (base_size, CV_32F);
263
- Mat Ly_buf (base_size, CV_32F);
264
- Mat Lflow_buf (base_size, CV_32F);
265
- Mat Lstep_buf (base_size, CV_32F);
266
- // views pointing to buffers
267
- Mat Lx (base_size, CV_32F, Lx_buf.data );
268
- Mat Ly (base_size, CV_32F, Ly_buf.data );
269
- Mat Lflow (base_size, CV_32F, Lflow_buf.data );
270
- Mat Lstep (base_size, CV_32F, Lstep_buf.data );
315
+ // derivatives, flow and diffusion step
316
+ Mat Lx, Ly, Lflow, Lstep;
317
+
318
+ // compute derivatives for computing k contrast, reuse Lflow for gaussian
319
+ GaussianBlur (img, Lflow, Size (5 , 5 ), 1 .0f , 1 .0f , BORDER_REPLICATE);
320
+ Scharr (Lflow, Lx, CV_32F, 1 , 0 , 1 , 0 , cv::BORDER_DEFAULT);
321
+ Scharr (Lflow, Ly, CV_32F, 0 , 1 , 1 , 0 , cv::BORDER_DEFAULT);
322
+ // compute the kcontrast factor
323
+ float kcontrast = compute_kcontrast (Lx, Ly, options_.kcontrast_percentile , options_.kcontrast_nbins );
271
324
272
325
// Now generate the rest of evolution levels
273
326
for (size_t i = 1 ; i < evolution_.size (); i++) {
@@ -277,12 +330,6 @@ int AKAZEFeatures::Create_Nonlinear_Scale_Space(const Mat& img)
277
330
// new octave will be half the size
278
331
resize (evolution_[i - 1 ].Lt , e.Lt , e.size , 0 , 0 , INTER_AREA);
279
332
kcontrast *= 0 .75f ;
280
-
281
- // resize temporary views to buffers to prevent reallocation
282
- Lx = Mat (e.size , CV_32F, Lx_buf.data );
283
- Ly = Mat (e.size , CV_32F, Ly_buf.data );
284
- Lflow = Mat (e.size , CV_32F, Lflow_buf.data );
285
- Lstep = Mat (e.size , CV_32F, Lstep_buf.data );
286
333
}
287
334
else {
288
335
evolution_[i - 1 ].Lt .copyTo (e.Lt );
@@ -317,6 +364,7 @@ int AKAZEFeatures::Create_Nonlinear_Scale_Space(const Mat& img)
317
364
std::vector<float > &tsteps = tsteps_[i - 1 ];
318
365
for (size_t j = 0 ; j < tsteps.size (); j++) {
319
366
// Lstep must be preallocated before this parallel loop
367
+ Lstep.create (e.Lt .size (), e.Lt .type ());
320
368
const float step_size = tsteps[j] * 0 .5f ;
321
369
parallel_for_ (Range (0 , e.Lt .rows ), NonLinearScalarDiffusionStep (e.Lt , Lflow, Lstep, step_size));
322
370
e.Lt += Lstep;
0 commit comments