21#define _USE_MATH_DEFINES
34#include <allheaders.h>
56 static std::mutex atan_table_mutex;
57 static bool atan_table_init =
false;
58 std::lock_guard<std::mutex> guard(atan_table_mutex);
59 if (!atan_table_init) {
64 atan_table_init =
true;
71 return FCOORD(cos_table[theta], sin_table[theta]);
81 std::vector<INT_FEATURE_STRUCT> *bl_features) {
82 std::vector<INT_FEATURE_STRUCT> cn_features;
87 int num_features = fx_info->
NumCN;
88 if (num_features > 0) {
91 if (sample !=
nullptr) {
94 topleft.
x = box.
left();
95 topleft.
y = box.
top();
98 TPOINT original_topleft, original_botright;
102 TBOX(original_topleft.
x, original_botright.
y, original_botright.
x, original_topleft.
y));
132 FCOORD center, second_moments;
134 if (fx_info !=
nullptr) {
146 if (nonlinear_norm) {
147 std::vector<std::vector<int>> x_coords;
148 std::vector<std::vector<int>> y_coords;
157 51.2f / second_moments.
x(), 51.2f / second_moments.
y(), 128.0f,
164static uint8_t NormalizeDirection(uint8_t dir,
const FCOORD &unnormed_pos,
const DENORM &denorm,
165 const DENORM *root_denorm) {
169 unnormed_end += unnormed_pos;
170 FCOORD normed_pos, normed_end;
171 denorm.
NormTransform(root_denorm, unnormed_pos, &normed_pos);
172 denorm.
NormTransform(root_denorm, unnormed_end, &normed_end);
173 normed_end -= normed_pos;
180static FCOORD MeanDirectionVector(
const LLSQ &point_diffs,
const LLSQ &dirs,
const FCOORD &start_pt,
181 const FCOORD &end_pt) {
183 if (dirs.count() > 0) {
187 FCOORD mean_pt = dirs.mean_point();
188 double mean_dir = 0.0;
189 if (dirs.x_variance() <= dirs.y_variance()) {
190 mean_dir = mean_pt.
x();
192 mean_dir = mean_pt.y() + 128;
199 FCOORD feature_dir(end_pt - start_pt);
200 fit_vector = point_diffs.vector_fit();
201 if (fit_vector.x() == 0.0f && fit_vector.y() == 0.0f) {
203 fit_vector = feature_dir;
208 FCOORD fit_vector2 = !fit_vector;
211 if (fit_vector % feature_dir < 0.0) {
212 fit_vector = -fit_vector;
214 if (fit_vector2 % feature_dir < 0.0) {
215 fit_vector2 = -fit_vector2;
219 if (fit_vector2 % feature_dir > fit_vector % feature_dir) {
220 fit_vector = fit_vector2;
231static int ComputeFeatures(
const FCOORD &start_pt,
const FCOORD &end_pt,
double feature_length,
232 std::vector<INT_FEATURE_STRUCT> *features) {
233 FCOORD feature_vector(end_pt - start_pt);
234 if (feature_vector.x() == 0.0f && feature_vector.y() == 0.0f) {
238 uint8_t theta = feature_vector.to_direction();
240 double target_length = feature_vector.length();
241 int num_features =
IntCastRounded(target_length / feature_length);
242 if (num_features == 0) {
246 double lambda_step = 1.0 / num_features;
247 double lambda = lambda_step / 2.0;
248 for (
int f = 0; f < num_features; ++f, lambda += lambda_step) {
249 FCOORD feature_pt(start_pt);
250 feature_pt += feature_vector * lambda;
251 INT_FEATURE_STRUCT feature(feature_pt, theta);
252 features->push_back(feature);
271static int GatherPoints(
const C_OUTLINE *outline,
double feature_length,
const DENORM &denorm,
272 const DENORM *root_denorm,
int start_index,
int end_index, ICOORD *pos,
273 FCOORD *pos_normed, LLSQ *points, LLSQ *dirs) {
274 int step_length = outline->pathlength();
275 ICOORD step = outline->step(start_index % step_length);
284 for (index = start_index; index <= end_index; ++index, *pos += step) {
285 step = outline->step(index % step_length);
286 int edge_weight = outline->edge_strength_at_index(index % step_length);
287 if (edge_weight == 0) {
292 FCOORD f_pos = outline->sub_pixel_pos_at_index(*pos, index % step_length);
293 denorm.NormTransform(root_denorm, f_pos, pos_normed);
294 if (num_points == 0) {
296 prev_normed = *pos_normed;
298 FCOORD offset = *pos_normed - prev_normed;
299 float length = offset.length();
300 if (length > feature_length) {
306 points->add(pos_normed->x(), pos_normed->y(), edge_weight);
307 int direction = outline->direction_at_index(index % step_length);
308 if (direction >= 0) {
309 direction = NormalizeDirection(direction, f_pos, denorm, root_denorm);
312 dirs->add(direction,
Modulo(direction + 128, 256));
325static void ExtractFeaturesFromRun(
const EDGEPT *startpt,
const EDGEPT *lastpt,
326 const DENORM &denorm,
double feature_length,
bool force_poly,
327 std::vector<INT_FEATURE_STRUCT> *features) {
328 const EDGEPT *endpt = lastpt->next;
329 const C_OUTLINE *outline = startpt->src_outline;
330 if (outline !=
nullptr && !force_poly) {
333 const DENORM *root_denorm = denorm.RootDenorm();
334 int total_features = 0;
336 int step_length = outline->pathlength();
337 int start_index = startpt->start_step;
339 ICOORD pos = outline->position_at_index(start_index);
343 int end_index = lastpt->start_step + lastpt->step_count;
344 if (end_index <= start_index) {
345 end_index += step_length;
349 FCOORD prev_normed_pos = outline->sub_pixel_pos_at_index(pos, start_index);
350 denorm.NormTransform(root_denorm, prev_normed_pos, &prev_normed_pos);
353 FCOORD normed_pos(0.0f, 0.0f);
354 int index = GatherPoints(outline, feature_length, denorm, root_denorm, start_index, end_index,
355 &pos, &normed_pos, &points, &dirs);
356 while (index <= end_index) {
364 FCOORD next_normed_pos(0.0f, 0.0f);
365 index = GatherPoints(outline, feature_length, denorm, root_denorm, index, end_index, &pos,
366 &next_normed_pos, &next_points, &next_dirs);
367 LLSQ sum_points(prev_points);
371 sum_points.add(points);
372 sum_points.add(next_points);
373 sum_dirs.add(next_dirs);
374 bool made_features =
false;
376 if (sum_points.count() > 0) {
378 FCOORD fit_pt = sum_points.mean_point();
379 FCOORD fit_vector = MeanDirectionVector(sum_points, sum_dirs, prev_normed_pos, normed_pos);
383 FCOORD start_pos = prev_normed_pos.nearest_pt_on_line(fit_pt, fit_vector);
386 if (total_features == 0 && startpt != endpt) {
387 FCOORD poly_pos(startpt->pos.x, startpt->pos.y);
388 denorm.LocalNormTransform(poly_pos, &start_pos);
390 if (index > end_index && startpt != endpt) {
391 FCOORD poly_pos(endpt->pos.x, endpt->pos.y);
392 denorm.LocalNormTransform(poly_pos, &end_pos);
394 int num_features = ComputeFeatures(start_pos, end_pos, feature_length, features);
395 if (num_features > 0) {
397 prev_points = points;
399 prev_normed_pos = normed_pos;
400 points = next_points;
402 made_features =
true;
403 total_features += num_features;
406 normed_pos = next_normed_pos;
408 if (!made_features) {
411 points.add(next_points);
417 const EDGEPT *pt = startpt;
419 FCOORD start_pos(pt->pos.x, pt->pos.y);
420 FCOORD end_pos(pt->next->pos.x, pt->next->pos.y);
421 denorm.LocalNormTransform(start_pos, &start_pos);
422 denorm.LocalNormTransform(end_pos, &end_pos);
423 ComputeFeatures(start_pos, end_pos, feature_length, features);
424 }
while ((pt = pt->next) != endpt);
437 std::vector<INT_FEATURE_STRUCT> *bl_features,
438 std::vector<INT_FEATURE_STRUCT> *cn_features,
440 std::vector<int> *outline_cn_counts) {
441 DENORM bl_denorm, cn_denorm;
443 if (outline_cn_counts !=
nullptr) {
444 outline_cn_counts->clear();
449 EDGEPT *loop_pt = ol->FindBestStartPt();
461 last_pt = last_pt->
next;
462 }
while (last_pt != loop_pt && !last_pt->
IsHidden() &&
464 last_pt = last_pt->
prev;
470 }
while ((pt = pt->
next) != loop_pt);
471 if (outline_cn_counts !=
nullptr) {
472 outline_cn_counts->push_back(cn_features->size());
475 results->
NumBL = bl_features->size();
476 results->
NumCN = cn_features->size();
#define INT_CHAR_NORM_RANGE
const double kStandardFeatureLength
FCOORD FeatureDirection(uint8_t theta)
TrainingSample * BlobToTrainingSample(const TBLOB &blob, bool nonlinear_norm, INT_FX_RESULT_STRUCT *fx_info, std::vector< INT_FEATURE_STRUCT > *bl_features)
int IntCastRounded(double x)
TBOX bounding_box() const
int ComputeMoments(FCOORD *center, FCOORD *second_moments) const
void GetPreciseBoundingBox(TBOX *precise_box) const
const DENORM & denorm() const
void GetEdgeCoords(const TBOX &box, std::vector< std::vector< int > > &x_coords, std::vector< std::vector< int > > &y_coords) const
void SetupNormalization(const BLOCK *block, const FCOORD *rotation, const DENORM *predecessor, float x_origin, float y_origin, float x_scale, float y_scale, float final_xshift, float final_yshift)
void NormTransform(const DENORM *first_norm, const TPOINT &pt, TPOINT *transformed) const
void DenormTransform(const DENORM *last_denorm, const TPOINT &pt, TPOINT *original) const
void SetupNonLinear(const DENORM *predecessor, const TBOX &box, float target_width, float target_height, float final_xshift, float final_yshift, const std::vector< std::vector< int > > &x_coords, const std::vector< std::vector< int > > &y_coords)
void from_direction(uint8_t direction)
FCOORD nearest_pt_on_line(const FCOORD &line_point, const FCOORD &dir_vector) const
uint8_t to_direction() const
TDimension bottom() const
void pad(int xpad, int ypad)
static void SetupBLCNDenorms(const TBLOB &blob, bool nonlinear_norm, DENORM *bl_denorm, DENORM *cn_denorm, INT_FX_RESULT_STRUCT *fx_info)
static void ExtractFeatures(const TBLOB &blob, bool nonlinear_norm, std::vector< INT_FEATURE_STRUCT > *bl_features, std::vector< INT_FEATURE_STRUCT > *cn_features, INT_FX_RESULT_STRUCT *results, std::vector< int > *outline_cn_counts)
static TrainingSample * CopyFromFeatures(const INT_FX_RESULT_STRUCT &fx_info, const TBOX &bounding_box, const INT_FEATURE_STRUCT *features, int num_features)
void set_bounding_box(const TBOX &box)