Jelajahi Sumber

Merge branch 'master' of http://192.168.110.57:3000/guor/ImageRecognition

郭睿 1 tahun lalu
induk
melakukan
931c460a6e

+ 179 - 0
AmpereMeterALGO.cpp

@@ -0,0 +1,179 @@
+#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 "AmpereMeterALGO.h"
+#include <vector>
+
+void AmpereMeterALGO::Init(bool isCuda)
+{
+	string model_path = "models/VoltageAmpereMeter.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];
+}
+
+float AmpereMeterALGO::detect(Mat& srcimg)
+{
+	/*namedWindow("矩形", WINDOW_NORMAL);
+	imshow("矩形", srcimg);
+	waitKey(0);*/
+	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 = 3 - result;
+	result *= 255;
+	result.convertTo(result, CV_8UC1);
+	Mat binary;
+	threshold(result, binary, 150, 255, THRESH_BINARY);//二值化阈值处理
+	Mat result_line_image = creat_line_image(binary, 258, 128);
+	/*namedWindow("矩形", WINDOW_NORMAL);
+	imshow("矩形", result_line_image);
+	waitKey(0);*/
+	return get_meter_reader(result_line_image);
+}
+
+Mat AmpereMeterALGO::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
+		try
+		{
+			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);
+			}
+		}
+		catch (exception &e) { /* Please, at least do some logging or other error handling here*/ }
+	}
+	return rectangle;
+}
+
+//像素值提取及累加
+float AmpereMeterALGO::get_meter_reader(const Mat& image)
+{
+	Mat histogram = Mat::zeros(Size(256, 1), CV_8UC1);    	 												 
+	int rows = LINE_HEIGH;  	 //输入图像的行数
+	int cols = LINE_WIDTH; 		 //输入图像的列数
+	int scale_num = 0;
+	int pointer_num = 0;
+	int sum_horsum = 0;   //水平方向列相加和
+	
+	vector<int>num1;      
+	vector<int>num2;     
+	for (int c = 0; c < 1696; c++)
+	{
+		int versum = 0;
+		for (int r = 0; r < rows; r++)
+		{
+			int index = int(image.at<uchar>(r, c));	
+			versum += index;                        
+		}
+		if (versum != 0)
+		{
+			//int max_sum_horsum = 0;
+			sum_horsum += versum;
+			//cout << "和:" << sum_horsum << endl;
+			num1.push_back(sum_horsum);
+		}
+		if (versum == 0)
+		{
+			int maxValue = 0;
+			for (auto v : num1) 
+			{
+				if (maxValue < v) maxValue = v;
+			}
+			if (maxValue != 0)
+			{
+				//cout << "最大值:" << maxValue << endl;
+				num2.push_back(maxValue);
+			}
+			sum_horsum = 0;            
+			vector<int>().swap(num1);  
+		}
+	}
+
+	//计算表盘读数
+	int maxPosition = max_element(num2.begin(), num2.end()) - num2.begin();
+    scale_num = num2.size();
+	pointer_num = maxPosition ;
+	float result_ratio = (1.0 * pointer_num  / scale_num );
+	float result_value = (result_ratio * METER_RANGE);
+	if (result_value > 0)
+	{
+		result_value += 2;
+	}
+	cout << "scale_num:" << scale_num << "  pointer_num:" << pointer_num << "  result_ratio:" << result_ratio << "  result_value:" << result_value << endl;
+	return result_value;
+}
+
+
+
+

+ 49 - 0
AmpereMeterALGO.h

