@@ -40,7 +40,7 @@ namespace banana {
40
40
std::ostream& operator << (std::ostream& o, AnnotatedAnalysisResult const & analysis_result) {
41
41
o << " found " << analysis_result.banana .size () << " banana(s) in the picture" << std::endl;
42
42
for (auto const & [n, banana] : std::ranges::enumerate_view (analysis_result.banana )) {
43
- auto const & [coeff_0, coeff_1, coeff_2] = banana.center_line_coefficients ;
43
+ auto const & [coeff_0, coeff_1, coeff_2] = banana.center_line . coefficients ;
44
44
o << " Banana #" << n << " :" << std::endl;
45
45
o << " " << std::format (" y = {} + {} * x + {} * x^2" , coeff_0, coeff_1, coeff_2) << std::endl;
46
46
o << " Rotation = " << (banana.rotation_angle * 180 / std::numbers::pi ) << " degrees" << std::endl;
@@ -129,15 +129,31 @@ namespace banana {
129
129
return contours;
130
130
}
131
131
132
- auto Analyzer::GetBananaCenterLineCoefficients (Contour const & banana_contour, PCAResult const & pca_result) const -> std::expected<std::tuple<double, double, double>, AnalysisError> {
133
- // rotate the contour so that it's horizontal
134
- auto const rotated_contour = this ->RotateContour (banana_contour, pca_result.center , pca_result.angle );
135
-
132
+ auto Analyzer::GetBananaCenterLineCoefficients (Contour const & rotated_banana_contour) const -> std::expected<Polynomial2DCoefficients, AnalysisError> {
136
133
auto const to_std_pair_fn = [](auto const & p) -> std::pair<double , double > { return {p.x , p.y }; };
137
- auto const coeffs = polyfit::Fit2DPolynomial (rotated_contour | std::views::transform (to_std_pair_fn));
134
+ auto const coeffs = polyfit::Fit2DPolynomial (rotated_banana_contour | std::views::transform (to_std_pair_fn));
138
135
return coeffs.transform_error ([](auto const & _) -> auto {return AnalysisError::kPolynomialCalcFailure ;});
139
136
}
140
137
138
+ auto Analyzer::GetBananaCenterLine (Contour const & rotated_banana_contour, Polynomial2DCoefficients const & coefficients) const -> std::vector<cv::Point2d> {
139
+ // note that the coefficients for the center line are given in relation to the bananas main axis.
140
+ // accordingly we have to rotate the resulting line to plot it over the banana in the image.
141
+
142
+ auto const & [coeff_0, coeff_1, coeff_2] = coefficients;
143
+
144
+ auto const minmax_x = std::ranges::minmax (rotated_banana_contour | std::views::transform (&cv::Point ::x));
145
+
146
+ // / Calculate a Point2d for the [x,y] coords based on the provided polynomial and x-values.
147
+ auto const calc_xy = [&coeff_0, &coeff_1, &coeff_2](auto const && x) -> cv::Point2d {
148
+ auto const y = coeff_0 + coeff_1 * x + coeff_2 * x * x;
149
+ return {static_cast <double >(x), y};
150
+ };
151
+
152
+ return std::views::iota (minmax_x.min , minmax_x.max )
153
+ | std::views::transform (calc_xy)
154
+ | std::ranges::to<std::vector>();
155
+ }
156
+
141
157
auto Analyzer::RotateContour (Contour const & contour, cv::Point const & center, double const angle) const -> Contour {
142
158
auto const rotation_matrix = cv::getRotationMatrix2D (center, angle * 180 / std::numbers::pi , 1 );
143
159
Contour rotated_contour{contour.size ()};
@@ -181,42 +197,33 @@ namespace banana {
181
197
182
198
auto Analyzer::AnalyzeBanana (cv::Mat const & image, Contour const & banana_contour) const -> std::expected<AnalysisResult, AnalysisError> {
183
199
auto const pca = this ->GetPCA (banana_contour);
184
- auto const coeffs = this ->GetBananaCenterLineCoefficients (banana_contour, pca);
200
+
201
+ // rotate the contour so that it's horizontal
202
+ auto const rotated_contour = this ->RotateContour (banana_contour, pca.center , pca.angle );
203
+
204
+ auto const coeffs = this ->GetBananaCenterLineCoefficients (rotated_contour);
185
205
if (!coeffs) {
186
206
return std::unexpected{coeffs.error ()};
187
207
}
188
208
209
+ auto const center_line_points_in_banana_coordsys = this ->GetBananaCenterLine (rotated_contour, *coeffs);
210
+
189
211
return AnalysisResult{
190
212
.contour = banana_contour,
191
- .center_line_coefficients = *coeffs,
213
+ .center_line {
214
+ .coefficients = *coeffs,
215
+ .points_in_banana_coordsys = center_line_points_in_banana_coordsys,
216
+ },
192
217
.rotation_angle = pca.angle ,
193
218
.estimated_center = pca.center ,
194
219
};
195
220
}
196
221
197
222
void Analyzer::PlotCenterLine (cv::Mat& draw_target, AnalysisResult const & result) const {
198
- // note that the coefficients for the center line are given in relation to the bananas main axis.
199
- // accordingly we have to rotate the resulting line to plot it over the banana in the image.
200
-
201
- // rotate the contour so that it's horizontal (needed to calculate the x-axis points for plotting in the coordinate system of the banana).
202
- auto const rotated_contour = this ->RotateContour (result.contour , result.estimated_center , result.rotation_angle );
203
-
204
- auto const & [coeff_0, coeff_1, coeff_2] = result.center_line_coefficients ;
205
-
206
- auto const minmax_x = std::ranges::minmax (rotated_contour | std::views::transform (&cv::Point ::x));
207
-
208
- // / Calculate a Point2d for the [x,y] coords based on the provided polynomial and x-values.
209
- auto const calc_xy = [&coeff_0, &coeff_1, &coeff_2](auto const && x) -> cv::Point2d {
210
- auto const y = coeff_0 + coeff_1 * x + coeff_2 * x * x;
211
- return {static_cast <double >(x), y};
212
- };
213
- auto const to_point2i = [](auto const && p) -> cv::Point {return {static_cast <int >(p.x ), static_cast <int >(p.y )};};
214
-
215
- auto const line_extension_length = 50 ; // /< amount of pixels by which the line should be extended on either side
216
- auto const start = std::max (minmax_x.min - line_extension_length, 0 );
217
- auto const end = std::min (minmax_x.max + line_extension_length, draw_target.cols );
218
- auto const center_line_points = std::views::iota (start, end) | std::views::transform (calc_xy);
219
- auto const center_line_points2i = center_line_points | std::views::transform (to_point2i) | std::ranges::to<std::vector>();
223
+ auto const to_point2i = [](auto const & p) -> cv::Point {return {static_cast <int >(p.x ), static_cast <int >(p.y )};};
224
+ auto const center_line_points2i = result.center_line .points_in_banana_coordsys
225
+ | std::views::transform (to_point2i)
226
+ | std::ranges::to<std::vector>();
220
227
221
228
// rotate the center line back so that it fits on the image
222
229
auto const rotated_center_line = this ->RotateContour (center_line_points2i, result.estimated_center , -result.rotation_angle );
0 commit comments