From 504c6629abdfa143f3b65666eb61e3332e6c8da6 Mon Sep 17 00:00:00 2001 From: slava Date: Mon, 14 Apr 2025 13:59:19 +0700 Subject: [PATCH] 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. --- .gitignore | 9 ++++- CMakeLists.txt | 29 ++++++++++--- main.cpp | 65 +++++++++++++++++++++++++++++- services/device_screener.cpp | 20 +++++++++ services/device_screener.h | 19 +++++++++ MyWindow.cpp => views/MyWindow.cpp | 0 MyWindow.h => views/MyWindow.h | 0 7 files changed, 133 insertions(+), 9 deletions(-) create mode 100644 services/device_screener.cpp create mode 100644 services/device_screener.h rename MyWindow.cpp => views/MyWindow.cpp (100%) rename MyWindow.h => views/MyWindow.h (100%) diff --git a/.gitignore b/.gitignore index c1425bf..1b97c30 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,11 @@ Makefile .qt/ # VS Code specific -.vscode/ \ No newline at end of file +.vscode/ +/build.ninja +/.cmake/ +/Testing/ +/.ninja_deps +/.ninja_log +/ARCDesktopProject_autogen/ +/ARCDesktopProject diff --git a/CMakeLists.txt b/CMakeLists.txt index a476c07..d754661 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.16) -project(MyQt6App LANGUAGES CXX) +project(ARCDesktopProject LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_AUTOMOC ON) @@ -8,13 +8,30 @@ set(CMAKE_AUTOUIC ON) # Укажи путь к Qt6 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) -add_executable(MyQt6App - main.cpp - MyWindow.cpp - MyWindow.h +file(GLOB_RECURSE VIEW_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/views/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/views/*.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 +) diff --git a/main.cpp b/main.cpp index 9f07115..92f5811 100644 --- a/main.cpp +++ b/main.cpp @@ -1,9 +1,70 @@ #include -#include "MyWindow.h" +#include +#include "views/MyWindow.h" +#include +#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[]) { 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; window.show(); return app.exec(); -} \ No newline at end of file +} diff --git a/services/device_screener.cpp b/services/device_screener.cpp new file mode 100644 index 0000000..8e14724 --- /dev/null +++ b/services/device_screener.cpp @@ -0,0 +1,20 @@ +#include "device_screener.h" +#include +#include + +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; +} \ No newline at end of file diff --git a/services/device_screener.h b/services/device_screener.h new file mode 100644 index 0000000..7e23a0f --- /dev/null +++ b/services/device_screener.h @@ -0,0 +1,19 @@ +#pragma once +#include + +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; +}; \ No newline at end of file diff --git a/MyWindow.cpp b/views/MyWindow.cpp similarity index 100% rename from MyWindow.cpp rename to views/MyWindow.cpp diff --git a/MyWindow.h b/views/MyWindow.h similarity index 100% rename from MyWindow.h rename to views/MyWindow.h