@@ -0,0 +1,49 @@
+#pragma once
+#define _CRT_SECURE_NO_WARNINGS
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <math.h>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/highgui.hpp>
+#include <onnxruntime_cxx_api.h>
+
+using namespace Ort;
+using namespace cv;
+using namespace std;
+using namespace Ort;
+
+const float pi = 3.1415926536f;
+const int circle_center[] = { 270, 290 };  //center position[310,320]
+#define SEG_IMAGE_SIZE 512
+#define LINE_HEIGH 120
+#define LINE_WIDTH 1696
+#define CIRCLE_RADIUS 250
+#define METER_RANGE 30
+
+class AmpereMeterALGO
+{
+public:
+	void Init (bool isCuda);
+	float detect(Mat& cv_image);
+	Mat creat_line_image(const Mat& circle,int Radius, int RingStride);
+	float get_meter_reader(const Mat& image);
+	
+private:
+	int inpWidth;
+	int inpHeight;
+	int outWidth;
+	int outHeight;
+
+	vector<float> input_image_ = { 1, 3, 512, 512 };
+	const float mean[3] = { 0.5f, 0.5f, 0.5f };
+	const float stds[3] = { 0.5f, 0.5f, 0.5f };
+
+	Env env = Env(ORT_LOGGING_LEVEL_ERROR, "u2net");
+	Ort::Session* ort_session = nullptr;
+	SessionOptions sessionOptions = SessionOptions();
+	vector<char*> input_names;
+	vector<char*> output_names;
+	vector<vector<int64_t>> input_node_dims; // >=1 outputs
+	vector<vector<int64_t>> output_node_dims; // >=1 outputs
+};

+ 2 - 2
CharacterDectect.h

@@ -18,8 +18,8 @@ private:
 	cv::dnn::Net net;
 	
 	const std::vector<std::string> className = {
-		"on",
-					   "off",
+		                "on",
+					    "off",
 						"stored_energy",
 						"stored_energy_graphics",
 						"green_on",

+ 0 - 1
DisconnectorDectect.cpp

@@ -118,7 +118,6 @@ bool DisconnectorDectect::Detect(cv::Mat& SrcImg) {
 			}
 		}
 	}
-
 	//执行非最大抑制以消除具有较低置信度的冗余重叠框(NMS)
 	vector<int> nms_result;
 	cv::dnn::NMSBoxes(boxes, confidences, nmsScoreThreshold, nmsThreshold, nms_result);

+ 231 - 160
DoublePointerCountALGO.cpp

@@ -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;
+}
+
+
+
+

+ 39 - 3
DoublePointerCountALGO.h

@@ -1,9 +1,45 @@
 #pragma once
-#include <opencv2/highgui.hpp>
+#define _CRT_SECURE_NO_WARNINGS
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <math.h>
 #include <opencv2/imgproc.hpp>
+#include <opencv2/highgui.hpp>
+#include <onnxruntime_cxx_api.h>
+
+using namespace cv;
+using namespace std;
+using namespace Ort;
+
+#define SEG_IMAGE_SIZE 512
+#define LINE_HEIGH 120
+#define LINE_WIDTH 1600
+#define CIRCLE_RADIUS 250
+//#define METER_RANGE 9
+
 class DoublePointerCountALGO
 {
 public:
-	int GetResult(cv::Mat sourceMat, bool IsShowWnd = true);
-};
+	void Init(bool isCuda);
+	int detect(Mat& cv_image);
+	Mat creat_line_image(const Mat& circle,int Radius, int RingStride);
+	int get_meter_reader(const Mat& image);
+private:
+	int inpWidth;
+	int inpHeight;
+	int outWidth;
+	int outHeight;
+	const float pi = 3.1415926536f;
+	const int circle_center[2] = { 256, 256 };//300,238  300,255 
+	const float mean[3] = {0,0,0};
+	const float stds[3] = {0.9f,0.9f,0.9f};
 
+	Env env = Env(ORT_LOGGING_LEVEL_ERROR, "u2net");
+	Ort::Session* ort_session = nullptr;
+	SessionOptions sessionOptions = SessionOptions();
+	vector<char*> input_names;
+	vector<char*> output_names;
+	vector<vector<int64_t>> input_node_dims; // >=1 outputs
+	vector<vector<int64_t>> output_node_dims; // >=1 outputs
+};

+ 9 - 0
DoublePointerCountALGO1.h

@@ -0,0 +1,9 @@
+#pragma once
+#include <opencv2/highgui.hpp>
+#include <opencv2/imgproc.hpp>
+class DoublePointerCountALGO
+{
+public:
+	int GetResult(cv::Mat sourceMat, bool IsShowWnd = true);
+};
+

+ 165 - 0
DoublePointerCountALGO原版.cpp

