FOSSredder 0.5.0
Loading...
Searching...
No Matches
TesseractTextRecognizerAdapter.cpp
Go to the documentation of this file.
1
5
13#include <sstream>
14#include <fstream>
15#include <iterator>
16#include <algorithm>
17#include <cctype>
18
20public:
21 explicit TesseractTextRecognizerAdapter(std::shared_ptr<core::ports::diagnostics::IDiagnostics> dbg = nullptr) : debugger(std::move(dbg)) {}
22
25 if (req.cancelFlag && req.cancelFlag->load()) return out;
26
27 std::vector<uint8_t> bytes;
28 if (!req.imageBytes.empty()) {
29 bytes = req.imageBytes;
30 } else if (!req.imagePath.empty()) {
31 std::ifstream ifs(req.imagePath, std::ios::binary);
32 if (ifs) bytes.assign((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
33 }
34
35 if (req.cancelFlag && req.cancelFlag->load()) return out;
36
37 auto [textDto, words] = TesseractCore::extractFromBytes(bytes, req.tessdataPath.string(), req.recognition, debugger);
38 out.text = textDto.text;
39 std::ostringstream oss;
40 for (const auto &w : words) {
41 oss << w.text << "\t" << w.bbox.x << "\t" << w.bbox.y << "\t" << w.bbox.width << "\t" << w.bbox.height << "\t" << w.confidence << "\n";
42 }
43 out.tsv = oss.str();
44
45 out.words.reserve(words.size());
46 for (const auto& w : words) {
48 wr.bbox.x = w.bbox.x;
49 wr.bbox.y = w.bbox.y;
50 wr.bbox.width = w.bbox.width;
51 wr.bbox.height = w.bbox.height;
52 wr.text = w.text;
53 wr.confidence = w.confidence;
54 out.words.push_back(wr);
55 }
56
57 if (req.cancelFlag && req.cancelFlag->load()) return out;
58
61 t.cells = req.cells;
62
64 int cx = w.x + w.width / 2;
65 int cy = w.y + w.height / 2;
66 return cx >= c.x && cx < (c.x + c.width) && cy >= c.y && cy < (c.y + c.height);
67 };
68
69 struct WRef {
71 int cy;
72 };
73
74 for (auto& cell : t.cells) {
75 if (req.cancelFlag && req.cancelFlag->load()) break;
76 std::vector<WRef> cellWords;
77 cellWords.reserve(out.words.size() / 4);
78 for (const auto& w : out.words) {
79 if (!inCell(w.bbox, cell.bbox)) continue;
80 cellWords.push_back(WRef{ &w, w.bbox.y + w.bbox.height / 2 });
81 }
82
83 if (cellWords.empty()) {
84 cell.text.clear();
85 cell.confidence = 0;
86 continue;
87 }
88
89 std::sort(cellWords.begin(), cellWords.end(), [](const WRef& a, const WRef& b) {
90 if (a.cy != b.cy) return a.cy < b.cy;
91 return a.w->bbox.x < b.w->bbox.x;
92 });
93
94 int avgH = 0;
95 for (const auto& cw : cellWords) avgH += cw.w->bbox.height;
96 avgH = std::max(1, avgH / static_cast<int>(cellWords.size()));
97 int lineTol = std::max(4, avgH / 2);
98
99 std::vector<std::vector<const core::ports::text_recognition::Word*>> lines;
100 std::vector<int> lineY;
101
102 for (const auto& cw : cellWords) {
103 if (lines.empty() || std::abs(cw.cy - lineY.back()) > lineTol) {
104 lines.push_back({ cw.w });
105 lineY.push_back(cw.cy);
106 } else {
107 lines.back().push_back(cw.w);
108 lineY.back() = (lineY.back() + cw.cy) / 2;
109 }
110 }
111
112 std::ostringstream text;
113 int sumConf = 0;
114 int n = 0;
115
116 for (size_t li = 0; li < lines.size(); ++li) {
117 auto& ln = lines[li];
118 std::sort(ln.begin(), ln.end(), [](const auto* a, const auto* b) { return a->bbox.x < b->bbox.x; });
119 for (size_t wi = 0; wi < ln.size(); ++wi) {
120 if (wi) text << ' ';
121 text << ln[wi]->text;
122 sumConf += ln[wi]->confidence;
123 ++n;
124 }
125 if (li + 1 < lines.size()) text << "\n";
126 }
127
128 cell.text = text.str();
129 cell.confidence = n > 0 ? (sumConf / n) : 0;
130 }
131
132 out.tables.push_back(std::move(t));
133 }
134
135 return out;
136 }
137
138private:
139 std::shared_ptr<core::ports::diagnostics::IDiagnostics> debugger;
140};
141
142std::shared_ptr<core::ports::text_recognition::ITextRecognizer> createTextRecognizerAdapter() {
143 return std::make_shared<TesseractTextRecognizerAdapter>();
144}
145
146std::shared_ptr<core::ports::text_recognition::ITextRecognizer> createTextRecognizerAdapter(std::shared_ptr<core::ports::diagnostics::IDiagnostics> debugger) {
147 return std::make_shared<TesseractTextRecognizerAdapter>(std::move(debugger));
148}
Declares the diagnostics artifact writing port.
Text recognition port.
Declares the Tesseract implementation helpers used by the import workflow.
std::shared_ptr< core::ports::text_recognition::ITextRecognizer > createTextRecognizerAdapter()
Request types for text recognition operations.
Result types for text recognition operations.
Shared text recognition data types.
static std::pair< core::ports::text_recognition::Text, std::vector< core::ports::text_recognition::Word > > extractFromBytes(const std::vector< uint8_t > &data, const std::string &tessdataPath, const core::ports::text_recognition::Settings &recognition, std::shared_ptr< core::ports::diagnostics::IDiagnostics > debugger=nullptr)
Extracts recognized text and word-level OCR data from image bytes.
core::ports::text_recognition::ExtractResult extract(const core::ports::text_recognition::ExtractRequest &req) override
Extracts text and geometry from an image.
TesseractTextRecognizerAdapter(std::shared_ptr< core::ports::diagnostics::IDiagnostics > dbg=nullptr)
Extracts recognized text from image data.
Precompiled header for the text-recognition infrastructure module.
std::shared_ptr< std::atomic< bool > > cancelFlag
enum core::ports::text_recognition::ExtractRequest::Kind kind