|
@@ -1,165 +1,236 @@
|
|
|
+#define _CRT_SECURE_NO_WARNINGS
|
|
|
+#include <iostream>
|
|
|
+#include <fstream>
|
|
|
+#include <string>
|
|
|
+#include <math.h>
|
|
|
+#include <cmath>
|
|
|
+#include <opencv2/imgproc.hpp>
|
|
|
+#include <opencv2/highgui.hpp>
|
|
|
+#include <opencv2/highgui/highgui.hpp>
|
|
|
+#include "opencv2/imgproc/types_c.h"
|
|
|
+#include <onnxruntime_cxx_api.h>
|
|
|
#include "DoublePointerCountALGO.h"
|
|
|
-#include "LineHandle.h"
|
|
|
-using namespace std;
|
|
|
+#include <vector>
|
|
|
+#include <algorithm>
|
|
|
+
|
|
|
using namespace cv;
|
|
|
-int DoublePointerCountALGO::GetResult(cv::Mat sourceMat, bool IsShowWnd)
|
|
|
+using namespace std;
|
|
|
+using namespace Ort;
|
|
|
+
|
|
|
+void DoublePointerCountALGO::Init(bool isCuda)
|
|
|
{
|
|
|
- Mat mat;
|
|
|
- sourceMat.copyTo(mat);
|
|
|
- int matCols = 500;
|
|
|
- Size size(500, 420);
|
|
|
- resize(mat, mat, size, (float)matCols / mat.cols, (float)matCols / mat.cols);
|
|
|
-
|
|
|
- int width = mat.cols;// .width;
|
|
|
- int height = mat.rows;
|
|
|
- Mat grayMat;
|
|
|
- cvtColor(mat, grayMat, COLOR_BGR2GRAY); // 转换为灰度图
|
|
|
- //Mat thMat;
|
|
|
- adaptiveThreshold(grayMat, grayMat, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 151, 2);
|
|
|
- if (IsShowWnd) {
|
|
|
- imshow("二值化图adaptiveThreshold", grayMat);
|
|
|
- }
|
|
|
- Mat biMat;
|
|
|
- bilateralFilter(grayMat, biMat, 9, 50, 50);
|
|
|
- if (IsShowWnd) {
|
|
|
- imshow("滤波去噪图", biMat);
|
|
|
- }
|
|
|
- //Mat gaussMat;
|
|
|
- GaussianBlur(biMat, grayMat, Size(3, 3), 0, 0);
|
|
|
- if (IsShowWnd) {
|
|
|
- imshow("高斯模糊图", grayMat);
|
|
|
- }
|
|
|
- medianBlur(grayMat, grayMat, 3);//中值滤波
|
|
|
- if (IsShowWnd) {
|
|
|
- imshow("中值滤波图", grayMat);
|
|
|
- }
|
|
|
- adaptiveThreshold(grayMat, grayMat, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 151, 2);
|
|
|
- if (IsShowWnd) {
|
|
|
- imshow("二次二值化图", grayMat);
|
|
|
- }
|
|
|
- Mat cannyMat;
|
|
|
- int g_nthreshold = 39;
|
|
|
- int c_cen = min(height, width);
|
|
|
- int w = grayMat.cols;
|
|
|
- int h = grayMat.rows;
|
|
|
- uchar* uc_pixel;
|
|
|
- for (int row = 0; row < h; row++) {
|
|
|
- uc_pixel = grayMat.data + row * grayMat.step;
|
|
|
- for (int col = 0; col < w; col++) {
|
|
|
- uc_pixel[0] = 255 - uc_pixel[0];
|
|
|
- uc_pixel[1] = 255 - uc_pixel[1];
|
|
|
- uc_pixel[2] = 255 - uc_pixel[2];
|
|
|
- uc_pixel += grayMat.channels();
|
|
|
- }
|
|
|
- }
|
|
|
- if (IsShowWnd) {
|
|
|
- imshow("反色图", grayMat);
|
|
|
- }
|
|
|
- //LineHandle lineHandle;
|
|
|
- Vec4i lineX(0, height / 2, width, height / 2);
|
|
|
- Vec4i lineY(width / 2, 0, width / 2, height);
|
|
|
- /* line(grayMat, Point(0, height / 2), Point(width, height / 2), Scalar(0, 0, 0), 1);
|
|
|
- line(grayMat, Point(width / 2, 0), Point(width / 2, height), Scalar(0, 0, 0), 1);*/
|
|
|
- vector<Point2f> tu1;
|
|
|
- //Mat mat(,)
|
|
|
- Mat darkMat(height, width, CV_8UC3, Scalar(0, 0, 0));
|
|
|
- vector<Vec4i> mylines;
|
|
|
- HoughLinesP(grayMat, mylines, 1, CV_PI / 180, 100, min(height / 6, width / 6), 3);
|
|
|
- for (size_t i = 0; i < mylines.size(); i++)
|
|
|
- {
|
|
|
-
|
|
|
- Vec4i cho_l = mylines[i];
|
|
|
- Point2f crossXPoints;
|
|
|
- LineHandle::crossPointsOfLines(cho_l, lineX, crossXPoints);
|
|
|
- Point2f crossYPoints;
|
|
|
- LineHandle::crossPointsOfLines(cho_l, lineY, crossYPoints);
|
|
|
- if (abs(crossXPoints.x - width / 2) < width / 6 && abs(crossXPoints.y - height / 2) < height / 6)
|
|
|
- {
|
|
|
- line(darkMat, Point(cho_l[0], cho_l[1]), Point(cho_l[2], cho_l[3]), Scalar(255, 0, 0), 10);
|
|
|
- /* circle(grayMat, Point(cho_l[2], cho_l[3]), 2, cv::Scalar(255, 0, 0), -1, cv::FILLED);
|
|
|
- circle(grayMat, Point(cho_l[0], cho_l[1]), 2, cv::Scalar(0, 255, 255), -1, cv::FILLED);*/
|
|
|
- Point2f pt1(cho_l[2] - cho_l[0], cho_l[3] - cho_l[1]);
|
|
|
- Point2f pt2(1, 0);
|
|
|
- float theta = atan2(pt1.x, pt1.y) - atan2(pt2.x, pt2.y);
|
|
|
- if (theta > CV_PI)
|
|
|
- theta -= 2 * CV_PI;
|
|
|
- if (theta < -CV_PI)
|
|
|
- theta += 2 * CV_PI;
|
|
|
- theta = theta * 180.0 / CV_PI;
|
|
|
- float a = pow((cho_l[2] - width / 2), 2) + pow((cho_l[3] - height / 2), 2);
|
|
|
- tu1.push_back(Point2f(sqrtf(a), theta));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
- /*vector< Point2f> sorttu;
|
|
|
- sort(tu1, sorttu,);*/
|
|
|
- Point ptStart(width / 2, 0);
|
|
|
- Point ptCenter(width / 2, height / 2);
|
|
|
- Mat darkMatCopy;
|
|
|
- darkMat.copyTo(darkMatCopy);
|
|
|
-
|
|
|
- vector<pair<int, int>> num_sum;
|
|
|
- //vector<,>
|
|
|
- for (size_t i = 0; i < 360; i++)
|
|
|
- {
|
|
|
- Point ptStart1(ptCenter.x + sin(i * 1 * CV_PI / 180) * (c_cen / 2), ptCenter.y - cos(i * 1 * CV_PI / 180) * (c_cen / 2));
|
|
|
- Point ptStart2(ptCenter.x + sin(i * 1 * CV_PI / 180) * (c_cen / 2 - 100), ptCenter.y - cos(i * 1 * CV_PI / 180) * (c_cen / 2 - 100));
|
|
|
-
|
|
|
- line(darkMatCopy, ptStart2, ptStart1, Scalar(255, 0, 0), 10);
|
|
|
- if (IsShowWnd)
|
|
|
- {
|
|
|
- imshow("test", darkMatCopy);
|
|
|
- waitKey(10);
|
|
|
- }
|
|
|
- int matdis = LineHandle::CalcMatSum(darkMatCopy) - LineHandle::CalcMatSum(darkMat);
|
|
|
- //cout << "像素综合cha " << i << ":" << matdis << endl;
|
|
|
- int angle = i;
|
|
|
- if (angle > 342)
|
|
|
- {
|
|
|
- angle = 360 - angle;
|
|
|
- }
|
|
|
- num_sum.push_back(make_pair(angle, matdis));
|
|
|
- darkMat.copyTo(darkMatCopy);
|
|
|
- }
|
|
|
- sort(num_sum.begin(), num_sum.end(), LineHandle::ComparePairSecond);
|
|
|
- int resultValue = 0;
|
|
|
- int secondPoint = -1;
|
|
|
- for (size_t i = 0; i < num_sum.size(); i++)
|
|
|
- {
|
|
|
-
|
|
|
- if (abs(num_sum[0].first - num_sum[i].first) > 18 && abs(num_sum[0].first - num_sum[i].first) < 342) //360° 0°附近特殊处理
|
|
|
- {
|
|
|
- if (num_sum[i].second < 3 * (num_sum[num_sum.size() - 1].second) / 4)
|
|
|
- {
|
|
|
- secondPoint = num_sum[i].first;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (secondPoint != -1)
|
|
|
- {
|
|
|
- int seondScore = num_sum[0].first / 36;
|
|
|
- if (num_sum[0].first % 36 > 18)
|
|
|
- {
|
|
|
- seondScore += 1;
|
|
|
- }
|
|
|
- int firstScore = secondPoint / 36;
|
|
|
- if (secondPoint % 36 > 18)
|
|
|
- {
|
|
|
- firstScore += 1;
|
|
|
- }
|
|
|
- resultValue = firstScore * 10 + seondScore;
|
|
|
- }
|
|
|
- else if (secondPoint == -1)
|
|
|
- {
|
|
|
- int seondScore = num_sum[0].first / 36;
|
|
|
- if (num_sum[0].first % 36 > 18)
|
|
|
- {
|
|
|
- seondScore += 1;
|
|
|
- }
|
|
|
- resultValue = seondScore * 10 + seondScore;
|
|
|
- }
|
|
|
- return resultValue;
|
|
|
+ string model_path = "models/double_pointer_count.onnx";
|
|
|
+ std::wstring widestr = std::wstring(model_path.begin(), model_path.end());
|
|
|
+ sessionOptions.SetGraphOptimizationLevel(ORT_ENABLE_BASIC);
|
|
|
+ ort_session = new Session(env, widestr.c_str(), sessionOptions);
|
|
|
+ size_t numInputNodes = ort_session->GetInputCount();
|
|
|
+ size_t numOutputNodes = ort_session->GetOutputCount();
|
|
|
+ AllocatorWithDefaultOptions allocator;
|
|
|
+ for (int i = 0; i < numInputNodes; i++)
|
|
|
+ {
|
|
|
+ input_names.push_back(ort_session->GetInputName(i, allocator));
|
|
|
+ Ort::TypeInfo input_type_info = ort_session->GetInputTypeInfo(i);
|
|
|
+ auto input_tensor_info = input_type_info.GetTensorTypeAndShapeInfo();
|
|
|
+ auto input_dims = input_tensor_info.GetShape();
|
|
|
+ input_node_dims.push_back(input_dims);
|
|
|
+ }
|
|
|
+ for (int i = 0; i < numOutputNodes; i++)
|
|
|
+ {
|
|
|
+ output_names.push_back(ort_session->GetOutputName(i, allocator));
|
|
|
+ Ort::TypeInfo output_type_info = ort_session->GetOutputTypeInfo(i);
|
|
|
+ auto output_tensor_info = output_type_info.GetTensorTypeAndShapeInfo();
|
|
|
+ auto output_dims = output_tensor_info.GetShape();
|
|
|
+ output_node_dims.push_back(output_dims);
|
|
|
+ }
|
|
|
+ this->inpHeight = input_node_dims[0][2];
|
|
|
+ this->inpWidth = input_node_dims[0][3];
|
|
|
+ this->outHeight = output_node_dims[0][2];
|
|
|
+ this->outWidth = output_node_dims[0][3];
|
|
|
}
|
|
|
|
|
|
+int DoublePointerCountALGO::detect(Mat& srcimg)
|
|
|
+{
|
|
|
+ vector<float> input_image_ = { 1, 3, 512, 512 };
|
|
|
+ Mat dstimg;
|
|
|
+ Size resize_size(input_image_[2], input_image_[3]);
|
|
|
+ resize(srcimg, dstimg, resize_size, 0, 0, cv::INTER_LINEAR);
|
|
|
+ int channels = dstimg.channels();
|
|
|
+ input_image_.resize((this->inpWidth * this->inpHeight * dstimg.channels()));
|
|
|
+
|
|
|
+ for (int c = 0; c < channels; c++)
|
|
|
+ {
|
|
|
+ for (int i = 0; i < this->inpHeight; i++)
|
|
|
+ {
|
|
|
+ for (int j = 0; j < this->inpWidth; j++)
|
|
|
+ {
|
|
|
+ float pix = dstimg.ptr<uchar>(i)[j * 3 + 2 - c];
|
|
|
+ input_image_[(c * this->inpHeight * this->inpWidth + i * this->inpWidth + j)] = (pix / 255.0 - mean[c]) / stds[c];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ array<int64_t, 4> input_shape_{ 1, 3, this->inpHeight, this->inpWidth };
|
|
|
+ auto allocator_info = MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
|
|
|
+ Value input_tensor_ = Value::CreateTensor<float>(allocator_info, input_image_.data(), input_image_.size(), input_shape_.data(), input_shape_.size());
|
|
|
+
|
|
|
+ // 开始推理
|
|
|
+ vector<Value> ort_outputs = ort_session->Run(RunOptions{ nullptr }, &input_names[0], &input_tensor_, 1, output_names.data(), output_names.size());
|
|
|
+ float* pred = ort_outputs[0].GetTensorMutableData<float>();
|
|
|
+ Mat result(outHeight, outWidth, CV_32FC1, pred);
|
|
|
+ result = 2 - result;
|
|
|
+ result *= 255;
|
|
|
+ result.convertTo(result, CV_8UC1);
|
|
|
+ Mat binary;
|
|
|
+ threshold(result, binary, 150, 255, THRESH_BINARY);//二值化阈值处理
|
|
|
+ //形态学变换
|
|
|
+ Mat Sobel_Y_thres;
|
|
|
+ Mat element = cv::getStructuringElement(MORPH_RECT, Size(1, 1));
|
|
|
+ morphologyEx(binary, Sobel_Y_thres, cv::MORPH_OPEN, element, Point(-1, -1), 2);
|
|
|
+ Mat result_line_image = creat_line_image(Sobel_Y_thres, 256, 130);
|
|
|
+ /*namedWindow("矩形", WINDOW_NORMAL);
|
|
|
+ imshow("矩形", result_line_image);
|
|
|
+ waitKey(0);*/
|
|
|
+ return get_meter_reader(result_line_image);
|
|
|
+ //return result;
|
|
|
+}
|
|
|
+
|
|
|
+Mat DoublePointerCountALGO::creat_line_image(const Mat& circle, int Radius, int RingStride)
|
|
|
+{
|
|
|
+ Mat rectangle;
|
|
|
+ float theta;
|
|
|
+ int rho;
|
|
|
+
|
|
|
+ rectangle = Mat::zeros(Size(Radius * pi * 2, RingStride), CV_8UC1);
|
|
|
+ int nl = rectangle.rows; // number of lines
|
|
|
+ int nc = rectangle.cols * rectangle.channels(); // total number of elements per line
|
|
|
+ for (int j = 0; j < nl; j++) {
|
|
|
+ // get the address of row j
|
|
|
+ uchar* data = rectangle.ptr<uchar>(j);
|
|
|
+ for (int i = 0; i < nc; i++)
|
|
|
+ {
|
|
|
+ theta = pi * 2.0 / LINE_WIDTH * float(i + 1);
|
|
|
+ rho = (Radius - j - 1);
|
|
|
+ int position_y = (float)circle_center[0] + rho * (float)std::cos(theta) + 0.5;
|
|
|
+ int position_x = (float)circle_center[1] - rho * (float)std::sin(theta) + 0.5;
|
|
|
+ data[i] = circle.at<uchar>(position_y, position_x);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return rectangle;
|
|
|
+}
|
|
|
+
|
|
|
+//像素值提取及累加
|
|
|
+int DoublePointerCountALGO::get_meter_reader(const Mat& image)
|
|
|
+{
|
|
|
+ Mat histogram = Mat::zeros(Size(256, 1), CV_8UC1);
|
|
|
+ int rows = LINE_HEIGH; //输入图像的行数
|
|
|
+ int cols = LINE_WIDTH; //输入图像的列数
|
|
|
+ int sum_horsum = 0; //水平方向列相加和
|
|
|
+ int long_pointer = 0;
|
|
|
+ int short_pointer = 0;
|
|
|
+ int METER_RANGE = 9;
|
|
|
+
|
|
|
+ //按矩形计算像素值
|
|
|
+ vector<int>num1;
|
|
|
+ vector<int>num_cols;
|
|
|
+ vector<int>num3;
|
|
|
+ vector<int>num_pixel;
|
|
|
+ for (int c = 0; c < cols; c++)
|
|
|
+ {
|
|
|
+ int versum = 0;
|
|
|
+ for (int r = 0; r < rows; r++)
|
|
|
+ {
|
|
|
+ int index = int(image.at<uchar>(r, c));
|
|
|
+ versum += index;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (versum != 0)
|
|
|
+ {
|
|
|
+ sum_horsum += versum;
|
|
|
+ num1.push_back(c); //列索引
|
|
|
+ num3.push_back(sum_horsum); //像素累加
|
|
|
+ }
|
|
|
+ if (versum == 0)
|
|
|
+ {
|
|
|
+ //列索引
|
|
|
+ int maxValue1 = 0;
|
|
|
+ for (auto v : num1)
|
|
|
+ {
|
|
|
+ if (maxValue1 < v) maxValue1 = v;
|
|
|
+ }
|
|
|
+ if (maxValue1 != 0)
|
|
|
+ {
|
|
|
+ num_cols.push_back(maxValue1);
|
|
|
+ }
|
|
|
+ vector<int>().swap(num1);
|
|
|
+
|
|
|
+ //像素
|
|
|
+ int maxValue2 = 0;
|
|
|
+ for (auto v : num3)
|
|
|
+ {
|
|
|
+ if (maxValue2 < v) maxValue2 = v;
|
|
|
+ }
|
|
|
+ if (maxValue2 != 0)
|
|
|
+ {
|
|
|
+ num_pixel.push_back(maxValue2);
|
|
|
+ }
|
|
|
+ sum_horsum = 0;
|
|
|
+ vector<int>().swap(num3);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //标记长短指针
|
|
|
+ auto firstValue1 = num_pixel.front();
|
|
|
+ auto lastValue1 = num_pixel.back();
|
|
|
+ //长短指针取值
|
|
|
+ auto firstValue2 = num_cols.front() - 30;
|
|
|
+ auto lastValue2 = num_cols.back() - 30;
|
|
|
+ //赋值于长短指针
|
|
|
+ if (firstValue1 < lastValue1)
|
|
|
+ {
|
|
|
+ short_pointer = firstValue2;
|
|
|
+ long_pointer = lastValue2;
|
|
|
+ }else
|
|
|
+ {
|
|
|
+ short_pointer = lastValue2;
|
|
|
+ long_pointer = firstValue2;
|
|
|
+ }
|
|
|
+
|
|
|
+ //计算表盘读数
|
|
|
+ float rectangle_value = 1650;
|
|
|
+ float short_result_ratio = (1.0 * short_pointer / rectangle_value);
|
|
|
+ float long_result_ratio = (1.0 * long_pointer / rectangle_value);
|
|
|
+ float short_result_value = (1.0 * short_result_ratio * METER_RANGE) - 4;
|
|
|
+ if (short_result_value < 0)
|
|
|
+ {
|
|
|
+ short_result_value += 9;
|
|
|
+ }
|
|
|
+ float long_result_value = (1.0 * long_result_ratio * METER_RANGE) - 4;
|
|
|
+ if (long_result_value < 0)
|
|
|
+ {
|
|
|
+ long_result_value += 9;
|
|
|
+ }
|
|
|
+ //四舍五入取整
|
|
|
+ if (short_result_value > 0)
|
|
|
+ {
|
|
|
+ short_result_value = short_result_value - int(short_result_value) >= 0.5 ? int(short_result_value) + 1 : int(short_result_value);
|
|
|
+ }else
|
|
|
+ {
|
|
|
+ short_result_value = -short_result_value - int(-short_result_value) >= 0.5 ? -(int(-short_result_value) + 1) : -int(-short_result_value);
|
|
|
+ }
|
|
|
+ if (long_result_value > 0)
|
|
|
+ {
|
|
|
+ long_result_value = long_result_value - int(long_result_value) >= 0.5 ? int(long_result_value) + 1 : int(long_result_value);
|
|
|
+ }else
|
|
|
+ {
|
|
|
+ long_result_value = -long_result_value - int(-long_result_value) >= 0.5 ? -(int(-long_result_value) + 1) : -int(-long_result_value);
|
|
|
+ }
|
|
|
+ //cout << "short_result_ratio:" << short_result_ratio << " long_result_ratio:" << long_result_ratio << endl;
|
|
|
+ cout << "short_result_value:" << short_result_value << " long_result_value:" << long_result_value << endl;
|
|
|
+ int result = (short_result_value * 10) + long_result_value;
|
|
|
+ cout << "读数:" << result << endl;
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|