@@ -0,0 +1,165 @@
+#include "DoublePointerCountALGO.h"
+#include "LineHandle.h"
+using namespace std;
+using namespace cv;
+int DoublePointerCountALGO::GetResult(cv::Mat sourceMat, bool IsShowWnd)
+{
+    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;
+}
+

+ 1 - 2
DoubleTemperatureGuageALGO.cpp

@@ -5,7 +5,6 @@
 using namespace cv;
 using namespace std;
 using namespace Ort;
-
 void DoubleTemperatureGuageALGO::Init(bool IsCuda)
 {
 	string model_path = "models/double_temperature_guage.onnx";
@@ -39,7 +38,7 @@ void DoubleTemperatureGuageALGO::Init(bool IsCuda)
 
 pair<float, float> DoubleTemperatureGuageALGO::detect(Mat& srcimg,int MaxRange)
 {
-	METER_RANGE = MaxRange;
+    METER_RANGE = MaxRange;
 	vector<float> input_image_ = { 1, 3, 512, 512 };
 	Mat dstimg;
 	Size resize_size(input_image_[2], input_image_[3]);

+ 2 - 0
JdydAlgorithnm.h

@@ -25,6 +25,7 @@
 #include "InstructionsDectect.h"
 #include "ContactDectect.h"
 #include "TriangleDisconnectorDectect.h"
+#include "OperatingHandleStateDectect.h"
 
 
 using namespace std;
@@ -51,5 +52,6 @@ public:
 	static DisconnectorStateDectect& GetdisconnectorStateDectectInstance();
 	static ElectronPlateDectect& GetelectronPlateDectectInstance();
 	static NumberDectect& GeNumberDectectInstance();
+	static OperatingHandleStateDectect& GetoperatingHandleStateDectectInstance();
 };
 

+ 25 - 4
MeterDectect.cpp

@@ -5,12 +5,17 @@
 #include "ArresterCircularZeroThreeALGO.h"
 #include "CircularOilSinglePointALGO.h"
 #include "DoubleTemperatureGuageALGO.h"
+#include "AmpereMeterALGO.h"
+#include "VoltageMeterALGO.h"
 
 using namespace std;
 static  AtmosphericPressureALGO atmosphericPressureALGO;
 static CircularArresterCurrentALGO circularArresterCurrentALGO;
 static  CircularOilSinglePointALGO circularOilSinglePointALGO;
 static  DoubleTemperatureGuageALGO doubleTemperatureGuageALGO;
+static  AmpereMeterALGO ampereMeterALGO;
+static  VoltageMeterALGO voltageMeterALGO;
+static  DoublePointerCountALGO doublePointerCountALGO;
 
 bool MeterDectect::Init(bool isCuda)
 {
@@ -21,6 +26,9 @@ bool MeterDectect::Init(bool isCuda)
 		circularArresterCurrentALGO.Init();
 		circularOilSinglePointALGO.Init(isCuda);
 		doubleTemperatureGuageALGO.Init(isCuda);
+		ampereMeterALGO.Init(isCuda);
+		voltageMeterALGO.Init(isCuda);
+		doublePointerCountALGO.Init(isCuda);
 	}
 	catch (const std::exception& ex)
 	{
@@ -183,7 +191,7 @@ bool MeterDectect::Detect(cv::Mat& SrcImg)
 			result.box = boxes[idx];*/
 			output.push_back(result);
 
-			if (className[classIds[idx]] == "circular_arrester_current")
+			if (className[classIds[idx]] == "rect_arrester_current")
 			{
 				auto tempResultValue = DectectResult(confidences[idx], 0, className[classIds[idx]]);
 				auto resValue = circularArresterCurrentALGO.detect(SrcImg);
@@ -205,7 +213,7 @@ bool MeterDectect::Detect(cv::Mat& SrcImg)
 				auto tempResultValue = DectectResult(confidences[idx], 0, className[classIds[idx]]);
 				resultValues.push_back(tempResultValue);
 			}
-			else if (className[classIds[idx]] == "rect_arrester_current") //0-3mA±ÜÀ×Æ÷µçÁ÷
+			else if (className[classIds[idx]] == "circular_arrester_current") //0-3mA±ÜÀ×Æ÷µçÁ÷
 			{
 				auto tempResultValue = DectectResult(confidences[idx], 0, className[classIds[idx]]);
 				ArresterCircularZeroThreeALGO* algo = new ArresterCircularZeroThreeALGO;
@@ -214,12 +222,19 @@ bool MeterDectect::Detect(cv::Mat& SrcImg)
 				delete algo;
 				resultValues.push_back(tempResultValue);
 			}
-			else if (className[classIds[idx]] == "quarter_square_ammeter")
+			else if (className[classIds[idx]] == "ampere_meter")
 			{
 				auto tempResultValue = DectectResult(confidences[idx], 0, className[classIds[idx]]);
+				tempResultValue.m_dValue = ampereMeterALGO.detect(SrcImg);
 				resultValues.push_back(tempResultValue);
 			}
-			else if (className[classIds[idx]] == "double_pointer_count")
+			else if (className[classIds[idx]] == "voltage_meter")
+			{
+				auto tempResultValue = DectectResult(confidences[idx], 0, className[classIds[idx]]);
+				tempResultValue.m_dValue = voltageMeterALGO.detect(SrcImg);
+				resultValues.push_back(tempResultValue);
+			}
+			/*else if (className[classIds[idx]] == "double_pointer_count1")
 			{
 				auto tempResultValue = DectectResult(confidences[idx], 0, className[classIds[idx]]);
 				DoublePointerCountALGO* doublePointerCountALGO = new DoublePointerCountALGO();
@@ -228,6 +243,12 @@ bool MeterDectect::Detect(cv::Mat& SrcImg)
 				delete doublePointerCountALGO;
 				resultValues.push_back(tempResultValue);
 
+			}*/
+			else if (className[classIds[idx]] == "double_pointer_count")
+			{
+				auto tempResultValue = DectectResult(confidences[idx], 0, className[classIds[idx]]);
+				tempResultValue.m_dValue = doublePointerCountALGO.detect(SrcImg);
+				resultValues.push_back(tempResultValue);
 			}
 			else if (className[classIds[idx]] == "transformers_oil_surface_thermometer")
 			{

+ 13 - 2
MeterDectect.h

@@ -17,7 +17,7 @@ private:
     vector<Output> output;
 	cv::dnn::Net net;
 
-	const std::vector<std::string> className = {
+	/*const std::vector<std::string> className = {
          "circular_arrester_current",
         "atmospheric_pressure",
         "digital_gear",
@@ -30,6 +30,17 @@ private:
         "round_single_point_oil_level",
         "oil_thermometer",
         "old_oil_thermometer",
-	};
+	};*/
+    const vector<std::string> className = { 
+        "atmospheric_pressure", 
+        "ampere_meter",
+        "transformers_oil_surface_thermometer",
+        "rect_arrester_current",
+        "double_pointer_count",
+        "round_single_point_oil_level",
+        "voltage_meter",
+        "oil_thermometer",
+        "open",
+        "close" };
 };
 

+ 151 - 0
OperatingHandleStateDectect.cpp

@@ -0,0 +1,151 @@
+#include "OperatingHandleStateDectect.h"
+using namespace std;
+
+bool OperatingHandleStateDectect::Init(bool isCuda)
+{
+	string model_path = "models/operating_handle-sim.onnx";
+	try {
+		net = cv::dnn::readNet(model_path);
+	}
+	catch (const std::exception& ex)
+	{
+		YunDaISASImageRecognitionService::ConsoleLog(ex.what());
+		return false;
+	}
+	//cuda
+	if (isCuda) {
+		net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
+		net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA_FP16);
+	}
+	//cpu
+	else {
+		net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
+		net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
+	}
+	return true;
+
+}
+IDetection::DectectResult OperatingHandleStateDectect::GetStateResult(cv::Mat img, cv::Rect rec)
+{
+	//resultValue.clear();
+	std::cout << "test" << std::endl;
+	try
+	{
+		cv::Mat ROI = img(rec);
+		/*imwrite("test.png", ROI);
+		YunDaISASImageRecognitionService::SetImage(QString::fromStdString("test.png"));*/
+		Detect(ROI);
+	}
+	catch (const std::exception& ex)
+	{
+		YunDaISASImageRecognitionService::ConsoleLog(ex.what());
+	}
+	if (resultValue.m_confidence < 0.1)
+	{
+		resultValue = DectectResult(0.45, 0, className[1]);
+	}
+	return resultValue;
+}
+IDetection::DectectResult OperatingHandleStateDectect::GetDigitResult(cv::Mat img, cv::Rect rec)
+{
+	return resultValue;
+}
+bool OperatingHandleStateDectect::Detect(cv::Mat& SrcImg) {
+	cv::Mat blob;
+	int col = SrcImg.cols;
+	int row = SrcImg.rows;
+	int maxLen = MAX(col, row);
+	cv::Mat netInputImg = SrcImg.clone();
+	if (maxLen > 1.2 * col || maxLen > 1.2 * row) {
+		cv::Mat resizeImg = cv::Mat::zeros(maxLen, maxLen, CV_8UC3);
+		SrcImg.copyTo(resizeImg(cv::Rect(0, 0, col, row)));
+		netInputImg = resizeImg;
+	}
+	cv::dnn::blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(netWidth, netHeight), cv::Scalar(0, 0, 0), true, false);
+	net.setInput(blob);
+	std::vector<cv::Mat> netOutputImg;
+	net.forward(netOutputImg, net.getUnconnectedOutLayersNames());
+	std::vector<int> classIds;//结果id数组
+	std::vector<float> confidences;//结果每个id对应置信度数组
+	std::vector<cv::Rect> boxes;//每个id矩形框
+	float ratio_h = (float)netInputImg.rows / netHeight;
+	float ratio_w = (float)netInputImg.cols / netWidth;
+	int net_width = className.size() + 5;  //输出的网络宽度是类别数+5
+	float* pdata = (float*)netOutputImg[0].data;
+	for (int stride = 0; stride < strideSize; stride++) {    //stride
+		int grid_x = (int)(netWidth / netStride[stride]);
+		int grid_y = (int)(netHeight / netStride[stride]);
+		for (int anchor = 0; anchor < 3; anchor++) {	//anchors
+			const float anchor_w = netAnchors[stride][anchor * 2];
+			const float anchor_h = netAnchors[stride][anchor * 2 + 1];
+			for (int i = 0; i < grid_y; i++) {
+				for (int j = 0; j < grid_x; j++) {
+					float box_score = pdata[4]; ;//获取每一行的box框中含有某个物体的概率
+					if (box_score >= boxThreshold) {
+						cv::Mat scores(1, className.size(), CV_32FC1, pdata + 5);
+						cv::Point classIdPoint;
+						double max_class_socre;
+						minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);
+						max_class_socre = (float)max_class_socre;
+						if (max_class_socre >= classThreshold)
+						{
+							//rect [x,y,w,h]
+							float x = pdata[0];  //x
+							float y = pdata[1];  //y
+							float w = pdata[2];  //w
+							float h = pdata[3];  //h
+							int left = (x - 0.5 * w) * ratio_w;
+							int top = (y - 0.5 * h) * ratio_h;
+
+							int widthBox = int(w * ratio_w);
+							int heightBox = int(h * ratio_h);
+							widthBox = widthBox > col ? col : widthBox;
+							heightBox = heightBox > row ? row : heightBox;
+							left = left < 0 ? 0 : left;
+							top = top < 0 ? 0 : top;
+							if (left < 0 || left>col || top < 0 || top>row || widthBox > col || heightBox > row)
+							{
+								continue;
+							}
+							classIds.push_back(classIdPoint.x);
+							confidences.push_back(max_class_socre * box_score);
+							boxes.push_back(cv::Rect(left, top, widthBox, heightBox));
+						}
+					}
+					pdata += net_width;//下一行
+				}
+			}
+		}
+	}
+
+	//执行非最大抑制以消除具有较低置信度的冗余重叠框(NMS)
+	vector<int> nms_result;
+	cv::dnn::NMSBoxes(boxes, confidences, nmsScoreThreshold, nmsThreshold, nms_result);
+	float confidenceMax = 0;
+	int confidenceMaxId = 0;
+	if (nms_result.size() > 0)
+	{
+		for (int i = 0; i < nms_result.size(); i++) {
+			int idx = nms_result[i];
+			if (confidences[idx] > confidenceMax)
+			{
+				confidenceMax = confidences[idx];
+
+				resultValue = DectectResult(confidenceMax, 0, className[classIds[idx]]);
+			}
+			YunDaISASImageRecognitionService::ConsoleLog(QString::fromStdString(className[classIds[idx]]));
+			//resultValue.push_back(DectectResult(, 0, className[classIds[idx]]));
+		}
+	}
+	else
+	{
+		resultValue = DectectResult(confidenceMax, 0, className[1]);
+	}
+
+	return true;
+
+}
+
+
+
+

