27 #include <Eigen/Dense>
28 #include "ndarray/eigen.h"
36 float src_dist, ndarray::Array<float, 1, 1>
const& ref_dist_array,
float max_dist_rad) {
38 std::upper_bound(ref_dist_array.begin(), ref_dist_array.end(), src_dist - max_dist_rad - 1e-16);
40 std::upper_bound(ref_dist_array.begin(), ref_dist_array.end(), src_dist + max_dist_rad + 1e-16);
42 size_t startIdx = itr - ref_dist_array.begin();
43 size_t endIdx = itrEnd - ref_dist_array.begin();
48 ndarray::Array<double, 1, 1>
const& src_ctr, ndarray::Array<double, 2, 1>
const& src_delta_array,
49 ndarray::Array<double, 1, 1>
const& src_dist_array, ndarray::Array<double, 1, 1>
const& ref_ctr,
50 ndarray::Array<double, 1, 1>
const& proj_ref_ctr_delta,
51 ndarray::Array<float, 1, 1>
const& ref_dist_array, ndarray::Array<uint16_t, 1, 1>
const& ref_id_array,
52 ndarray::Array<double, 2, 1>
const& reference_array,
double max_dist_rad,
size_t n_match) {
62 auto src_ctr_eigen = ndarray::asEigenMatrix(src_ctr);
63 double src_delta_ctr_dot = ndarray::asEigenMatrix(src_delta_array[0]).dot(src_ctr_eigen);
65 ndarray::Array<double, 1, 1> proj_src_ctr_delta = copy(src_delta_array[0] - src_delta_ctr_dot * src_ctr);
66 auto proj_src_ctr_delta_eigen = ndarray::asEigenMatrix(proj_src_ctr_delta);
67 double proj_src_ctr_dist_sq = proj_src_ctr_delta_eigen.dot(proj_src_ctr_delta_eigen);
70 auto proj_ref_ctr_delta_eigen = ndarray::asEigenMatrix(proj_ref_ctr_delta);
71 double proj_ref_ctr_dist_sq = proj_ref_ctr_delta_eigen.dot(proj_ref_ctr_delta_eigen);
75 double max_sin_tol = 0.0447;
76 for (
size_t src_idx = 1; src_idx < src_dist_array.size(); src_idx++) {
77 if (n_fail > src_dist_array.size() - (n_match - 1)) {
85 if (candidate_range.first == candidate_range.second) {
92 double src_sin_tol = max_dist_rad / (src_dist_array[src_idx] + max_dist_rad);
98 if (src_sin_tol > max_sin_tol) {
99 src_sin_tol = max_sin_tol;
104 double proj_src_delta_dot = ndarray::asEigenMatrix(src_delta_array[src_idx]).dot(src_ctr_eigen);
106 ndarray::Array<double, 1, 1> proj_src_delta =
107 copy(src_delta_array[src_idx] - proj_src_delta_dot * src_ctr);
108 auto proj_src_delta_eigen = ndarray::asEigenMatrix(proj_src_delta);
109 double geom_dist_src = sqrt(proj_src_delta_eigen.dot(proj_src_delta_eigen) * proj_src_ctr_dist_sq);
112 double cos_theta_src = proj_src_delta_eigen.dot(proj_src_ctr_delta_eigen) / geom_dist_src;
113 Eigen::Vector3d cross_src =
114 proj_src_delta_eigen.head<3>().cross(proj_src_ctr_delta_eigen.head<3>()) / geom_dist_src;
115 double sin_theta_src = cross_src.dot(src_ctr_eigen);
120 check_spoke(cos_theta_src, sin_theta_src, ref_ctr, proj_ref_ctr_delta, proj_ref_ctr_dist_sq,
121 candidate_range, ref_id_array, reference_array, src_sin_tol);
130 if (output_spokes.
size() >= n_match - 2) {
134 return output_spokes;
137 int check_spoke(
double cos_theta_src,
double sin_theta_src, ndarray::Array<double, 1, 1>
const& ref_ctr,
138 ndarray::Array<double, 1, 1>
const& proj_ref_ctr_delta,
double proj_ref_ctr_dist_sq,
140 ndarray::Array<uint16_t, 1, 1>
const& ref_id_array,
141 ndarray::Array<double, 2, 1>
const& reference_array,
double src_sin_tol) {
145 size_t midpoint = (candidate_range.first + candidate_range.second) / 2;
146 for (
size_t idx = 0; idx < candidate_range.second - candidate_range.first; idx++) {
148 midpoint = midpoint + idx;
150 midpoint = midpoint - idx;
153 uint16_t ref_id = ref_id_array[midpoint];
154 ndarray::Array<double, 1, 1> ref_delta = copy(reference_array[ref_id] - ref_ctr);
156 double ref_dot = ndarray::asEigenMatrix(ref_delta).dot(ndarray::asEigenMatrix(ref_ctr));
157 ndarray::Array<double, 1, 1> proj_ref_delta = copy(ref_delta - ref_dot * ref_ctr);
160 auto proj_ref_delta_eigen = ndarray::asEigenMatrix(proj_ref_delta);
161 auto proj_ref_ctr_delta_eigen = ndarray::asEigenMatrix(proj_ref_ctr_delta);
162 double proj_delta_dist_sq = proj_ref_delta_eigen.dot(proj_ref_delta_eigen);
163 double geom_dist_ref = sqrt(proj_ref_ctr_dist_sq * proj_delta_dist_sq);
164 double cos_theta_ref = proj_ref_delta_eigen.dot(proj_ref_ctr_delta_eigen) / geom_dist_ref;
168 double cos_sq_comparison;
169 if (cos_theta_ref * cos_theta_ref < (1 - src_sin_tol * src_sin_tol)) {
170 cos_sq_comparison = (cos_theta_src - cos_theta_ref) * (cos_theta_src - cos_theta_ref) /
171 (1 - cos_theta_ref * cos_theta_ref);
173 cos_sq_comparison = (cos_theta_src - cos_theta_ref) * (cos_theta_src - cos_theta_ref) /
174 (src_sin_tol * src_sin_tol);
179 if (cos_sq_comparison > src_sin_tol * src_sin_tol) {
185 Eigen::Vector3d cross_ref =
186 proj_ref_delta_eigen.head<3>().cross(proj_ref_ctr_delta_eigen.head<3>()) / geom_dist_ref;
187 double sin_theta_ref = cross_ref.dot(ndarray::asEigenMatrix(ref_ctr));
190 double sin_comparison;
191 if (
abs(cos_theta_src) < src_sin_tol) {
192 sin_comparison = (sin_theta_src - sin_theta_ref) / src_sin_tol;
194 sin_comparison = (sin_theta_src - sin_theta_ref) / cos_theta_ref;
198 if (
abs(sin_comparison) < src_sin_tol) {
int check_spoke(double cos_theta_src, double sin_theta_src, ndarray::Array< double, 1, 1 > const &ref_ctr, ndarray::Array< double, 1, 1 > const &proj_ref_ctr_delta, double proj_ref_ctr_dist_sq, std::pair< size_t, size_t > const &candidate_range, ndarray::Array< uint16_t, 1, 1 > const &ref_id_array, ndarray::Array< double, 2, 1 > const &reference_array, double src_sin_tol)
Check the opening angle between the first spoke of our pattern for the source object against the refe...
std::pair< size_t, size_t > find_candidate_reference_pair_range(float src_dist, ndarray::Array< float, 1, 1 > const &ref_dist_array, float max_dist_rad)
Find the range of reference spokes within a spoke distance tolerance of our source spoke.
std::vector< std::pair< size_t, size_t > > create_pattern_spokes(ndarray::Array< double, 1, 1 > const &src_ctr, ndarray::Array< double, 2, 1 > const &src_delta_array, ndarray::Array< double, 1, 1 > const &src_dist_array, ndarray::Array< double, 1, 1 > const &ref_ctr, ndarray::Array< double, 1, 1 > const &proj_ref_ctr_delta, ndarray::Array< float, 1, 1 > const &ref_dist_array, ndarray::Array< uint16_t, 1, 1 > const &ref_id_array, ndarray::Array< double, 2, 1 > const &reference_array, double max_dist_rad, size_t n_match)
Create the individual spokes that make up the pattern now that the shift and rotation are within tole...
Angle abs(Angle const &a)
A base class for image defects.