1
0
forked from BRT/arc

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:
slava 2025-04-14 13:59:19 +07:00
parent 944e32cfda
commit 504c6629ab
7 changed files with 133 additions and 9 deletions

9
.gitignore vendored
View File

@ -13,4 +13,11 @@ Makefile
.qt/
# VS Code specific
.vscode/
.vscode/
/build.ninja
/.cmake/
/Testing/
/.ninja_deps
/.ninja_log
/ARCDesktopProject_autogen/
/ARCDesktopProject

View File

@ -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
)

View File

@ -1,9 +1,70 @@
#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[]) {
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();
}
}

View 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;
}

View 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;
};