+ 21 - 0
OperatingHandleStateDectect.h

@@ -0,0 +1,21 @@
+#pragma once
+#include "IDetection.h"
+
+class OperatingHandleStateDectect :IDetection
+{
+
+public:
+	IDetection::DectectResult GetStateResult(cv::Mat img, cv::Rect rec);
+	IDetection::DectectResult GetDigitResult(cv::Mat img, cv::Rect rec);
+
+	bool Detect(cv::Mat& SrcImg);
+	bool Init(bool isCuda);
+private:
+	IDetection::DectectResult resultValue;
+	cv::dnn::Net net;
+
+	const std::vector<std::string> className = {
+		"on",
+	};
+};
+

+ 176 - 0
VoltageMeterALGO.cpp

@@ -0,0 +1,176 @@
+#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 "VoltageMeterALGO.h"
+#include <vector>
+
+void VoltageMeterALGO::Init(bool isCuda)
+{
+	string model_path = "models/VoltageAmpereMeter.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];
+}
+
+float VoltageMeterALGO::detect(Mat& srcimg)
+{
+	/*namedWindow("矩形", WINDOW_NORMAL);
+	imshow("矩形", srcimg);
+	waitKey(0);*/
+	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 = 3 - result;
+	result *= 255;
+	result.convertTo(result, CV_8UC1);
+	/*namedWindow("矩形", WINDOW_NORMAL);
+	imshow("矩形", result);
+	waitKey(0);*/
+	Mat result_line_image = creat_line_image(result, 240, 128);
+	/*namedWindow("矩形", WINDOW_NORMAL);
+	imshow("矩形", result_line_image);
+	waitKey(0);*/
+	return get_meter_reader(result_line_image);
+}
+
+Mat VoltageMeterALGO::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
+		try
+		{
+			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);
+			}
+		}
+		catch (exception &e) { /* Please, at least do some logging or other error handling here*/ }
+	}
+	return rectangle;
+}
+
+//像素值提取及累加
+float VoltageMeterALGO::get_meter_reader(const Mat& image)
+{
+	Mat histogram = Mat::zeros(Size(256, 1), CV_8UC1);    	 												 
+	int rows = LINE_HEIGH;  	 //输入图像的行数
+	int cols = LINE_WIDTH; 		 //输入图像的列数
+	int scale_num = 0;
+	int pointer_num = 0;
+	int sum_horsum = 0;   //水平方向列相加和
+	
+	vector<int>num1;      
+	vector<int>num2;     
+	for (int c = 0; c < 1696; c++)
+	{
+		int versum = 0;
+		for (int r = 0; r < rows; r++)
+		{
+			int index = int(image.at<uchar>(r, c));	
+			versum += index;                        
+		}
+		if (versum != 0)
+		{
+			//int max_sum_horsum = 0;
+			sum_horsum += versum;
+			//cout << "和:" << sum_horsum << endl;
+			num1.push_back(sum_horsum);
+		}
+		if (versum == 0)
+		{
+			int maxValue = 0;
+			for (auto v : num1) 
+			{
+				if (maxValue < v) maxValue = v;
+			}
+			if (maxValue != 0)
+			{
+				//cout << "最大值:" << maxValue << endl;
+				num2.push_back(maxValue);
+			}
+			sum_horsum = 0;            
+			vector<int>().swap(num1);  
+		}
+	}
+
+	//计算表盘读数
+	int maxPosition = max_element(num2.begin(), num2.end()) - num2.begin();
+    scale_num = num2.size();
+	pointer_num = maxPosition ;
+	float result_ratio = (1.0 * pointer_num  / scale_num );
+	float result_value = (result_ratio * METER_RANGE);
+	cout << "scale_num:" << scale_num << "  pointer_num:" << pointer_num << "  result_ratio:" << result_ratio << "  result_value:" << result_value << endl;
+	return result_value;
+}
+
+
+
+

