postprocess.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <iostream>
  15. #include <vector>
  16. #include <utility>
  17. #include <limits>
  18. #include <cmath>
  19. #include <chrono> // NOLINT
  20. #include <opencv2/opencv.hpp>
  21. #include <opencv2/highgui.hpp>
  22. #include <opencv2/core/core.hpp>
  23. #include "meter_reader/global.h"
  24. #include "meter_reader/postprocess.h"
  25. using namespace std::chrono; // NOLINT
  26. // The size of inputting images (SEG_IMAGE_SIZE x SEG_IMAGE_SIZE) of
  27. // the segmenter.
  28. #define SEG_IMAGE_SIZE 512
  29. // During the postprocess phase, annulus formed by the radius from
  30. // 130 to 250 of a circular meter will be converted to a rectangle.
  31. // So the height of the rectangle is 120.
  32. #define LINE_HEIGHT 120
  33. // The width of the rectangle is 1570, that is to say the perimeter
  34. // of a circular meter.
  35. #define LINE_WIDTH 1570
  36. // Radius of a circular meter
  37. #define CIRCLE_RADIUS 250
  38. const float pi = 3.1415926536f;
  39. // Center of a circular meter
  40. const int circle_center[] = {256, 256};
  41. void creat_line_image(const std::vector<int64_t> &seg_image,
  42. std::vector<unsigned char> *output) {
  43. float theta;
  44. int rho;
  45. int image_x;
  46. int image_y;
  47. // The minimum scale value is at the bottom left, the maximum scale value
  48. // is at the bottom right, so the vertical down axis is the starting axis and
  49. // rotates around the meter ceneter counterclockwise.
  50. for (int row = 0; row < LINE_HEIGHT; row++) {
  51. for (int col = 0; col < LINE_WIDTH; col++) {
  52. theta = pi * 2 / LINE_WIDTH * (col + 1);
  53. rho = CIRCLE_RADIUS - row - 1;
  54. image_y = static_cast<int>(circle_center[0] + rho * cos(theta) + 0.5);
  55. image_x = static_cast<int>(circle_center[1] - rho * sin(theta) + 0.5);
  56. (*output)[row * LINE_WIDTH + col] =
  57. seg_image[image_y * SEG_IMAGE_SIZE + image_x];
  58. }
  59. }
  60. return;
  61. }
  62. void convert_1D_data(const std::vector<unsigned char> &line_image,
  63. std::vector<unsigned int> *scale_data,
  64. std::vector<unsigned int> *pointer_data) {
  65. // Accumulte the number of positions whose label is 1 along the height axis.
  66. // Accumulte the number of positions whose label is 2 along the height axis.
  67. for (int col = 0; col < LINE_WIDTH; col++) {
  68. (*scale_data)[col] = 0;
  69. (*pointer_data)[col] = 0;
  70. for (int row = 0; row < LINE_HEIGHT; row++) {
  71. if (line_image[row * LINE_WIDTH + col] == 1) {
  72. (*pointer_data)[col]++;
  73. } else if (line_image[row * LINE_WIDTH + col] == 2) {
  74. (*scale_data)[col]++;
  75. }
  76. }
  77. }
  78. return;
  79. }
  80. void scale_mean_filtration(const std::vector<unsigned int> &scale_data,
  81. std::vector<unsigned int> *scale_mean_data) {
  82. int sum = 0;
  83. float mean = 0;
  84. int size = scale_data.size();
  85. for (int i = 0; i < size; i++) {
  86. sum = sum + scale_data[i];
  87. }
  88. mean = static_cast<float>(sum) / static_cast<float>(size);
  89. for (int i = 0; i < size; i++) {
  90. if (static_cast<float>(scale_data[i]) >= mean) {
  91. (*scale_mean_data)[i] = scale_data[i];
  92. }
  93. }
  94. return;
  95. }
  96. void get_meter_reader(const std::vector<unsigned int> &scale,
  97. const std::vector<unsigned int> &pointer,
  98. READ_RESULT *result) {
  99. std::vector<float> scale_location;
  100. float one_scale_location = 0;
  101. bool scale_flag = 0;
  102. unsigned int one_scale_start = 0;
  103. unsigned int one_scale_end = 0;
  104. float pointer_location = 0;
  105. bool pointer_flag = 0;
  106. unsigned int one_pointer_start = 0;
  107. unsigned int one_pointer_end = 0;
  108. for (int i = 0; i < LINE_WIDTH; i++) {
  109. // scale location
  110. if (scale[i] > 0 && scale[i+1] > 0) {
  111. if (scale_flag == 0) {
  112. one_scale_start = i;
  113. scale_flag = 1;
  114. }
  115. }
  116. if (scale_flag == 1) {
  117. if (scale[i] == 0 && scale[i+1] == 0) {
  118. one_scale_end = i - 1;
  119. one_scale_location = (one_scale_start + one_scale_end) / 2.;
  120. scale_location.push_back(one_scale_location);
  121. one_scale_start = 0;
  122. one_scale_end = 0;
  123. scale_flag = 0;
  124. }
  125. }
  126. // pointer location
  127. if (pointer[i] > 0 && pointer[i+1] > 0) {
  128. if (pointer_flag == 0) {
  129. one_pointer_start = i;
  130. pointer_flag = 1;
  131. }
  132. }
  133. if (pointer_flag == 1) {
  134. if ((pointer[i] == 0) && (pointer[i+1] == 0)) {
  135. one_pointer_end = i - 1;
  136. pointer_location = (one_pointer_start + one_pointer_end) / 2.;
  137. one_pointer_start = 0;
  138. one_pointer_end = 0;
  139. pointer_flag = 0;
  140. }
  141. }
  142. }
  143. int scale_num = scale_location.size();
  144. result->scale_num = scale_num;
  145. result->scales = -1;
  146. result->ratio = -1;
  147. if (scale_num > 0) {
  148. for (int i = 0; i < scale_num - 1; i++) {
  149. if (scale_location[i] <= pointer_location &&
  150. pointer_location < scale_location[i + 1]) {
  151. result->scales = i + 1 +
  152. (pointer_location-scale_location[i]) /
  153. (scale_location[i+1]-scale_location[i] + 1e-05);
  154. }
  155. }
  156. result->ratio =
  157. (pointer_location - scale_location[0]) /
  158. (scale_location[scale_num - 1] - scale_location[0] + 1e-05);
  159. }
  160. return;
  161. }
  162. void read_process(const std::vector<std::vector<int64_t>> &seg_image,
  163. std::vector<READ_RESULT> *read_results,
  164. const int thread_num) {
  165. int read_num = seg_image.size();
  166. #pragma omp parallel for num_threads(thread_num)
  167. for (int i_read = 0; i_read < read_num; i_read++) {
  168. // Convert the circular meter into a rectangular meter
  169. std::vector<unsigned char> line_result(LINE_WIDTH*LINE_HEIGHT, 0);
  170. creat_line_image(seg_image[i_read], &line_result);
  171. // Get two one-dimension data where 0 represents background and
  172. // >0 represents a scale or a pointer
  173. std::vector<unsigned int> scale_data(LINE_WIDTH);
  174. std::vector<unsigned int> pointer_data(LINE_WIDTH);
  175. convert_1D_data(line_result, &scale_data, &pointer_data);
  176. // Fliter scale data whose value is lower than the mean value
  177. std::vector<unsigned int> scale_mean_data(LINE_WIDTH);
  178. scale_mean_filtration(scale_data, &scale_mean_data);
  179. // Get the number of scales,the pointer location relative to the
  180. // scales, the ratio between the distance from the pointer to the
  181. // starting scale and distance from the ending scale to the
  182. // starting scale.
  183. READ_RESULT result;
  184. get_meter_reader(scale_mean_data, pointer_data, &result);
  185. (*read_results)[i_read] = std::move(result);
  186. }
  187. return;
  188. }