2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > QT案例实战1 - 从零开始编写一个OCR工具软件 (6) 关于QThread线程的使用

QT案例实战1 - 从零开始编写一个OCR工具软件 (6) 关于QThread线程的使用

时间:2023-10-26 12:08:05

相关推荐

QT案例实战1 - 从零开始编写一个OCR工具软件 (6) 关于QThread线程的使用

一、为什么用线程

在这里将ocr识别的这个耗时的操作放在新线程内,这样是为了主线程/UI界面不会卡在那里没有响应。如果说不在乎用户体验,ocr识别也可以放在主线程,卡住就卡住,就是会被骂。

不过关于线程的使用有的时候也要看平台框架的要求,比如android,网络请求就要在新线程内,否则就会报错。

QT内的线程类叫做QThread,看看qthread.h内的部分方法,熟悉Java线程的大概在就会知道用法了(因为挺像的),我们这里采用创建一个新的继承自QThread类的方法使用线程。

QThread 的头文件的部分截图

二、创建继承自Thread的类

1、创建头文件

起了个名字,有点长,MyThreadForTextRecognition.h。

其中public方法内主要是自定义的init方法,用来传递给线程一些ocr识别的参数,比如语言、用哪个引擎等。

其中private是一些线程内的参数,以及对应两个ocr引擎的识别方法。

其中protected就是我们要覆写的run方法。

其中signals就是我们用来和主线程通信的方法。关于信号和槽可以查看官网说明。其中getRecognitionText方法是用来将识别结果传递给主线程以显示在界面上。其中recognitionFinish方法是告诉主线程识别完了,可以关闭loading了。

#ifndef MYTHREADFORTEXTRECOGNITION_H#define MYTHREADFORTEXTRECOGNITION_H// windows sdk api#define _SILENCE_CLANG_COROUTINE_MESSAGE#include "winrt/Windows.Globalization.h"#include "winrt/windows.media.ocr.h"#include "winrt/windows.graphics.imaging.h"#include "winrt/Windows.Storage.h"#include "winrt/Windows.Storage.Streams.h"#include "winrt/Windows.Foundation.Collections.h"// QT#include <QObject>#include <QThread>#include "qdebug.h"// 自定义#include "mytools.h"// tesseract#include <tesseract/baseapi.h>#include <leptonica/allheaders.h>class MyThreadForTextRecognition : public QThread{Q_OBJECTpublic:MyThreadForTextRecognition();void init(std::string filepath, std::string newFilepath, int language_index, bool preprocessing, int ocrengine);private:char *outText;std::string _filepath;int _language_index;std::string _newFilepath;bool _preprocessing = false;std::string _ocrengine;void _cognizeByWinOCR();void _cognizeByTesseract();protected:void run() override;signals:void minNumToamin(int min);void getRecognitionText(std::string outText);void recognitionFinish();};#endif // MYTHREADFORTEXTRECOGNITION_H

2、创建cpp文件

参考代码如下