+ 47 - 0
VoltageMeterALGO.h

@@ -0,0 +1,47 @@
+#pragma once
+#define _CRT_SECURE_NO_WARNINGS
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <math.h>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/highgui.hpp>
+#include <onnxruntime_cxx_api.h>
+
+using namespace Ort;
+using namespace cv;
+using namespace std;
+using namespace Ort;
+
+#define SEG_IMAGE_SIZE 512
+#define LINE_HEIGH 120
+#define LINE_WIDTH 1696
+#define CIRCLE_RADIUS 250
+#define METER_RANGE 150
+
+class VoltageMeterALGO
+{
+public:
+	void Init (bool isCuda);
+	float detect(Mat& cv_image);
+	Mat creat_line_image(const Mat& circle,int Radius, int RingStride);
+	float get_meter_reader(const Mat& image);
+	
+private:
+	int inpWidth;
+	int inpHeight;
+	int outWidth;
+	int outHeight;
+	const float pi = 3.1415926536f;
+	const int circle_center[2] = { 280, 300 };  //center position[310,320]
+	const float mean[3] = { 0.5f, 0.5f, 0.5f };
+	const float stds[3] = { 0.5f, 0.5f, 0.5f };
+
+	Env env = Env(ORT_LOGGING_LEVEL_ERROR, "u2net");
+	Ort::Session* ort_session = nullptr;
+	SessionOptions sessionOptions = SessionOptions();
+	vector<char*> input_names;
+	vector<char*> output_names;
+	vector<vector<int64_t>> input_node_dims; // >=1 outputs
+	vector<vector<int64_t>> output_node_dims; // >=1 outputs
+};

