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