AmpereMeterALGO.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <iostream>
  3. #include <fstream>
  4. #include <string>
  5. #include <math.h>
  6. #include <cmath>
  7. #include <opencv2/imgproc.hpp>
  8. #include <opencv2/highgui.hpp>
  9. #include <opencv2/highgui/highgui.hpp>
  10. #include "opencv2/imgproc/types_c.h"
  11. #include <onnxruntime_cxx_api.h>
  12. #include "AmpereMeterALGO.h"
  13. #include <vector>
  14. void AmpereMeterALGO::Init(bool isCuda)
  15. {
  16. string model_path = "models/VoltageAmpereMeter.onnx";
  17. std::wstring widestr = std::wstring(model_path.begin(), model_path.end());
  18. sessionOptions.SetGraphOptimizationLevel(ORT_ENABLE_BASIC);
  19. ort_session = new Session(env, widestr.c_str(), sessionOptions);
  20. size_t numInputNodes = ort_session->GetInputCount();
  21. size_t numOutputNodes = ort_session->GetOutputCount();
  22. AllocatorWithDefaultOptions allocator;
  23. for (int i = 0; i < numInputNodes; i++)
  24. {
  25. input_names.push_back(ort_session->GetInputName(i, allocator));
  26. Ort::TypeInfo input_type_info = ort_session->GetInputTypeInfo(i);
  27. auto input_tensor_info = input_type_info.GetTensorTypeAndShapeInfo();
  28. auto input_dims = input_tensor_info.GetShape();
  29. input_node_dims.push_back(input_dims);
  30. }
  31. for (int i = 0; i < numOutputNodes; i++)
  32. {
  33. output_names.push_back(ort_session->GetOutputName(i, allocator));
  34. Ort::TypeInfo output_type_info = ort_session->GetOutputTypeInfo(i);
  35. auto output_tensor_info = output_type_info.GetTensorTypeAndShapeInfo();
  36. auto output_dims = output_tensor_info.GetShape();
  37. output_node_dims.push_back(output_dims);
  38. }
  39. this->inpHeight = input_node_dims[0][2];
  40. this->inpWidth = input_node_dims[0][3];
  41. this->outHeight = output_node_dims[0][2];
  42. this->outWidth = output_node_dims[0][3];
  43. }
  44. float AmpereMeterALGO::detect(Mat& srcimg)
  45. {
  46. /*namedWindow("矩形", WINDOW_NORMAL);
  47. imshow("矩形", srcimg);
  48. waitKey(0);*/
  49. vector<float> input_image_ = { 1, 3, 512, 512 };
  50. Mat dstimg;
  51. Size resize_size(input_image_[2], input_image_[3]);
  52. resize(srcimg, dstimg, resize_size, 0, 0, cv::INTER_LINEAR);
  53. int channels = dstimg.channels();
  54. input_image_.resize((this->inpWidth * this->inpHeight * dstimg.channels()));
  55. for (int c = 0; c < channels; c++)
  56. {
  57. for (int i = 0; i < this->inpHeight; i++)
  58. {
  59. for (int j = 0; j < this->inpWidth; j++)
  60. {
  61. float pix = dstimg.ptr<uchar>(i)[j * 3 + 2 - c];
  62. input_image_[(c * this->inpHeight * this->inpWidth + i * this->inpWidth + j)] = (pix / 255.0 - mean[c]) / stds[c];
  63. }
  64. }
  65. }
  66. array<int64_t, 4> input_shape_{ 1, 3, this->inpHeight, this->inpWidth };
  67. auto allocator_info = MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
  68. Value input_tensor_ = Value::CreateTensor<float>(allocator_info, input_image_.data(), input_image_.size(), input_shape_.data(), input_shape_.size());
  69. // 开始推理
  70. vector<Value> ort_outputs = ort_session->Run(RunOptions{ nullptr }, &input_names[0], &input_tensor_, 1, output_names.data(), output_names.size());
  71. float* pred = ort_outputs[0].GetTensorMutableData<float>();
  72. Mat result(outHeight, outWidth, CV_32FC1, pred);
  73. result = 3 - result;
  74. result *= 255;
  75. result.convertTo(result, CV_8UC1);
  76. Mat binary;
  77. threshold(result, binary, 150, 255, THRESH_BINARY);//二值化阈值处理
  78. Mat result_line_image = creat_line_image(binary, 258, 128);
  79. /*namedWindow("矩形", WINDOW_NORMAL);
  80. imshow("矩形", result_line_image);
  81. waitKey(0);*/
  82. return get_meter_reader(result_line_image);
  83. }
  84. Mat AmpereMeterALGO::creat_line_image(const Mat& circle, int Radius, int RingStride)
  85. {
  86. Mat rectangle;
  87. float theta;
  88. int rho;
  89. rectangle = Mat::zeros(Size(Radius * pi * 2, RingStride), CV_8UC1);
  90. int nl = rectangle.rows; // number of lines
  91. int nc = rectangle.cols * rectangle.channels(); // total number of elements per line
  92. for (int j = 0; j < nl; j++)
  93. {
  94. // get the address of row j
  95. try
  96. {
  97. uchar* data = rectangle.ptr<uchar>(j);
  98. for (int i = 0; i < nc; i++)
  99. {
  100. theta = pi * 2.0 / LINE_WIDTH * float(i + 1);
  101. rho = (Radius - j - 1);
  102. int position_y = (float)circle_center[0] + rho * (float)std::cos(theta) + 0.5;
  103. int position_x = (float)circle_center[1] - rho * (float)std::sin(theta) + 0.5;
  104. data[i] = circle.at<uchar>(position_y, position_x);
  105. }
  106. }
  107. catch (exception &e) { /* Please, at least do some logging or other error handling here*/ }
  108. }
  109. return rectangle;
  110. }
  111. //像素值提取及累加
  112. float AmpereMeterALGO::get_meter_reader(const Mat& image)
  113. {
  114. Mat histogram = Mat::zeros(Size(256, 1), CV_8UC1);
  115. int rows = LINE_HEIGH; //输入图像的行数
  116. int cols = LINE_WIDTH; //输入图像的列数
  117. int scale_num = 0;
  118. int pointer_num = 0;
  119. int sum_horsum = 0; //水平方向列相加和
  120. vector<int>num1;
  121. vector<int>num2;
  122. for (int c = 0; c < 1696; c++)
  123. {
  124. int versum = 0;
  125. for (int r = 0; r < rows; r++)
  126. {
  127. int index = int(image.at<uchar>(r, c));
  128. versum += index;
  129. }
  130. if (versum != 0)
  131. {
  132. //int max_sum_horsum = 0;
  133. sum_horsum += versum;
  134. //cout << "和:" << sum_horsum << endl;
  135. num1.push_back(sum_horsum);
  136. }
  137. if (versum == 0)
  138. {
  139. int maxValue = 0;
  140. for (auto v : num1)
  141. {
  142. if (maxValue < v) maxValue = v;
  143. }
  144. if (maxValue != 0)
  145. {
  146. //cout << "最大值:" << maxValue << endl;
  147. num2.push_back(maxValue);
  148. }
  149. sum_horsum = 0;
  150. vector<int>().swap(num1);
  151. }
  152. }
  153. //计算表盘读数
  154. int maxPosition = max_element(num2.begin(), num2.end()) - num2.begin();
  155. scale_num = num2.size();
  156. pointer_num = maxPosition ;
  157. float result_ratio = (1.0 * pointer_num / scale_num );
  158. float result_value = (result_ratio * METER_RANGE);
  159. if (result_value > 0)
  160. {
  161. result_value += 2;
  162. }
  163. cout << "scale_num:" << scale_num << " pointer_num:" << pointer_num << " result_ratio:" << result_ratio << " result_value:" << result_value << endl;
  164. return result_value;
  165. }