+ 10 - 4
YunDa.ISAS.Image.Recognition.Service.vcxproj

@@ -21,12 +21,12 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
-    <PlatformToolset>v143</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
-    <PlatformToolset>v143</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
@@ -34,12 +34,12 @@
     <Import Project="$(QtMsBuild)\qt_defaults.props" />
   </ImportGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
-    <QtInstall>5.13.0_msvc2017_64</QtInstall>
+    <QtInstall>msvc2017_64</QtInstall>
     <QtModules>core;gui;widgets</QtModules>
     <QtBuildConfig>debug</QtBuildConfig>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
-    <QtInstall>5.13.0_msvc2017_64</QtInstall>
+    <QtInstall>msvc2017_64</QtInstall>
     <QtModules>core;gui;widgets</QtModules>
     <QtBuildConfig>release</QtBuildConfig>
   </PropertyGroup>
@@ -130,9 +130,12 @@
     <ClCompile Include="NumberDectect.cpp" />
     <ClCompile Include="OilLevelDectect.cpp" />
     <ClCompile Include="ArresterCircularZeroThreeALGO.cpp" />
+    <ClCompile Include="OperatingHandleStateDectect.cpp" />
     <ClCompile Include="PressplateDectect.cpp" />
     <ClCompile Include="TriangleDisconnectorDectect.cpp" />
     <ClCompile Include="UpdateUI.cpp" />