#include <MyThreadForTextRecognition.h>#include <string>#include <iostream>#include <locale>#include <codecvt>//#pragma execution_character_set("utf-8");//comment(lib, "windowsapp")using namespace winrt::Windows::Foundation;using namespace winrt::Windows::Storage;using namespace winrt::Windows::Storage::Streams;using namespace winrt::Windows::Globalization;using namespace winrt::Windows::Media::Ocr;using namespace winrt::Windows::Graphics::Imaging;MyThreadForTextRecognition::MyThreadForTextRecognition(){}/*** @brief MyThreadForTextRecognition::init 接收一些参数* @param filepath* @param newFilepath* @param language* @param preprocessing*/void MyThreadForTextRecognition::init(std::string filepath, std::string newFilepath, int language_index, bool preprocessing, int ocrengine){_filepath = filepath;_language_index = language_index;_newFilepath = newFilepath;_preprocessing = preprocessing;_ocrengine = (ocrengine==0) ? "micocr" : "tesseract";}/*** @brief MyThreadForTextRecognition::_cognizeByWinOCR* 基于windows的ocr*/void MyThreadForTextRecognition::_cognizeByWinOCR(){//获取图片路径std::wstring uriImage = MyTools::ConvertUtf8ToWide(_newFilepath);//获取SoftwareBitmapRandomAccessStreamReference streamRef = RandomAccessStreamReference::CreateFromFile(StorageFile::GetFileFromPathAsync(uriImage).get());IAsyncOperation<IRandomAccessStreamWithContentType> stream = streamRef.OpenReadAsync();Buffer buffer = Buffer((uint)stream.get().Size());auto decoder = BitmapDecoder::CreateAsync(stream.get().CloneStream());IAsyncOperation<SoftwareBitmap> softwareBitmap = decoder.get().GetSoftwareBitmapAsync();//进行识别Language language(winrt::to_hstring(MyTools::get_Choise_Language(_language_index, _ocrengine)));//如果不支持的语言if (OcrEngine::IsLanguageSupported(language)) {OcrEngine engine = OcrEngine::TryCreateFromLanguage(language);Collections::IVectorView<OcrLine> lines = engine.RecognizeAsync(softwareBitmap.get()).get().Lines();if(lines.Size()>0){for (auto p : lines){std::string text = "";for (OcrWord word : p.Words()) {text += to_string(word.Text()) + ((_language_index>0)?" ":"");}emit getRecognitionText(text/*const_cast<char *>(text.c_str())*/);qDebug() << "识别结果:" << text.c_str();}}else{emit getRecognitionText("");}}else{qDebug() << "不支持的语言:" << QString::fromStdString(MyTools::get_Choise_Language(_language_index, _ocrengine));emit getRecognitionText("");}}/*** @brief MyThreadForTextRecognition::_cognizeByTesseract* 基于Tesseract的ocr*/void MyThreadForTextRecognition::_cognizeByTesseract(){// 初始化apitesseract::TessBaseAPI *api = new tesseract::TessBaseAPI();// 初始化ocr识别,使用中文并且指定tessdata路径if (api->Init("lib/tesseract/tessdata/", MyTools::get_Choise_Language(_language_index, _ocrengine).c_str(), tesseract::OcrEngineMode::OEM_LSTM_ONLY)) {emit getRecognitionText("");}else{// 使用leptonica库打开图像Pix *image = pixRead(_newFilepath.c_str());api->SetImage(image);// 【最简单的api】//outText = api->GetUTF8Text();//qDebug()<<"outText:"<<outText;//getRecognitionText(outText);// 【获取组件图像示例】Boxa* boxes = api->GetComponentImages(tesseract::RIL_PARA, true, NULL, NULL);for (int i = 0; i < boxes->n; i++) {BOX* box = boxaGetBox(boxes, i, L_CLONE);api->SetRectangle(box->x, box->y, box->w, box->h);char* ocrResult = api->GetUTF8Text();int meanConf = api->MeanTextConf();int *confs = api->AllWordConfidences();qDebug()<<"meanConf:"<<meanConf;emit getRecognitionText(ocrResult);//fprintf(stdout, "Box[%d]: x=%d, y=%d, w=%d, h=%d, confidence: %d, text: %s", i, box->x, box->y, box->w, box->h, conf, ocrResult);boxDestroy(&box);}emit recognitionFinish();// 销毁使用过的对象并释放内存api->End();delete api;//delete[] outText;pixDestroy(&image);}}/*** @brief MyThreadForTextRecognition::run 运行线程*/void MyThreadForTextRecognition::run(){try{//图像预处理,可以没有if(_preprocessing){MyTools::BinarythresoldByOpenCV(_filepath.c_str(), _newFilepath.c_str());}else{_newFilepath = _filepath;}if(_ocrengine == "micocr"){_cognizeByWinOCR();}else if(_ocrengine == "tesseract"){_cognizeByTesseract();}}catch(_exception e){emit getRecognitionText("");qDebug()<<"ocr识别异常:"<<0;}emit recognitionFinish();}

三、使用线程

首先实例化线程类,然后调用init传递参数,然后绑定两个信号/槽,最后调用start方法启动线程。

//启动线程m_thread = new MyThreadForTextRecognition;m_thread->init(filePath.toStdString(), QString("%1\\screen_action.jpg").arg(qApp->applicationDirPath().replace("/", "\\")).toStdString(),ui->comboBox->currentIndex(), ui->checkBox_3->isChecked(), ui->comboBox_2->currentIndex());connect(m_thread, &MyThreadForTextRecognition::getRecognitionText,this,&TextRecognition::getRecognitionText);connect(m_thread, &MyThreadForTextRecognition::recognitionFinish,this,&TextRecognition::recognitionFinish);m_thread->start();

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。