Integrate threading and Tesseract OCR functionality
Added a background worker using QThread for device screening and integrated Tesseract OCR for text recognition from images. Refactored project structure, updated CMakeLists for Tesseract support, and adjusted .gitignore for build files.
This commit is contained in:
parent
944e32cfda
commit
504c6629ab
7
.gitignore
vendored
7
.gitignore
vendored
@ -14,3 +14,10 @@ Makefile
|
|||||||
|
|
||||||
# VS Code specific
|
# VS Code specific
|
||||||
.vscode/
|
.vscode/
|
||||||
|
/build.ninja
|
||||||
|
/.cmake/
|
||||||
|
/Testing/
|
||||||
|
/.ninja_deps
|
||||||
|
/.ninja_log
|
||||||
|
/ARCDesktopProject_autogen/
|
||||||
|
/ARCDesktopProject
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
project(MyQt6App LANGUAGES CXX)
|
project(ARCDesktopProject LANGUAGES CXX)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
@ -8,13 +8,30 @@ set(CMAKE_AUTOUIC ON)
|
|||||||
|
|
||||||
# Укажи путь к Qt6
|
# Укажи путь к Qt6
|
||||||
set(CMAKE_PREFIX_PATH "/opt/homebrew/opt/qt")
|
set(CMAKE_PREFIX_PATH "/opt/homebrew/opt/qt")
|
||||||
|
include_directories("/opt/homebrew/opt/tesseract/include")
|
||||||
|
link_directories("/opt/homebrew/opt/tesseract/lib")
|
||||||
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Widgets)
|
find_package(Qt6 REQUIRED COMPONENTS Widgets)
|
||||||
|
|
||||||
add_executable(MyQt6App
|
file(GLOB_RECURSE VIEW_SOURCES
|
||||||
main.cpp
|
"${CMAKE_CURRENT_SOURCE_DIR}/views/*.cpp"
|
||||||
MyWindow.cpp
|
"${CMAKE_CURRENT_SOURCE_DIR}/views/*.h"
|
||||||
MyWindow.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(MyQt6App Qt6::Widgets)
|
file(GLOB_RECURSE SERVICES_SOURCES
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/services/*.cpp"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/services/*.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(ARCDesktopProject
|
||||||
|
main.cpp
|
||||||
|
${VIEW_SOURCES}
|
||||||
|
${SERVICES_SOURCES}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(ARCDesktopProject PRIVATE)
|
||||||
|
|
||||||
|
target_link_libraries(ARCDesktopProject
|
||||||
|
Qt6::Widgets
|
||||||
|
tesseract
|
||||||
|
)
|
||||||
|
|||||||
63
main.cpp
63
main.cpp
@ -1,8 +1,69 @@
|
|||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include "MyWindow.h"
|
#include <QThread>
|
||||||
|
#include "views/MyWindow.h"
|
||||||
|
#include <tesseract/baseapi.h>
|
||||||
|
#include "services/device_screener.h"
|
||||||
|
|
||||||
|
void setupWorkerAndThread(QCoreApplication& app) {
|
||||||
|
auto* thread = new QThread;
|
||||||
|
auto* deviceScreenerWorker = new DeviceScreener;
|
||||||
|
|
||||||
|
// Перемещаем worker в новый поток thread.
|
||||||
|
// Это значит, что все слоты worker, вызываемые через connect(), теперь будут исполняться в этом фоне-потоке.
|
||||||
|
deviceScreenerWorker->moveToThread(thread);
|
||||||
|
|
||||||
|
// Когда поток запустится, автоматически вызовется worker->start() внутри фонового потока.
|
||||||
|
QObject::connect(thread, &QThread::started, deviceScreenerWorker, &DeviceScreener::start);
|
||||||
|
|
||||||
|
// 🔁 Эти 3 строки делают автоматическую зачистку:
|
||||||
|
// Когда worker закончит работу (emit finished()), мы:
|
||||||
|
// - останавливаем поток (thread->quit())
|
||||||
|
// - удаляем worker (deleteLater)
|
||||||
|
// - удаляем thread (deleteLater)
|
||||||
|
// Это защищает от утечек памяти и оставшихся потоков после завершения.
|
||||||
|
QObject::connect(deviceScreenerWorker, &DeviceScreener::finished, thread, &QThread::quit);
|
||||||
|
QObject::connect(deviceScreenerWorker, &DeviceScreener::finished, deviceScreenerWorker, &QObject::deleteLater);
|
||||||
|
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||||
|
|
||||||
|
// Когда пользователь закрывает приложение (Ctrl+C, exit() и т.п.), мы вызываем worker->stop() — ты сам пишешь, что в этом методе.
|
||||||
|
//Обычно он просто ставит флаг m_running = false, чтобы остановить бесконечный цикл в start()
|
||||||
|
QObject::connect(&app, &QCoreApplication::aboutToQuit, [=]() {
|
||||||
|
deviceScreenerWorker->stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
thread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
|
||||||
|
// Setup worker and thread
|
||||||
|
setupWorkerAndThread(app);
|
||||||
|
|
||||||
|
|
||||||
|
// tesseract, tesseract-lang
|
||||||
|
QImage image("./resources/img.png");
|
||||||
|
if (image.isNull()) {
|
||||||
|
qDebug() << "Не удалось загрузить изображение.";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
image = image.convertToFormat(QImage::Format_Grayscale8);
|
||||||
|
|
||||||
|
tesseract::TessBaseAPI tess;
|
||||||
|
if (tess.Init(nullptr, "rus")) {
|
||||||
|
qDebug() << "Ошибка инициализации Tesseract с русским языком.";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tess.SetImage(image.bits(), image.width(), image.height(), 1, image.bytesPerLine());
|
||||||
|
|
||||||
|
QString result = QString::fromUtf8(tess.GetUTF8Text());
|
||||||
|
qDebug() << "Распознанный текст:" << result;
|
||||||
|
|
||||||
|
|
||||||
MyWindow window;
|
MyWindow window;
|
||||||
window.show();
|
window.show();
|
||||||
return app.exec();
|
return app.exec();
|
||||||
|
|||||||
20
services/device_screener.cpp
Normal file
20
services/device_screener.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include "device_screener.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
DeviceScreener::DeviceScreener(QObject* parent) : QObject(parent) {}
|
||||||
|
|
||||||
|
DeviceScreener::~DeviceScreener() = default;
|
||||||
|
|
||||||
|
void DeviceScreener::start() {
|
||||||
|
qDebug() << "Worker started in thread:" << QThread::currentThread();
|
||||||
|
while (m_running) {
|
||||||
|
qDebug() << "Running in background...";
|
||||||
|
QThread::sleep(2);
|
||||||
|
}
|
||||||
|
emit finished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceScreener::stop() {
|
||||||
|
m_running = false;
|
||||||
|
}
|
||||||
19
services/device_screener.h
Normal file
19
services/device_screener.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class DeviceScreener final : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit DeviceScreener(QObject* parent = nullptr);
|
||||||
|
~DeviceScreener() override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void finished();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_running = true;
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user