+    <ClCompile Include="AmpereMeterALGO.cpp" />
+    <ClCompile Include="VoltageMeterALGO.cpp" />
     <ClCompile Include="WriteLog.cpp" />
     <ClCompile Include="ClassifyDectect.cpp" />
     <ClCompile Include="YundaTecAlgorithnm.cpp" />
@@ -170,11 +173,14 @@
     <ClInclude Include="MeterDectect.h" />
     <ClInclude Include="NumberDectect.h" />
     <ClInclude Include="OilLevelDectect.h" />
+    <ClInclude Include="OperatingHandleStateDectect.h" />
     <ClInclude Include="PressplateDectect.h" />
     <ClInclude Include="resource.h" />
     <ClInclude Include="ArresterCircularZeroThreeALGO.h" />
+    <ClInclude Include="AmpereMeterALGO.h" />
     <ClInclude Include="TriangleDisconnectorDectect.h" />
     <ClInclude Include="UpdateUI.h" />
+    <ClInclude Include="VoltageMeterALGO.h" />
     <ClInclude Include="WriteLog.h" />
     <ClInclude Include="ClassifyDectect.h" />
     <ClInclude Include="YundaTecAlgorithnm.h" />

+ 24 - 0
YunDa.ISAS.Image.Recognition.Service.vcxproj.filters

