Repository navigation
Expand file tree
/
Copy pathcnn.cpp
More file actions
149 lines (126 loc) · 5.5 KB
/
Copy pathcnn.cpp
File metadata and controls
149 lines (126 loc) · 5.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//
// Created by marking on 2024/12/5.
//
#include "cnn.h"
void Figure::getMaxClass(const Mat& probBlob, int* classId, double* classProb)
{
Mat probMat = probBlob.reshape(1, 1);
Point classNumber;
minMaxLoc(probMat, NULL, classProb, NULL, &classNumber);
*classId = classNumber.x;
}
void Figure::cnn_load()
{
//***************************************************加载模型********************************************************
string model = "/Users/marking/Desktop/data/lenet_iter_10000.caffemodel";
string config = "/Users/marking/Desktop/data/lenet_train_test.prototxt";
try {
net = readNetFromCaffe(config, model);
cout << "cnn数字识别加载模型成功" << endl;
}
catch (cv::Exception& ee) {
cerr << "错误: " << ee.what() << endl;
if (net.empty()) {
cout << "无法加载以下模型:" << endl;
cout << "modelTxt: " << model << endl;
cout << "modelBin: " << config << endl;
exit(-1);
}
}
}
bool Figure::validateInput(const Mat& frame) {
// ---------------------- 预处理增强 ----------------------
Mat gray, binary;
cvtColor(frame, gray, COLOR_BGR2GRAY);
imshow("processed1",frame);
// threshold(frame,)
// 1. 自适应二值化(增强鲁棒性)
adaptiveThreshold(gray, binary, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 11, 2);
// 2. 形态学去噪(去除小斑点)
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
morphologyEx(binary, binary, MORPH_OPEN, kernel);
imshow("processed",binary);
// 3. 轮廓分析(确保存在有效字符)
vector<vector<Point>> contours;
findContours(binary, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
// 规则1:必须有且仅有一个显著轮廓
if (contours.size() != 1) return false;
// 规则2:最大轮廓面积占比超过10%
double maxArea = contourArea(contours[0]);
if (maxArea < (frame.rows * frame.cols * 0.1)) return false;
// 规则3:宽高比在合理范围内(0.3~3.0,避免线状噪声)
Rect bbox = boundingRect(contours[0]);
float aspectRatio = (float)bbox.width / bbox.height;
if (aspectRatio < 0.3 || aspectRatio > 3.0) return false;
return true;
}
void Figure::cnn_recognition(const Mat& frame) {
// ---------------------- 输入校验 ----------------------
if (!validateInput(frame)) {
cout << "无效输入(非数字图像)" << endl;
return;
}
// ---------------------- 预处理标准化 ----------------------
Mat processed;
cvtColor(frame, processed, COLOR_BGR2GRAY);
adaptiveThreshold(processed, processed, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 11, 2);
resize(processed, processed, Size(28, 28));
// ---------------------- 模型推理 ----------------------
Mat inputBlob = blobFromImage(processed, 1.0, Size(28, 28), false);
net.setInput(inputBlob, "data");
Mat pred = net.forward("prob");
// ---------------------- 后处理校验 ----------------------
int classId;
double classProb;
getMaxClass(pred, &classId, &classProb);
// 规则1:置信度阈值(可调整)
const double CONF_THRESHOLD = 0.8;
if (classProb < CONF_THRESHOLD) {
cout << "低置信度(" << classProb * 100 << "%),拒绝识别" << endl;
return;
}
// 规则2:概率分布熵检测(避免多个高概率类别)
Mat probMat = pred.reshape(1, 1);
Scalar mean, stddev;
meanStdDev(probMat, mean, stddev);
if (stddev[0] < 0.2) { // 标准差过小说明概率分布平坦
cout << "不确定结果,拒绝识别" << endl;
return;
}
// ---------------------- 最终输出 ----------------------
cout << "识别结果: " << classId << " (置信度: " << classProb * 100 << "%)" << endl;
}
//********************************************old******************************************************
//void Figure::cnn_recognition(const Mat& frame)
//{
// //***************************************************识别数字***********************************************************
// double time0 = static_cast<double>(getTickCount());
// Mat inputBlob = blobFromImage(frame, 1.0, Size(28, 28), false);
// net.setInput(inputBlob, "data");
// Mat pred = net.forward("prob");
// time0 = ((double)getTickCount() - time0) / getTickFrequency();
// //cout << "\t此方法运行时间为: " << cvRound(time0 * 1000) << "毫秒" << endl;
// //cout << pred << endl;
// int classId; double classProb;
// Figure::getMaxClass(pred, &classId, &classProb);
// cout << "Best Class: " << classId << endl;
// //cout << "Probability: " << classProb * 100 << "%" << endl;
//}
//*******************************************************************************************************
void Figure::cnn_fps(const Mat& img)//在图片的左上角显示帧率
{
double fps,t2,spendtime;
char string[20]; // 用于存放帧率的字符串
// 获取当前 tick count
t2 = (double)getTickCount();
// 计算从 t1 到 t2 的时间
spendtime = (t2 - t1) / getTickFrequency();
fps = 1.0 / spendtime;
sprintf(string, "%.2f", fps); // 帧率保留两位小数
std::string fpsString("FPS: ");
fpsString += string; // 在 "FPS:" 后加入帧率数值字符串
// 将帧率信息写在输出帧上
putText(img, fpsString, Point(5, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 255, 255));
// 更新 t1 为当前的 tick count
t1 = t2;
}