5#include <QFutureWatcher>
7#include <tesseract/baseapi.h>
8#include <leptonica/allheaders.h>
9#include "OCRLanguageModel.h"
10#if TESSERACT_MAJOR_VERSION < 5
11#include <tesseract/strngs.h>
12#include <tesseract/genericvector.h>
16#include <preprocessimage.hpp>
17#include <convertimage.hpp>
45 ,m_tesseract(new tesseract::TessBaseAPI())
46 ,m_languages(new OCRLanguageModel(this))
47 ,m_boxesTypes(BoxType::Word | BoxType::Line | BoxType::Paragraph)
48 ,m_confidenceThreshold(50)
51 std::vector<std::string> availableLanguages;
52#if TESSERACT_MAJOR_VERSION < 5
53 GenericVector<STRING> languageVector;
54 m_tesseract->GetAvailableLanguagesAsVector(&languageVector);
55 for (
int i = 0; i < languageVector.size(); i++) {
56 availableLanguages.push_back(languageVector[i].c_str());
59 m_tesseract->GetAvailableLanguagesAsVector(&availableLanguages);
62 m_languages->setLanguages(availableLanguages);
75QRect OCS::area()
const
80bool OCS::autoRead()
const
85void OCS::setAutoRead(
bool value)
87 if(m_autoRead == value)
94void OCS::setBoxesType(OCS::BoxesType types)
96 if(m_boxesTypes == types)
100 m_boxesTypes = types;
101 qDebug() <<
"Setting the boxes types" << m_boxesTypes << types;
103 Q_EMIT boxesTypeChanged();
106void OCS::setConfidenceThreshold(
float value)
108 if(m_confidenceThreshold == value)
111 m_confidenceThreshold = value;
112 Q_EMIT confidenceThresholdChanged();
115int OCS::wordBoxAt(
const QPoint point)
118 for(
const auto &box : m_wordBoxes)
120 QRect rect = box[
"rect"].toRect();
122 qDebug() <<
"Rect: " << rect <<
"Point: " << point << rect.
contains(point,
true);
137 for(
const auto &box : m_wordBoxes)
139 QRect rect_o = box[
"rect"].toRect();
150void OCS::setWhiteList(
const QString &value)
152 if(value == m_whiteList)
156 Q_EMIT whiteListChanged();
159void OCS::setBlackList(
const QString &value)
161 if(value == m_blackList)
165 Q_EMIT blackListChanged();
168void OCS::setPreprocessImage(
bool value)
170 if(m_preprocessImage == value)
173 m_preprocessImage = value;
175 Q_EMIT preprocessImageChanged();
178void OCS::setPageSegMode(PageSegMode value)
180 if(m_segMode == value)
184 Q_EMIT pageSegModeChanged();
192void OCS::do_preprocessImage(
const QImage &image)
198static tesseract::PageSegMode mapPageSegValue(OCS::PageSegMode value)
203 case OCS::PageSegMode::Auto:
return tesseract::PageSegMode::PSM_AUTO;
204 case OCS::PageSegMode::Auto_OSD:
return tesseract::PageSegMode::PSM_AUTO_OSD;
205 case OCS::PageSegMode::SingleColumn:
return tesseract::PageSegMode::PSM_SINGLE_COLUMN;
206 case OCS::PageSegMode::SingleLine:
return tesseract::PageSegMode::PSM_SINGLE_LINE;
207 case OCS::PageSegMode::SingleBlock:
return tesseract::PageSegMode::PSM_SINGLE_BLOCK;
208 case OCS::PageSegMode::SingleWord:
return tesseract::PageSegMode::PSM_SINGLE_WORD;
212void OCS::getTextAsync()
216 qDebug() <<
"URL is not local :: OCR";
219 typedef QMap<BoxType, TextBoxes> Res;
220 auto func = [ocs =
this](QUrl url, BoxesType levels) -> Res
222 tesseract::TessBaseAPI *api =
new tesseract::TessBaseAPI();
223 api->Init(NULL,
"eng");
225 api->SetVariable(
"tessedit_char_whitelist",
226 ocs->m_whiteList.toStdString().c_str());
227 api->SetVariable(
"tessedit_char_blacklist",
228 ocs->m_blackList.toStdString().c_str());
230 api->SetPageSegMode(mapPageSegValue(ocs->m_segMode));
232 if(ocs->m_preprocessImage)
234 auto var =
new QImage(url.toLocalFile());
235 auto m_imgMat = ConvertImage::qimageToMatRef(*var, CV_8UC4);
238 PreprocessImage::adaptThreshold(m_imgMat,
false, 3, 1);
242 m_ocrImg.save(
"/home/camilo/"+QFileInfo(url.toLocalFile()).fileName());
244 api->SetImage(m_ocrImg.bits(), m_ocrImg.width(), m_ocrImg.height(), 4, m_ocrImg.bytesPerLine());
250 ocs->m_ocrImg =
new QImage(url.toLocalFile());
251 api->SetImage(ocs->m_ocrImg->bits(), ocs->m_ocrImg->width(), ocs->m_ocrImg->height(), 4,
252 ocs->m_ocrImg->bytesPerLine());
256 api->SetSourceResolution(200);
260 TextBoxes wordBoxes, lineBoxes, paragraphBoxes;
262 auto levelFunc = [ocs](tesseract::TessBaseAPI *api, tesseract::PageIteratorLevel
level) -> TextBoxes
265 tesseract::ResultIterator* ri = api->GetIterator();
268 qDebug() <<
"Getting text for level" <<
level;
271 const char* word = ri->GetUTF8Text(level);
272 float conf = ri->Confidence(level);
274 ri->BoundingBox(level, &x1, &y1, &x2, &y2);
276 printf(
"word: '%s'; \tconf: %.2f; BoundingBox: %d,%d,%d,%d;\n",
277 word, conf, x1, y1, x2, y2);
279 if(conf > ocs->m_confidenceThreshold && !isspace(*word))
282 }
while (ri->Next(level));
288 if(levels.testFlag(Word))
289 wordBoxes = levelFunc(api, tesseract::RIL_WORD);
291 if(levels.testFlag(Line))
292 lineBoxes = levelFunc(api, tesseract::RIL_TEXTLINE);
294 if(levels.testFlag(Paragraph))
295 paragraphBoxes = levelFunc(api, tesseract::RIL_PARA);
300 return Res{{Word, wordBoxes}, {Line, lineBoxes}, {Paragraph, paragraphBoxes}};
303 auto watcher =
new QFutureWatcher<Res>;
307 m_wordBoxes = watcher->result()[Word];
308 m_lineBoxes = watcher->result()[Line];
309 m_paragraphBoxes = watcher->result()[Paragraph];
310 Q_EMIT wordBoxesChanged();
311 Q_EMIT lineBoxesChanged();
312 Q_EMIT paragraphBoxesChanged();
313 watcher->deleteLater();
316 qDebug() <<
"GEtting text for boxes " << m_boxesTypes << m_boxesTypes.testFlag(Word);
318 watcher->setFuture(future);
324 if(!url.isLocalFile())
326 qDebug() <<
"URL is not local :: OCR";
330 if (m_tesseract->Init(
nullptr, m_languages->getLanguagesString().c_str()))
332 qDebug() <<
"Failed tesseract OCR init";
336 m_tesseract->SetPageSegMode(tesseract::PSM_AUTO);
340 if(!m_area.isEmpty())
342 QImage img(url.toLocalFile());
343 img = img.copy(m_area);
346 m_tesseract->SetImage(img.bits(), img.width(), img.height(), 4, img.bytesPerLine());
350 Pix* im = pixRead(url.toLocalFile().toStdString().c_str());
351 m_tesseract->SetImage(im);
359void OCS::setFilePath(
QString filePath)
361 if (m_filePath == filePath)
364 m_filePath = filePath;
365 Q_EMIT filePathChanged(m_filePath);
368void OCS::setArea(
QRect area)
374 Q_EMIT areaChanged(m_area);
378TextBoxes OCS::wordBoxes()
const
383TextBoxes OCS::paragraphBoxes()
const
385 return m_paragraphBoxes;
388TextBoxes OCS::lineBoxes()
const
393OCS::BoxesType OCS::boxesType()
398float OCS::confidenceThreshold()
400 return m_confidenceThreshold;
413OCS::PageSegMode OCS::pageSegMode()
const
418bool OCS::preprocessImage()
const
420 return m_preprocessImage;
423void OCS::classBegin()
427void OCS::componentComplete()
429 qDebug() <<
"OCS CALSS COMPLETED IN QML";
430 connect(
this, &OCS::filePathChanged, [
this](QString)
QStringView level(QStringView ifopt)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool contains(const QPoint &point, bool proper) const const
bool intersects(const QRect &rectangle) const const
QString fromStdString(const std::string &str)
QFuture< T > run(Function function,...)