@@ -95,6 +95,15 @@
     <ClCompile Include="ContactDectect.cpp">
       <Filter>Source Files\Contact</Filter>
     </ClCompile>
+    <ClCompile Include="AmpereMeterALGO.cpp">
+      <Filter>Source Files\Meter</Filter>
+    </ClCompile>
+    <ClCompile Include="VoltageMeterALGO.cpp">
+      <Filter>Source Files\Meter</Filter>
+    </ClCompile>
+    <ClCompile Include="OperatingHandleStateDectect.cpp">
+      <Filter>Source Files\OperatingHandleStateDectect</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <Filter Include="Header Files">
@@ -208,6 +217,12 @@
     <Filter Include="Source Files\Instructions">
       <UniqueIdentifier>{8fab5816-bc3b-43af-bd99-84ef62d19c0a}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Source Files\OperatingHandleStateDectect">
+      <UniqueIdentifier>{381d25b7-e1dc-40ed-82f9-2c212386dfab}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Header Files\OperatingHandleStateDectect">
+      <UniqueIdentifier>{7a2a451f-1077-4b8b-b723-2bd2a38d9c40}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="resource.h" />
@@ -304,6 +319,15 @@
     <ClInclude Include="ContactDectect.h">
       <Filter>Header Files\Contact</Filter>
     </ClInclude>
+    <ClInclude Include="AmpereMeterALGO.h">
+      <Filter>Header Files\Meter</Filter>
+    </ClInclude>
+    <ClInclude Include="VoltageMeterALGO.h">
+      <Filter>Header Files\Meter</Filter>
+    </ClInclude>
+    <ClInclude Include="OperatingHandleStateDectect.h">
+      <Filter>Header Files\OperatingHandleStateDectect</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <QtRcc Include="YunDaISASImageRecognitionService.qrc">

+ 2 - 2
YunDa.ISAS.Image.Recognition.Service.vcxproj.user

@@ -2,9 +2,9 @@
 <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup />
   <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <QtLastBackgroundBuild>2022-11-17T11:46:22.3275037Z</QtLastBackgroundBuild>
+    <QtLastBackgroundBuild>2023-02-13T09:16:20.8720525Z</QtLastBackgroundBuild>
   </PropertyGroup>
   <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <QtLastBackgroundBuild>2022-11-17T11:46:22.4270129Z</QtLastBackgroundBuild>
+    <QtLastBackgroundBuild>2023-02-13T09:15:31.0170061Z</QtLastBackgroundBuild>
   </PropertyGroup>
 </Project>

TEMPAT SAMPAH
test.png


File diff ditekan karena terlalu besar
+ 11988 - 173152
test.txt


+ 0 - 0
图像识别配置/AlgorithmConfiguration.json → 图像识别配置/AlgorithmConfiguration.json1


+ 14 - 1
图像识别配置/Translate.json

@@ -87,10 +87,15 @@
       "unit": "mPa"
     },
     {
-      "key": "meter_quarter_square_ammeter",
+      "key": "meter_ampere_meter",
       "value": "电流",
       "unit": "A"
     },
+    {
+      "key": "meter_voltage_meter",
+      "value": "电压",
+      "unit": "V"
+    },
     {
       "key": "meter_oil_thermometer_Min",
       "value": "油温",
@@ -146,6 +151,14 @@
       "key": "disconnector_state_off",
       "value": "分"
     },
+    {
+      "key": "operating_handle_on",
+      "value": "合"
+    },
+    {
+      "key": "operating_handle_off",
+      "value": "分"
+    },
     {
       "key": "disconnector_connection",
       "value": "合闸"

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini