Version: 1.0
conact_code_generator.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020, the GRAPHGEN contributors, as
2 // shown by the AUTHORS file. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file.
6 
8 
9 #include <map>
10 
11 
12 #include "utilities.h"
13 
14 using namespace std;
15 
16 // Generate string to access a pixel value using pointers
17 string GenerateAccessPixelCode(const string& img_name, const pixel& p) {
18  string slice_id = "";
19  if (p.coords_.size() > 2) {
20  slice_id = "slice" + string(p.coords_[2] < 0 ? "1" : "0") + to_string(abs(p.coords_[2])) + "_";
21  }
22 
23  string row_id = "row" + string(p.coords_[1] < 0 ? "1" : "0") + to_string(abs(p.coords_[1]));
24  string col = "";
25  if (p.coords_[0] > 0) {
26  col += " + " + to_string(abs(p.coords_[0]));
27  }
28  else if (p.coords_[0] < 0) {
29  col += " - " + to_string(abs(p.coords_[0]));
30  }
31 
32  return img_name + slice_id + row_id + "[c" + col + "]";
33 }
34 
35 string CreateAssignmentCodeRec(const std::vector<std::string>& pixels_names, const pixel_set& names) {
36  if (pixels_names.size() == 1) {
37  pixel p = names[pixels_names.front()];
38  return GenerateAccessPixelCode("img_labels_", p);
39  }
40 
41  std::vector<std::string> pixels_names_seta(pixels_names.size() / 2), pixels_names_setb(pixels_names.size() - (pixels_names.size() / 2));
42 
43  std::copy_n(pixels_names.begin(), pixels_names_seta.size(), pixels_names_seta.begin());
44  std::copy_n(pixels_names.begin() + pixels_names_seta.size(), pixels_names_setb.size(), pixels_names_setb.begin());
45 
46  return "LabelsSolver::Merge(" + CreateAssignmentCodeRec(pixels_names_setb, names) + ", " + CreateAssignmentCodeRec(pixels_names_seta, names) + ")";
47 }
48 
49 string CreateAssignmentCode(const string& action, const pixel_set& names) {
50  if (action == "nothing") {
51  return "0";
52  }
53 
54  string action_ = action.substr(3);
55  if (action_ == "newlabel") {
56  return "LabelsSolver::NewLabel()";
57  }
58 
59  std::vector<std::string> pixels_names;
60  StringSplit(action_, pixels_names);
61 
62  assert(pixels_names.size() > 0 && "Something wrong with actions");
63 
64  return CreateAssignmentCodeRec(pixels_names, names);
65 }
66 
67 // This is the version for CTBE algorithm, still very raw
68 string CreateActionCodeCtbe(const string& action, const pixel_set& names, const string& assignment_variable) {
69  if (action == "nothing") {
70  return "NOTHING";
71  }
72 
73  string action_ = action.substr(3);
74  if (action_ == "newlabel") {
75  return assignment_variable + " LabelsSolver::NewLabel()";
76  }
77 
78  std::vector<std::string> pixels_names;
79  StringSplit(action_, pixels_names);
80 
81  assert(pixels_names.size() > 0 && "Something wrong with actions");
82 
83  return assignment_variable + " " + CreateAssignmentCodeRec(pixels_names, names);
84 }
85 
86 void GeneratePointersCode(ofstream& os, const rule_set& rs) {
87  // The names of pointers are identified by the following string
88  // <image_name>_<slice_identifier>_<row_identifier>
89  //
90  // slice identifiers can be (first number is the sign):
91  // - 'slice00' for the current slice (z)
92  // - 'slice11' for the slice z - 1
93  // - 'slice12' for the slice z - 2
94  // - 'slice01' for the slice z + 1
95  // - 'slice02' for the slice z + 2
96  // - .. and so on
97  //
98  // row identifiers can be (first number is the sign):
99  // - 'row00' for the current row (y)
100  // - 'row11' for the row y - 1
101  // - 'row12' for the row y - 2
102  // - 'row01' for the row y + 1
103  // - 'row02' for the row y + 2
104  // - .. and so on
105 
106  // Pointers:
107  os << "//Pointers:\n";
108 
109  auto& shifts = rs.ps_.shifts_; // Shifts on each dim -> [x, y] or [x, y, z]
110  size_t n_dims = shifts.size(); // Here we get how many dims image has
111 
112  stringstream global_ss, in_ss, out_ss;
113  string type_in_prefix_string = "const unsigned char* const ";
114  string type_out_prefix_string = "unsigned* const ";
115 
116  // TODO: 3D generation only works with unitary shift
117  // x is always ignored because we always create row pointers
118  switch (n_dims) {
119  case 2:
120  {
121  string base_row_in_name = "img_row00";
122  string base_row_out_name = "img_labels_row00";
123  string base_row_in = type_in_prefix_string + base_row_in_name + " = img_.ptr<unsigned char>(r);";
124  string base_row_out = type_out_prefix_string + base_row_out_name + " = img_labels_.ptr<unsigned>(r);";
125 
126  in_ss << "// Row pointers for the input image \n";
127  in_ss << base_row_in + "\n";
128 
129  out_ss << "// Row pointers for the output image \n";
130  out_ss << base_row_out + "\n";
131 
132  for (int j = -shifts[1]; j < shifts[1]; ++j) { // TODO: should use min and max y in mask
133 
134  if (j == 0) {
135  continue;
136  }
137 
138  string complete_string_in =
139  type_in_prefix_string +
140  "img_row" + to_string(j < 0) + to_string(abs(j)) +
141  " = (unsigned char *)(((char *)" + base_row_in_name + ") + img_.step.p[0] * " + to_string(j) + ");";
142  in_ss << complete_string_in + "\n";
143 
144 
145  string complete_string_out =
146  type_out_prefix_string +
147  "img_labels_row" + to_string(j < 0) + to_string(abs(j)) +
148  " = (unsigned *)(((char *)" + base_row_out_name + ") + img_labels_.step.p[0] * " + to_string(j) + ");";
149  out_ss << complete_string_out + "\n";
150 
151  }
152  break;
153  }
154  case 3:
155  {
156  // TODO: this generation only works with unitary shift
157 
158  // Current slice
159  string base_row_in_name = "img_slice00_row00";
160  string base_row_out_name = "img_labels_slice00_row00";
161  string base_row_in = type_in_prefix_string + base_row_in_name + " = img_.ptr<unsigned char>(s, r);";
162  string base_row_out = type_out_prefix_string + base_row_out_name + " = img_labels_.ptr<unsigned>(s, r);";
163 
164  in_ss << "// Row pointers for the input image (current slice) \n";
165  in_ss << base_row_in + "\n";
166 
167  out_ss << "// Row pointers for the output image (current slice)\n";
168  out_ss << base_row_out + "\n";
169 
170  for (int j = -shifts[1]; j < shifts[1]; ++j) {
171 
172  if (j == 0) {
173  continue;
174  }
175 
176  string complete_string_in =
177  type_in_prefix_string +
178  "img_slice00_row" + to_string(j < 0) + to_string(abs(j)) +
179  " = (unsigned char *)(((char *)" + base_row_in_name + ") + img_.step.p[1] * " + to_string(j) + ");";
180  in_ss << complete_string_in + "\n";
181 
182  string complete_string_out =
183  type_out_prefix_string +
184  "img_labels_slice00_row" + to_string(j < 0) + to_string(abs(j)) +
185  " = (unsigned *)(((char *)" + base_row_out_name + ") + img_labels_.step.p[1] * " + to_string(j) + ");";
186  out_ss << complete_string_out + "\n";
187 
188  }
189 
190  in_ss << "\n// Row pointers for the input image (previous slice) \n";
191  out_ss << "\n// Row pointers for the output image (previous slice)\n";
192 
193  // Previous slice
194  base_row_in = type_in_prefix_string + base_row_in_name + " = img_.ptr<unsigned char>(s, r);";
195  base_row_out = type_out_prefix_string + base_row_out_name + " = img_labels_.ptr<unsigned>(s, r);";
196 
197  for (int j = -shifts[1]; j <= shifts[1]; ++j) {
198 
199  string complete_string_in =
200  type_in_prefix_string +
201  "img_slice11_row" + to_string(j < 0) + to_string(abs(j)) +
202  " = (unsigned char *)(((char *)" + base_row_in_name + ") - img_.step.p[0] + img_.step.p[1] * " + to_string(j) + ");";
203  in_ss << complete_string_in + "\n";
204 
205  string complete_string_out =
206  type_out_prefix_string +
207  "img_labels_slice11_row" + to_string(j < 0) + to_string(abs(j)) +
208  " = (unsigned *)(((char *)" + base_row_out_name + ") - img_labels_.step.p[0] + img_labels_.step.p[1] * " + to_string(j) + ");";
209  out_ss << complete_string_out + "\n";
210 
211  }
212  }
213  break;
214  }
215  global_ss << in_ss.str() + "\n" + out_ss.str();
216  os << global_ss.str();
217 }
218 
219 void GenerateConditionsCode(ofstream& os, const rule_set& rs, bool with_conditions)
220 {
221  auto& shifts = rs.ps_.shifts_; // Shifts on each dim -> [x, y] or [x, y, z]
222  size_t n_dims = shifts.size(); // Here we get how many dims image has
223  // Conditions:
224  os << "//Conditions:\n";
225 
226  vector<string> counters_names = { "c", "r", "s" };
227  vector<string> sizes_names = { "w", "h", "d" };
228  for (const auto& p : rs.ps_) {
229  string uppercase_name(p.name_);
230  transform(p.name_.begin(), p.name_.end(), uppercase_name.begin(), ::toupper);
231  os << "#define CONDITION_" + uppercase_name + " ";
232  // stringstream col;
233  if (with_conditions) {
234  for (size_t i = 0; i < n_dims; ++i) {
235  if (p.coords_[i] < 0) {
236  os << counters_names[i] << " > " << -p.coords_[i] - 1 << " && ";
237  }
238  else if (p.coords_[i] > 0) {
239  os << counters_names[i] << " < " << sizes_names[i] << " - " << p.coords_[i] << " && ";
240  }
241  }
242  }
243 
244  os << GenerateAccessPixelCode("img_", p) << " > 0\n";
245  }
246 }
247 
248 // This is the function to generate Connected Component Labeling action code
249 void GenerateActionsCode(ofstream& os, const rule_set& rs, const pixel_set& names, bool with_continues = true)
250 {
251  auto& shifts = rs.ps_.shifts_; // Shifts on each dim -> [x, y] or [x, y, z]
252  size_t n_dims = shifts.size(); // Here we get how many dims image has
253 
254  // Actions:
255  os << "\n\n//Actions:\n";
256  for (size_t a = 0; a < rs.actions.size(); ++a) {
257 
258  string cur_action = rs.actions[a];
259 
260  os << "// Action " << a + 1 << ": " << cur_action << "\n";
261  os << "#define ACTION_" << a + 1 << " ";
262 
263  string where_to_write = "img_labels_" + string(n_dims > 2 ? "slice00_" : "") + "row00[c] = ";
264 
265  os << where_to_write << CreateAssignmentCode(cur_action, names) << ";";
266 
267  if (with_continues) {
268  os << "continue;";
269  }
270 
271  os << "\n";
272  }
273 }
274 
275 // This is the function to generate Thinning action code
276 void GenerateThinningActionsCode(ofstream& os, const rule_set& rs, bool with_continues = true) {
277  // Actions:
278  os << "\n\n//Actions:\n";
279  for (size_t a = 0; a < rs.actions.size(); ++a) {
280  const auto& action = rs.actions[a];
281 
282  os << "#define ACTION_" + std::to_string(a + 1);
283 
284  if (action == "keep0") {
285  os << " ; // keep0\n";
286  }
287 
288  if (action == "keep1") {
289  os << " img_row00[c] = 1; // keep1\n";
290  }
291 
292  if (action == "change0") {
293  os << " modified = true; // change0\n";
294  }
295  }
296 }
297 
298 // This is the function to generate Chain Code action code
299 void GenerateChaincodeActionsCode(ofstream& os, const rule_set& rs, bool with_continues = true) {
300  // Actions:
301  os << "\n\n//Actions:\n";
302  for (size_t a = 0; a < rs.actions.size(); ++a) {
303  const auto& action = rs.actions[a];
304 
305  os << "#define ACTION_" << (a + 1) << "\tpos = ProcessPixel<" << action << "\t>(r, c, rccode, chains, pos);";
306 
307  if (with_continues) {
308  os << " continue;";
309  }
310 
311  os << "\n";
312 
313  }
314 }
315 
319  std::optional<pixel_set> names)
320 {
321  bool actions_with_conditions = flag & GenerateConditionActionCodeFlags::CONDITIONS_WITH_IFS;
322  bool actions_with_continue = flag & GenerateConditionActionCodeFlags::ACTIONS_WITH_CONTINUE;
323 
324  ofstream os(conf.code_path_);
325  if (!os) {
326  return false;
327  }
328 
329  if (!names) {
330  names = rs.ps_;
331  }
332 
333  GeneratePointersCode(os, rs);
334  GenerateConditionsCode(os, rs, actions_with_conditions);
335 
336  switch (type) {
338  GenerateActionsCode(os, rs, names.value(), actions_with_continue);
339  break;
341  GenerateThinningActionsCode(os, rs, actions_with_continue);
342  break;
344  GenerateChaincodeActionsCode(os, rs, actions_with_continue);
345  break;
346  default:
347  std::cout << "WARNING: the specified algorithms type is not valid. The ACTION code won't be generated\n";
348  }
349 
350  return true;
351 }
352 
353 //bool GenerateActionsForCtbe(const string& filename, const rule_set& rs) {
354 // ofstream os(filename);
355 //
356 // if (!os) {
357 // return false;
358 // }
359 //
360 // // Actions:
361 // os << "\n\n//Actions:\n";
362 // os << "#define NOTHING \n";
363 // for (size_t a = 0; a < rs.actions.size(); ++a) {
364 //
365 // string cur_action = rs.actions[a];
366 //
367 // os << "// Action " << a + 1 << ": " << cur_action << "\n";
368 // os << "#define ACTION_" << a + 1 << " ";
369 //
370 // vector<string> pixels_actions;
371 // StringSplit(cur_action, pixels_actions, ',');
372 //
373 // if (pixels_actions[1].substr(3) == "e" && (pixels_actions[2].substr(3) == "e" || pixels_actions[2].substr(3) == "g")) {
374 // os << CreateActionCodeCtbe(pixels_actions[0], rs, "img_labels_row00[c] = img_labels_row01[c] = img_labels_row02[c] = ") << "; continue; \n";
375 // }
376 // else {
377 // if (pixels_actions[1].substr(3) == "e") {
378 // os << CreateActionCodeCtbe(pixels_actions[0], rs, "img_labels_row00[c] = img_labels_row01[c] = ") << "; ";
379 // os << CreateActionCodeCtbe(pixels_actions[2], rs, "img_labels_row02[c] = ") << "; continue;\n";
380 // }
381 // else {
382 // if (pixels_actions[2].substr(3) == "e") {
383 // os << CreateActionCodeCtbe(pixels_actions[0], rs, "img_labels_row00[c] = img_labels_row02[c] = ") << "; ";
384 // os << CreateActionCodeCtbe(pixels_actions[1], rs, "img_labels_row01[c] = ") << "; continue;\n";
385 // }
386 // else {
387 // // Il pixel "e" ha azione unica
388 //
389 // os << CreateActionCodeCtbe(pixels_actions[0], rs, "img_labels_row00[c] = ") << "; ";
390 // if (pixels_actions[2].substr(3) == "e") {
391 // os << CreateActionCodeCtbe(pixels_actions[1], rs, "img_labels_row01[c] = img_labels_row02[c] = ") << "; continue;\n";
392 // }
393 // else {
394 // // Ogni pixel ha la sua azione
395 // os << CreateActionCodeCtbe(pixels_actions[1], rs, "img_labels_row01[c] = ") << "; ";
396 // os << CreateActionCodeCtbe(pixels_actions[2], rs, "img_labels_row02[c] = ") << "; continue;\n";
397 // }
398 // }
399 // }
400 // }
401 // }
402 //
403 // return true;
404 //}
bool GeneratePointersConditionsActionsCode(const rule_set &rs, GenerateConditionActionCodeFlags flag, GenerateActionCodeTypes type, std::optional< pixel_set > names)
TODO fix documentation names contains the position in the labels image corresponding to the names use...
string GenerateAccessPixelCode(const string &img_name, const pixel &p)
void GenerateThinningActionsCode(ofstream &os, const rule_set &rs, bool with_continues=true)
string CreateAssignmentCodeRec(const std::vector< std::string > &pixels_names, const pixel_set &names)
void GenerateActionsCode(ofstream &os, const rule_set &rs, const pixel_set &names, bool with_continues=true)
void GeneratePointersCode(ofstream &os, const rule_set &rs)
string CreateAssignmentCode(const string &action, const pixel_set &names)
string CreateActionCodeCtbe(const string &action, const pixel_set &names, const string &assignment_variable)
void GenerateConditionsCode(ofstream &os, const rule_set &rs, bool with_conditions)
void GenerateChaincodeActionsCode(ofstream &os, const rule_set &rs, bool with_continues=true)
GenerateConditionActionCodeFlags
This is the enum class that defines the available flags for the GeneratePointersConditionsActionsCode...
@ ACTIONS_WITH_CONTINUE
Whether to add continues at the end of each action or not.
@ CONDITIONS_WITH_IFS
Whether to add if statements or not when generating conditions code. They serve to check if the pixel...
GenerateActionCodeTypes
This is the enum class that defines the available algorithms types for the GenerateActionsCode functi...
@ LABELING
Connected Components Labeling.
std::filesystem::path code_path_
Definition: config_data.h:49
std::vector< uint8_t > shifts_
Definition: pixel_set.h:89
std::vector< int > coords_
Definition: pixel_set.h:23
pixel_set ps_
Definition: rule_set.h:53
std::vector< std::string > actions
Definition: rule_set.h:50
ConfigData conf
Definition: utilities.cpp:9
void StringSplit(const std::string &str, T &cont, char delim='+')
Definition: utilities.h:77