licornea_tools
cg_optical_flow_features.cc
Go to the documentation of this file.
1 #include "../lib/args.h"
2 #include "../lib/opencv.h"
3 #include "../lib/dataset.h"
4 #include "../lib/image_io.h"
5 #include "../lib/viewer.h"
6 #include "../lib/filesystem.h"
8 #include "lib/feature_points.h"
9 #include <string>
10 #include <format.h>
11 
12 using namespace tlz;
13 
14 
15 int main(int argc, const char* argv[]) {
16  get_args(argc, argv, "dataset_parameters.json [refgrid.json] [out_fpoints_dir/] [dataset_group]");
17  dataset datas = dataset_arg();
18  std::string refgrid_filename = in_filename_opt_arg();
19  std::string out_fpoints_dirname = out_dirname_opt_arg();
20  std::string dataset_group_name = string_opt_arg("");
21 
22  dataset_group datag = datas.group(dataset_group_name);
23 
24  viewer view("Dataset Viewer", datag.image_size_with_border(), true);
25  std::function<view_index()> get_shown_idx;
26  references_grid grid;
27  if(refgrid_filename.empty()) {
28  const auto& slider_x = view.add_int_slider("X", datas.x_mid(), datas.x_min(), datas.x_max(), datas.x_step());
29  auto& slider_y = view.add_int_slider("Y", datas.y_mid(), datas.y_min(), datas.y_max(), datas.y_step());
30  get_shown_idx = [&]() {
31  return view_index(slider_x, slider_y);
32  };
33  } else {
34  grid = decode_references_grid(import_json_file(refgrid_filename));
35  auto& slider_col = view.add_int_slider("r_col", 0, 0, grid.cols()-1);
36  auto& slider_row = view.add_int_slider("r_row", 0, 0, grid.rows()-1);
37  get_shown_idx = [&]() {
38  return grid.view(slider_col, slider_row);
39  };
40  }
41 
42 
43  auto& min_distance_between_features = view.add_int_slider("dist", 60, 1, 200);
44  auto& features_quality_level = view.add_real_slider("qual", 0.5, 0.0, 1.0);
45  auto& wanted_features = view.add_int_slider("wanted", 100, 1, 300);
46  auto& subdivisions = view.add_int_slider("subdiv", 2, 1, 4);
47 
48  auto choose_features = [&](const cv::Mat_<cv::Vec3b>& orig_img) {
49  cv::Mat_<uchar> img;
50  cv::cvtColor(orig_img, img, CV_BGR2GRAY);
51 
52  int width = img.cols, height = img.rows;
53 
54  const int pieces_count = subdivisions * subdivisions;
55  auto get_piece_mask = [&](int piece) {
56  int w = width/subdivisions;
57  int h = height/subdivisions;
58  int x = (piece % subdivisions) * w;
59  int y = (piece / subdivisions) * h;
60 
61  cv::Mat_<uchar> mask(height, width);
62  mask.setTo(0);
63  mask(cv::Rect(x, y, w, h)).setTo(255);
64  return mask;
65  };
66 
67  std::vector<std::vector<cv::Point2f>> piece_positions(pieces_count);
68  #pragma omp parallel for
69  for(int piece = 0; piece < pieces_count; ++piece) {
70  cv::Mat_<uchar> piece_mask = get_piece_mask(piece);
71  cv::goodFeaturesToTrack(img, piece_positions[piece], wanted_features, features_quality_level, min_distance_between_features, piece_mask);
72  }
73 
74  std::vector<cv::Point2f> positions;
75  int i = 0;
76  while(positions.size() < wanted_features) {
77  bool none_left = true;
78  for(const std::vector<cv::Point2f>& piece_pos : piece_positions) {
79  if(piece_pos.size() <= i) continue;
80  positions.push_back(piece_pos[i]);
81  none_left = false;
82  }
83  if(none_left) break;
84  ++i;
85  }
86 
87  return positions;
88  };
89 
90  view.update_callback = [&]() {
91  view_index idx = get_shown_idx();
92  if(! datas.valid(idx)) return;
93 
94  std::string filename = datag.view(idx).image_filename();
95  try {
96  cv::Mat_<cv::Vec3b> img = load_texture(filename);
97  std::vector<cv::Point2f> features = choose_features(img);
98  for(cv::Point2f pt : features) {
99  cv_aa_circle(img, pt, 7, cv::Scalar(cv::Vec3b(255, 255, 255)), 3);
100  cv_aa_circle(img, pt, 5, cv::Scalar(cv::Vec3b(0, 0, 255)), 2);
101  }
102  view.draw(img);
103  } catch(const std::runtime_error&) {
104  std::cout << "could not load " << filename << std::endl;
105  view.clear();
106  }
107  };
108 
109  auto unique_feature_name = [](int number) {
110  return fmt::format("feat{:04d}", number);
111  };
112 
113  auto export_fpoints = [&](view_index idx, int global_index_base = 0) {
114  int number = 0;
115  std::string img_filename = datag.view(idx).image_filename();
116  cv::Mat_<cv::Vec3b> img = load_texture(img_filename);
117  std::vector<cv::Point2f> features = choose_features(img);
118  feature_points fpoints;
119  fpoints.view_idx = idx;
120  for(const cv::Point2f& pt : features) {
121  std::string feature_name = unique_feature_name(global_index_base + number);
122  number++;
123  feature_point fpoint;
124  fpoint.position = point2f_to_vec2(pt);
125  fpoints.points[feature_name] = fpoint;
126  }
127 
128  std::string out_filename = "fpoints_" + encode_view_index(idx) + ".json";
129  out_filename = filename_append(out_fpoints_dirname, out_filename);
130  export_json_file(encode_feature_points(fpoints), out_filename);
131  };
132 
133  view.key_callback = [&](int keycode) {
134  if(keycode != enter_keycode) return;
135 
136  if(grid.is_valid()) {
137  std::cout << "saving feature points for all reference views" << std::endl;
138  int global_index_base = 0;
139  for(std::ptrdiff_t col = 0; col < grid.cols(); ++col)
140  for(std::ptrdiff_t row = 0; row < grid.rows(); ++row) {
141  export_fpoints(grid.view(col, row), global_index_base);
142  global_index_base += 1000;
143  }
144 
145  } else {
146  std::cout << "saving feature points for this view" << std::endl;
147  export_fpoints(get_shown_idx());
148  }
149  };
150 
151  view.show_modal();
152 }
std::string filename_append(const std::string &a, const std::string &b)
cv::Size image_size_with_border() const
Definition: dataset.cc:101
int main(int argc, const char *argv[])
int x_step() const
Definition: dataset.cc:173
std::vector< vec2 > positions(const feature_points &fpoints)
references_grid decode_references_grid(const json &j_grid)
std::string image_filename() const
Definition: dataset.cc:64
std::string encode_view_index(view_index idx)
Definition: dataset.cc:275
bool is_valid() const
int x_max() const
Definition: dataset.cc:169
int x_min() const
Definition: dataset.cc:165
dataset_view view(int x) const
Definition: dataset.cc:105
Points of different features, on one view.
int x_mid() const
Definition: dataset.cc:186
cv::Mat_< cv::Vec3b > load_texture(const std::string &filename)
Definition: image_io.cc:6
std::map< std::string, feature_point > points
bool valid(view_index) const
Definition: dataset.cc:231
json encode_feature_points(const feature_points &fpoints)
dataset dataset_arg()
Definition: dataset.cc:297
constexpr int enter_keycode
Definition: common.h:73
void export_json_file(const json &j, const std::string &filename, bool compact)
Definition: json.cc:9
view_index view(std::ptrdiff_t col, std::ptrdiff_t row) const
int y_step() const
Definition: dataset.cc:206
std::string out_dirname_opt_arg(const std::string &def)
Definition: args.cc:127
constexpr real min_distance_between_features
int y_max() const
Definition: dataset.cc:201
std::size_t cols() const
json import_json_file(const std::string &filename)
Definition: json.cc:24
std::string in_filename_opt_arg(const std::string &def="")
Definition: args.h:40
int y_min() const
Definition: dataset.cc:196
dataset_group group(const std::string &grp) const
Definition: dataset.cc:265
void cv_aa_circle(cv::Mat &mat, const cv::Point2f &center, float rad, cv::Scalar col, int thickness)
Definition: opencv.cc:5
int y_mid() const
Definition: dataset.cc:226
std::string string_opt_arg(const std::string &def="")
Definition: args.h:36
std::size_t rows() const
void get_args(int argc, const char *argv[], const std::string &usage)
Definition: args.cc:49