Iteratively open the estimated surface. progressiveFilter can be used to identify both low points and object (i.e., non-ground) points, depending on the inputs.
| 667 | // identify both low points and object (i.e., non-ground) points, depending on |
| 668 | // the inputs. |
| 669 | std::vector<int> SMRFilter::progressiveFilter(std::vector<double> const& ZImin, |
| 670 | double slope, double max_window) |
| 671 | { |
| 672 | // "The maximum window radius is supplied as a distance metric (e.g., 21 m), |
| 673 | // but is internally converted to a pixel equivalent by dividing it by the |
| 674 | // cell size and rounding the result toward positive infinity (i.e., taking |
| 675 | // the ceiling value)." |
| 676 | int max_radius = static_cast<int>(std::ceil(max_window / m_args->m_cell)); |
| 677 | std::vector<double> prevSurface = ZImin; |
| 678 | std::vector<double> erosion = ZImin; |
| 679 | |
| 680 | // "...the radius of the element at each step [is] increased by one pixel |
| 681 | // from a starting value of one pixel to the pixel equivalent of the maximum |
| 682 | // value." |
| 683 | std::vector<int> Obj(m_rows * m_cols, 0); |
| 684 | for (int radius = 1; radius <= max_radius; ++radius) |
| 685 | { |
| 686 | // "On the first iteration, the minimum surface (ZImin) is opened using |
| 687 | // a disk-shaped structuring element with a radius of one pixel." |
| 688 | math::erodeDiamond(erosion, m_rows, m_cols, 1); |
| 689 | std::vector<double> curOpening = erosion; |
| 690 | math::dilateDiamond(curOpening, m_rows, m_cols, radius); |
| 691 | |
| 692 | // "An elevation threshold is then calculated, where the value is equal |
| 693 | // to the supplied slope tolerance parameter multiplied by the product |
| 694 | // of the window radius and the cell size." |
| 695 | double threshold = slope * m_args->m_cell * radius; |
| 696 | |
| 697 | // "This elevation threshold is applied to the difference of the minimum |
| 698 | // and the opened surfaces." |
| 699 | |
| 700 | // Need to provide means of diffing two vectors. |
| 701 | std::vector<double> diff; |
| 702 | std::transform(prevSurface.begin(), prevSurface.end(), |
| 703 | curOpening.begin(), std::back_inserter(diff), |
| 704 | [&](double l, double r) { return std::fabs(l - r); }); |
| 705 | |
| 706 | // "Any grid cell with a difference value exceeding the calculated |
| 707 | // elevation threshold for the iteration is then flagged as an OBJ |
| 708 | // cell." |
| 709 | std::vector<int> foo; |
| 710 | std::transform(diff.begin(), diff.end(), std::back_inserter(foo), |
| 711 | [threshold](double x) { |
| 712 | return (x > threshold) ? int(1) : int(0); |
| 713 | }); |
| 714 | std::transform(Obj.begin(), Obj.end(), foo.begin(), Obj.begin(), |
| 715 | [](int a, int b) { return (std::max)(a, b); }); |
| 716 | |
| 717 | // "The algorithm then proceeds to the next window radius (up to the |
| 718 | // maximum), and proceeds as above with the last opened surface acting |
| 719 | // as the minimum surface for the next difference calculation." |
| 720 | prevSurface = curOpening; |
| 721 | |
| 722 | size_t ng = std::count(Obj.begin(), Obj.end(), 1); |
| 723 | size_t g(Obj.size() - ng); |
| 724 | double p(100.0 * double(ng) / double(Obj.size())); |
| 725 | log()->floatPrecision(2); |
| 726 | log()->get(LogLevel::Debug) << "progressiveFilter: radius = " << radius |
nothing calls this directly
no test coverage detected