-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathocrmanager.cpp
More file actions
270 lines (226 loc) · 6.66 KB
/
Copy pathocrmanager.cpp
File metadata and controls
270 lines (226 loc) · 6.66 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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
#include "ocrmanager.h"
#include <QImage>
#include <QDebug>
#include <QBuffer>
#include <QThreadPool>
#include <QRunnable>
#include <QFuture>
#include <QtConcurrent/QtConcurrent>
// 如果定义了 USE_TESSERACT,则使用 Tesseract
// 否则在 macOS 上尝试使用 Vision,其他平台返回错误
#ifdef USE_TESSERACT
#include <tesseract/baseapi.h>
#include <leptonica/allheaders.h>
#endif
#if defined(Q_OS_MAC) && !defined(USE_TESSERACT)
#include "macocr.h"
#endif
// 初始化静态成员
OcrManager *OcrManager::m_instance = nullptr;
QMutex OcrManager::m_instanceMutex;
OcrManager::OcrManager()
#ifdef USE_TESSERACT
: m_tesseractApi(nullptr), m_tesseractInitialized(false),
m_language("chi_sim+eng"), m_imageScaleFactor(1.0)
#else
: m_language("chi_sim+eng"), m_imageScaleFactor(1.0)
#endif
{
// 初始化结果缓存,最多缓存50个结果
m_resultCache.setMaxCost(50);
// 预初始化OCR引擎
initializeOcr();
}
OcrManager::~OcrManager()
{
#ifdef USE_TESSERACT
if (m_tesseractApi != nullptr)
{
m_tesseractApi->End();
delete m_tesseractApi;
m_tesseractApi = nullptr;
m_tesseractInitialized = false;
}
#endif
}
OcrManager *OcrManager::instance()
{
// 双重检查锁定模式,确保线程安全
if (m_instance == nullptr)
{
QMutexLocker locker(&m_instanceMutex);
if (m_instance == nullptr)
{
m_instance = new OcrManager();
}
}
return m_instance;
}
bool OcrManager::initializeOcr()
{
#ifdef USE_TESSERACT
if (m_tesseractInitialized)
return true;
if (m_tesseractApi == nullptr)
{
m_tesseractApi = new tesseract::TessBaseAPI();
}
// 初始化 Tesseract
// 尝试初始化中文简体和英文
// 注意:需要确保 tessdata 目录下有 chi_sim.traineddata 和 eng.traineddata
// 如果初始化失败,尝试只初始化英文
if (m_tesseractApi->Init(NULL, m_language.toStdString().c_str()))
{
qDebug() << "Could not initialize tesseract with" << m_language << ", trying eng...";
if (m_tesseractApi->Init(NULL, "eng"))
{
qDebug() << "Could not initialize tesseract with eng.";
return false;
}
m_language = "eng";
}
m_tesseractInitialized = true;
return true;
#else
// 非Tesseract模式,不需要初始化
return true;
#endif
}
// 辅助函数:计算QPixmap的哈希值
static uint computePixmapHash(const QPixmap &pixmap)
{
// 缩放图像以加快哈希计算
QPixmap scaledPixmap = pixmap.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation);
// 转换为灰度图像
QImage image = scaledPixmap.toImage().convertToFormat(QImage::Format_Grayscale8);
// 计算哈希值,使用sizeInBytes替代deprecated的byteCount
QByteArray data((const char *)image.bits(), image.sizeInBytes());
return qHash(data);
}
QString OcrManager::recognize(const QPixmap &pixmap)
{
if (pixmap.isNull())
{
return QString();
}
// 获取单例实例
OcrManager *ocrInstance = instance();
// 计算图像哈希值作为缓存键
uint cacheKey = computePixmapHash(pixmap);
// 检查缓存
if (ocrInstance->m_resultCache.contains(cacheKey))
{
return *ocrInstance->m_resultCache[cacheKey];
}
// 调用实例的识别方法
QString result = ocrInstance->doRecognize(pixmap);
// 缓存结果
ocrInstance->m_resultCache.insert(cacheKey, new QString(result), 1);
return result;
}
QString OcrManager::doRecognize(const QPixmap &pixmap)
{
QMutexLocker locker(&m_mutex);
// 确保OCR引擎已初始化
if (!initializeOcr())
{
return "Error: Could not initialize OCR engine.";
}
QImage image = pixmap.toImage();
// 图像预处理
image = preprocessImage(image);
image = image.convertToFormat(QImage::Format_RGB888);
#ifdef USE_TESSERACT
// 设置图像
m_tesseractApi->SetImage(image.bits(), image.width(), image.height(), 3, image.bytesPerLine());
// 识别
char *outText = m_tesseractApi->GetUTF8Text();
QString result = QString::fromUtf8(outText);
// 清理结果
delete[] outText;
return result.trimmed();
#else
#if defined(Q_OS_MAC)
// macOS 原生 OCR
return MacOCR::recognizeText(QPixmap::fromImage(image)).trimmed();
#else
return "OCR not configured. Please enable Tesseract in .pro file.";
#endif
#endif
}
QImage OcrManager::preprocessImage(const QImage &image)
{
QImage processedImage = image;
// 应用缩放因子
if (m_imageScaleFactor != 1.0 && (m_imageScaleFactor > 1.0 || processedImage.width() > 2000 || processedImage.height() > 2000))
{
int newWidth = static_cast<int>(processedImage.width() * m_imageScaleFactor);
int newHeight = static_cast<int>(processedImage.height() * m_imageScaleFactor);
processedImage = processedImage.scaled(newWidth, newHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
// 转换为灰度图像(如果不是已经灰度)
if (processedImage.format() != QImage::Format_Grayscale8)
{
processedImage = processedImage.convertToFormat(QImage::Format_Grayscale8);
}
return processedImage;
}
QString OcrManager::getBackendType()
{
#ifdef USE_TESSERACT
return "Tesseract";
#elif defined(Q_OS_MAC)
return "Native";
#else
return "None";
#endif
}
void OcrManager::recognizeAsync(const QPixmap &pixmap, std::function<void(const QString &)> callback)
{
if (pixmap.isNull())
{
callback("");
return;
}
// 使用Qt Concurrent进行异步识别
QtConcurrent::run([pixmap, callback]()
{
QString result = recognize(pixmap);
callback(result); });
}
void OcrManager::cleanup()
{
QMutexLocker locker(&m_instanceMutex);
if (m_instance != nullptr)
{
delete m_instance;
m_instance = nullptr;
}
}
void OcrManager::setLanguage(const QString &language)
{
OcrManager *ocrInstance = instance();
QMutexLocker locker(&ocrInstance->m_mutex);
if (ocrInstance->m_language != language)
{
ocrInstance->m_language = language;
// 重新初始化OCR引擎
#ifdef USE_TESSERACT
if (ocrInstance->m_tesseractInitialized)
{
ocrInstance->m_tesseractApi->End();
ocrInstance->m_tesseractInitialized = false;
}
#endif
ocrInstance->initializeOcr();
}
}
void OcrManager::setImageScaleFactor(double factor)
{
if (factor > 0.1 && factor < 5.0)
{
OcrManager *ocrInstance = instance();
QMutexLocker locker(&ocrInstance->m_mutex);
ocrInstance->m_imageScaleFactor = factor;
}
}