@@ -252,6 +252,81 @@ static void gradientHist(const cv::Mat &src, cv::Mat &magnitude, cv::Mat &histog
252
252
}
253
253
}
254
254
255
+ /* !
256
+ * The class parallelizing the edgenms algorithm.
257
+ *
258
+ * \param E : edge image
259
+ * \param O : orientation image
260
+ * \param dst : destination image
261
+ * \param r : radius for NMS suppression
262
+ * \param s : radius for boundary suppression
263
+ * \param m : multiplier for conservative suppression
264
+ */
265
+ class NmsInvoker : public cv ::ParallelLoopBody
266
+ {
267
+
268
+ private:
269
+ const cv::Mat &E;
270
+ const cv::Mat &O;
271
+ cv::Mat &dst;
272
+ const int r;
273
+ const float m;
274
+
275
+ public:
276
+ NmsInvoker (const cv::Mat &_E, const cv::Mat &_O, cv::Mat &_dst, const int _r, const float _m)
277
+ : E(_E), O(_O), dst(_dst), r(_r), m(_m)
278
+ {
279
+ }
280
+
281
+ void operator ()(const cv::Range &range) const
282
+ {
283
+ for (int x = range.start ; x < range.end ; x++)
284
+ {
285
+ const float *e_ptr = E.ptr <float >(x);
286
+ const float *o_ptr = O.ptr <float >(x);
287
+ float *dst_ptr = dst.ptr <float >(x);
288
+ for (int y=0 ; y < E.cols ; y++)
289
+ {
290
+ float e = e_ptr[y];
291
+ dst_ptr[y] = e;
292
+ if (!e) continue ;
293
+ e *= m;
294
+ float coso = cos (o_ptr[y]);
295
+ float sino = sin (o_ptr[y]);
296
+ for (int d=-r; d<=r; d++)
297
+ {
298
+ if (d)
299
+ {
300
+ float xdcos = x+d*coso;
301
+ float ydsin = y+d*sino;
302
+ xdcos = xdcos < 0 ? 0 : (xdcos > E.rows - 1 .001f ? E.rows - 1 .001f : xdcos);
303
+ ydsin = ydsin < 0 ? 0 : (ydsin > E.cols - 1 .001f ? E.cols - 1 .001f : ydsin);
304
+ int x0 = (int )xdcos;
305
+ int y0 = (int )ydsin;
306
+ int x1 = x0 + 1 ;
307
+ int y1 = y0 + 1 ;
308
+ float dx0 = xdcos - x0;
309
+ float dy0 = ydsin - y0;
310
+ float dx1 = 1 - dx0;
311
+ float dy1 = 1 - dy0;
312
+ float e0 = E.at <float >(x0, y0) * dx1 * dy1 +
313
+ E.at <float >(x1, y0) * dx0 * dy1 +
314
+ E.at <float >(x0, y1) * dx1 * dy0 +
315
+ E.at <float >(x1, y1) * dx0 * dy0;
316
+
317
+ if (e < e0 )
318
+ {
319
+ dst_ptr[y] = 0 ;
320
+ break ;
321
+ }
322
+ }
323
+ }
324
+
325
+ }
326
+ }
327
+ }
328
+ };
329
+
255
330
/* ******************** RFFeatureGetter class *********************/
256
331
257
332
namespace cv
@@ -442,21 +517,23 @@ class StructuredEdgeDetectionImpl : public StructuredEdgeDetection
442
517
/* !
443
518
* The function detects edges in src and draw them to dst
444
519
*
445
- * \param src : source image (RGB, float, in [0;1]) to detect edges
446
- * \param dst : destination image (grayscale, float, in [0;1])
520
+ * \param _src : source image (RGB, float, in [0;1]) to detect edges
521
+ * \param _dst : destination image (grayscale, float, in [0;1])
447
522
* where edges are drawn
448
523
*/
449
- void detectEdges (const cv::Mat &src , cv::Mat &dst ) const
524
+ void detectEdges (cv::InputArray _src , cv::OutputArray _dst ) const
450
525
{
451
- CV_Assert ( src .type () == CV_32FC3 );
526
+ CV_Assert ( _src .type () == CV_32FC3 );
452
527
453
- dst.create ( src.size (), cv::DataType<float >::type );
528
+ _dst.createSameSize ( _src, cv::DataType<float >::type );
529
+ _dst.setTo (0 );
530
+ Mat dst = _dst.getMat ();
454
531
455
532
int padding = ( __rf.options .patchSize
456
533
- __rf.options .patchInnerSize )/2 ;
457
534
458
535
cv::Mat nSrc;
459
- copyMakeBorder ( src , nSrc, padding, padding,
536
+ copyMakeBorder ( _src , nSrc, padding, padding,
460
537
padding, padding, BORDER_REFLECT );
461
538
462
539
NChannelsMat features;
@@ -469,6 +546,101 @@ class StructuredEdgeDetectionImpl : public StructuredEdgeDetection
469
546
predictEdges ( features, dst );
470
547
}
471
548
549
+ /* !
550
+ * The function computes orientation from edge image.
551
+ *
552
+ * \param src : edge image.
553
+ * \param dst : orientation image.
554
+ * \param r : filter radius.
555
+ */
556
+ void computeOrientation (cv::InputArray _src, cv::OutputArray _dst) const
557
+ {
558
+ CV_Assert ( _src.type () == CV_32FC1 );
559
+
560
+ cv::Mat Oxx, Oxy, Oyy;
561
+
562
+ _dst.createSameSize ( _src, _src.type () );
563
+ _dst.setTo (0 );
564
+
565
+ Mat src = _src.getMat ();
566
+ cv::Mat E_conv = imsmooth (src, __rf.options .gradientNormalizationRadius );
567
+
568
+ Sobel (E_conv, Oxx, -1 , 2 , 0 );
569
+ Sobel (E_conv, Oxy, -1 , 1 , 1 );
570
+ Sobel (E_conv, Oyy, -1 , 0 , 2 );
571
+
572
+ Mat dst = _dst.getMat ();
573
+ float *o = dst.ptr <float >();
574
+ float *oxx = Oxx.ptr <float >();
575
+ float *oxy = Oxy.ptr <float >();
576
+ float *oyy = Oyy.ptr <float >();
577
+ for (int i = 0 ; i < dst.rows * dst.cols ; i++)
578
+ {
579
+ int xysign = -((oxy[i] > 0 ) - (oxy[i] < 0 ));
580
+ o[i] = (atan ((oyy[i] * xysign / (oxx[i] + 1e-5 ))) > 0 ) ? (float ) fmod (
581
+ atan ((oyy[i] * xysign / (oxx[i] + 1e-5 ))), M_PI) : (float ) fmod (
582
+ atan ((oyy[i] * xysign / (oxx[i] + 1e-5 ))) + M_PI, M_PI);
583
+ }
584
+ }
585
+
586
+ /* !
587
+ * The function suppress edges where edge is stronger in orthogonal direction
588
+ * \param edge_image : edge image from detectEdges function.
589
+ * \param orientation_image : orientation image from computeOrientation function.
590
+ * \param _dst : suppressed image (grayscale, float, in [0;1])
591
+ * \param r : radius for NMS suppression.
592
+ * \param s : radius for boundary suppression.
593
+ * \param m : multiplier for conservative suppression.
594
+ * \param isParallel: enables/disables parallel computing.
595
+ */
596
+ void edgesNms (cv::InputArray edge_image, cv::InputArray orientation_image, cv::OutputArray _dst, int r, int s, float m, bool isParallel) const
597
+ {
598
+ CV_Assert (edge_image.type () == CV_32FC1);
599
+ CV_Assert (orientation_image.type () == CV_32FC1);
600
+
601
+ cv::Mat E = edge_image.getMat ();
602
+ cv::Mat O = orientation_image.getMat ();
603
+ cv::Mat E_t = E.t ();
604
+ cv::Mat O_t = O.t ();
605
+
606
+ cv::Mat dst = _dst.getMat ();
607
+ dst.create (E.cols , E.rows , E.type ());
608
+ dst.setTo (0 );
609
+
610
+ cv::Range sizeRange = cv::Range (0 , E_t.rows );
611
+ NmsInvoker body = NmsInvoker (E_t, O_t, dst, r, m);
612
+ if (isParallel)
613
+ {
614
+ cv::parallel_for_ (sizeRange, body);
615
+ } else
616
+ {
617
+ body (sizeRange);
618
+ }
619
+
620
+ s = s > E_t.rows / 2 ? E_t.rows / 2 : s;
621
+ s = s > E_t.cols / 2 ? E_t.cols / 2 : s;
622
+ for (int x=0 ; x<s; x++)
623
+ {
624
+ for (int y=0 ; y<E_t.cols ; y++)
625
+ {
626
+ dst.at <float >(x, y) *= x / (float )s;
627
+ dst.at <float >(E_t.rows -1 -x, y) *= x / (float )s;
628
+ }
629
+ }
630
+
631
+ for (int x=0 ; x < E_t.rows ; x++)
632
+ {
633
+ for (int y=0 ; y < s; y++)
634
+ {
635
+ dst.at <float >(x, y) *= y / (float )s;
636
+ dst.at <float >(x, E_t.cols -1 -y) *= y / (float )s;
637
+ }
638
+ }
639
+ transpose (dst, dst);
640
+ dst.copyTo (_dst);
641
+ }
642
+
643
+
472
644
protected:
473
645
/* !
474
646
* Private method used by process method. The function
0 commit comments