22 #ifndef CRNGradientShapeContext_H
23 #define CRNGradientShapeContext_H
45 static constexpr
auto size = ngrad * ntheta * nrho;
53 SC(
const SC&) =
default;
63 static double Distance(
const std::vector<SC> &img1,
const std::vector<SC> &img2);
66 template<
typename Sc>
static int dist(
const Sc &p1,
const Sc &p2);
69 template<
size_t ngrad,
size_t ntheta,
size_t nrho>
73 auto pts = std::vector<Point2DInt>{};
76 pts.emplace_back(
int(x),
int(y));
77 auto distmat = std::vector<std::vector<double>>(pts.size(), std::vector<double>(pts.size(), 0));
78 for (
auto p1 :
Range(pts))
79 for (
auto p2 = p1 + 1; p2 < pts.size(); ++p2)
80 distmat[p1][p2] = distmat[p2][p1] = sqrt(
Sqr(pts[p1].X - pts[p2].X) +
Sqr(pts[p1].Y - pts[p2].Y));
82 auto meds = std::vector<size_t>{};
83 if (pts.size() <= npoints)
85 meds.reserve(pts.size());
86 std::iota(meds.begin(), meds.end(), 0);
92 auto res = std::vector<SC>{};
93 for (
auto tp :
Range(meds))
95 const auto p = meds[tp];
96 auto refp =
SC{pts[p]};
97 const auto maxdist = log(1 + *std::max_element(distmat[p].begin(), distmat[p].end())) + 1;
98 for (
auto p2 :
Range(pts))
102 const auto &op = pts[p2];
104 const auto r = size_t(log(1 + vec.rho) * nrho / maxdist);
105 const auto t = size_t(vec.theta.value * ntheta / 256);
106 refp.histo[r * roffset + t * toffset + igr.
At(op.X, op.Y).theta.value * ngrad / 256] += 1;
109 for (
auto &g : refp.histo)
111 g = (g * 1000) /
int(pts.size());
114 res.push_back(std::move(refp));
117 res.insert(res.end(), ndummy,
SC{});
121 template<
size_t ngrad,
size_t ntheta,
size_t nrho>
124 auto npoints = size_t(0);
125 for (
auto tmp :
Range(igr))
128 return CreateFixed(igr,
crn::Max(
size_t(1), npoints / divisor), ndummy);
131 template<
size_t ngrad,
size_t ntheta,
size_t nrho>
134 const auto s =
Max(img1.size(), img2.size());
135 auto distmat = std::vector<std::vector<double>>(s, std::vector<double>(s, 0));
136 for (
auto p1 :
Range(img1))
137 for (
auto p2 :
Range(img2))
138 distmat[p1][p2] = dist(img1[p1], img2[p2]);
139 return std::get<0>(
Hungarian(distmat)) /
double(
Min(img1.size(), img2.size()));
142 template<
size_t ngrad,
size_t ntheta,
size_t nrho>
145 if (p1.X == 0 && p1.Y == 0)
147 if (p2.X == 0 && p2.Y == 0)
150 for (
auto tmp :
Range(p1.histo))
151 diff +=
Abs(p1.histo[tmp] - p2.histo[tmp]);
ScalarRange< T > Range(T b, T e)
Creates a range [[b, e[[.
static constexpr auto roffset
std::vector< pixel_type >::reference At(size_t x, size_t y) noexcept
Returns a reference to a pixel.
const T & Max(const T &a, const T &b)
Returns the max of two values.
#define FOREACHPIXEL(x, y, img)
Convenience macro to sweep an image.
static constexpr auto toffset
static std::vector< SC > CreateFixed(const ImageGradient &igr, size_t npoints, size_t ndummy)
Finds the k most central elements.
static std::vector< SC > CreateRatio(const ImageGradient &igr, size_t divisor, size_t ndummy)
static double Distance(const std::vector< SC > &img1, const std::vector< SC > &img2)
SC & operator=(const SC &)=default
constexpr SumType< T > Sqr(const T &v) noexcept(noexcept(v *v))
Returns the square of a value.
static constexpr auto size
Gradient image in polar form.
bool IsSignificant(size_t i) const
Tests if a pixel has a significant gradient.
std::tuple< double, std::vector< std::pair< size_t, size_t > > > Hungarian(const std::vector< std::vector< double >> &distmat)
void Abs(Image< T > &img, typename std::enable_if< std::is_arithmetic< T >::value >::type *dummy=nullptr) noexcept
Replaces each pixel by its absolute value.
const T & Min(const T &a, const T &b)
Returns the min of two values.
Gets the element with the lower distance to other elements in the cluster.
std::tuple< std::vector< size_t >, std::vector< std::multimap< double, size_t > >, std::vector< size_t > > Run(Init init, Update update, const std::vector< std::vector< double >> &distmat, size_t maxiter=std::numeric_limits< size_t >::max())
k medoids
std::array< int, size > histo
Gradient shape context factory.