Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions SerialPrograms/Source/CommonFramework/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
#include "Startup/SetupSettings.h"
#include "Startup/NewVersionCheck.h"
#include "CommonFramework/VideoPipeline/Backends/CameraImplementations.h"
#include "CommonTools/OCR/OCR_RawOCR.h"
#include "CommonTools/OCR/OCR_Routines.h"
#include "ControllerInput/ControllerInput.h"
#include "Controllers/SerialPortPollerQt.h"
#include "Integrations/DiscordWebhook.h"
Expand Down Expand Up @@ -225,7 +225,7 @@ int main(int argc, char *argv[]){

// We must clear the OCR cache or it will crash on Linux when the library
// unloads before the cache is destructed from static memory.
OCR::clear_cache();
OCR::clear_ocr_cache();

// Stop the controllers.
global_input_stop();
Expand Down
4 changes: 2 additions & 2 deletions SerialPrograms/Source/CommonTools/OCR/OCR_DictionaryMatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class DictionaryMatcher{
// It specifies the minimum separation between the best candidate and
// 2nd best candidate's log10p for it to not be considered ambiguous.
// psm: Tesseract Page Segmentation mode. See
// SerialPrograms/Source/CommonTools/OCR/OCR_RawOCR.h:PageSegMode
// SerialPrograms/Source/CommonTools/OCR/OCR_RawTesseractOCR.h:PageSegMode
OCR::StringMatchResult match_substring_from_image(
Logger* logger,
Language language,
Expand All @@ -69,7 +69,7 @@ class DictionaryMatcher{
// even attempts to OCR. This is useful for pruning images with no appearant texts to
// reduce expensive OCR computation.
// psm: Tesseract Page Segmentation mode. See
// SerialPrograms/Source/CommonTools/OCR/OCR_RawOCR.h:PageSegMode
// SerialPrograms/Source/CommonTools/OCR/OCR_RawTesseractOCR.h:PageSegMode
OCR::StringMatchResult match_substring_from_image_multifiltered(
Logger* logger,
Language language,
Expand Down
19 changes: 3 additions & 16 deletions SerialPrograms/Source/CommonTools/OCR/OCR_NumberReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
#include "CommonTools/Images/ImageManip.h"
#include "CommonTools/Images/ImageFilter.h"
#include "CommonTools/Images/BinaryImage_FilterRgb32.h"
#include "OCR_RawOCR.h"
#include "OCR_RawPaddleOCR.h"
#include "OCR_Routines.h"
#include "OCR_NumberReader.h"

#include <iostream>
Expand Down Expand Up @@ -85,13 +84,7 @@ std::string run_number_normalization(const std::string& input){


int read_number(Logger& logger, const ImageViewRGB32& image, Language language){
bool use_paddle_ocr = false; // GlobalSettings::instance().USE_PADDLE_OCR;
std::string ocr_text;
if (use_paddle_ocr){
ocr_text = OCR::paddle_ocr_read(language, image);
}else{
ocr_text = OCR::ocr_read(language, image, OCR::PageSegMode::SINGLE_LINE);
}
std::string ocr_text = OCR::ocr_read(language, image, OCR::PageSegMode::SINGLE_LINE);

std::string normalized = run_number_normalization(ocr_text);

Expand Down Expand Up @@ -179,13 +172,7 @@ std::string read_number_waterfill_no_normalization(
}

ImageRGB32 padded = pad_image(cropped, 1 * cropped.width(), 0xffffffff);
bool use_paddle_ocr = false; // GlobalSettings::instance().USE_PADDLE_OCR;
std::string ocr;
if (use_paddle_ocr){
ocr = OCR::paddle_ocr_read(Language::English, padded);
}else{
ocr = OCR::ocr_read(Language::English, padded, OCR::PageSegMode::SINGLE_CHAR);
}
std::string ocr = OCR::ocr_read(Language::English, padded, OCR::PageSegMode::SINGLE_CHAR);

// padded.save("zztest-cropped" + std::to_string(c) + "-" + std::to_string(i++) + ".png");
// std::cout << ocr[0] << std::endl;
Expand Down
11 changes: 9 additions & 2 deletions SerialPrograms/Source/CommonTools/OCR/OCR_RawPaddleOCR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
*
*/

#include "ML/Inference/ML_PaddleOCRPipeline.h"
#include "Common/Cpp/Filesystem.h"
#include "Common/Cpp/Exceptions.h"
#include "Common/Cpp/Concurrency/SpinLock.h"
#include "CommonFramework/ImageTypes/ImageViewRGB32.h"
#include "OCR_RawOCR.h"
#include "ML/Inference/ML_PaddleOCRPipeline.h"
#include "OCR_RawPaddleOCR.h"

namespace PokemonAutomation{
namespace OCR{
Expand Down Expand Up @@ -50,6 +51,12 @@ LanguageGroup language_to_languagegroup(Language language){
}
}

bool paddle_ocr_language_available(Language language){
std::string path = ML::PaddleOCRPipeline::get_paths(language).first;
Filesystem::Path p{path};
return std::filesystem::exists(p);
}


// Global singleton managing the single PaddleOCR instance for each language.
// ocr_pool_lock protects the map
Expand Down
6 changes: 6 additions & 0 deletions SerialPrograms/Source/CommonTools/OCR/OCR_RawPaddleOCR.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
*
*/

// NOTE: This file should only be inluded in OCR_Routines.h
// This file should not be inluded in other files.
// Use OCR_Routines.h instead

#ifndef PokemonAutomation_CommonTools_OCR_RawPaddleOCR_H
#define PokemonAutomation_CommonTools_OCR_RawPaddleOCR_H

Expand All @@ -17,6 +21,8 @@ namespace PokemonAutomation{
}
namespace OCR{

bool paddle_ocr_language_available(Language language);


// Pre-warm the PaddleOCR instance pool for a language. Ensure one instance exists.
// Avoids lazy initialization delays during runtime. Thread-safe.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include "CommonFramework/Globals.h"
#include "CommonFramework/Logging/Logger.h"
#include "CommonFramework/ImageTypes/ImageViewRGB32.h"
#include "OCR_RawOCR.h"
#include "OCR_RawTesseractOCR.h"

#include <iostream>
using std::cout;
Expand All @@ -24,7 +24,7 @@ namespace PokemonAutomation{
namespace OCR{


bool language_available(Language language){
bool tesseract_language_available(Language language){
std::string path = RESOURCE_PATH();
path += "Tesseract/";
path += language_data(language).code;
Expand Down Expand Up @@ -179,7 +179,7 @@ struct OcrGlobals{
};


std::string ocr_read(Language language, const ImageViewRGB32& image, PageSegMode psm){
std::string tesseract_ocr_read(Language language, const ImageViewRGB32& image, PageSegMode psm){
// static size_t c = 0;
// image.save("ocr-" + std::to_string(c++) + ".png");

Expand All @@ -193,7 +193,7 @@ std::string ocr_read(Language language, const ImageViewRGB32& image, PageSegMode
// Get or create the pool for this language (lock only during map access).
std::map<Language, TesseractPool>::iterator iter;
{
WriteSpinLock lg(globals.ocr_pool_lock, "ocr_read()");
WriteSpinLock lg(globals.ocr_pool_lock, "tesseract_ocr_read()");
iter = ocr_pool.find(language);
if (iter == ocr_pool.end()){
iter = ocr_pool.emplace(language, language).first;
Expand All @@ -208,7 +208,7 @@ std::string ocr_read(Language language, const ImageViewRGB32& image, PageSegMode
}


void ensure_instances(Language language, size_t instances){
void ensure_tesseract_instances(Language language, size_t instances){
if (language == Language::None){
throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "Attempted to call OCR without a language.");
}
Expand All @@ -219,7 +219,7 @@ void ensure_instances(Language language, size_t instances){
// Get or create the pool for this language.
std::map<Language, TesseractPool>::iterator iter;
{
WriteSpinLock lg(globals.ocr_pool_lock, "ocr_read()");
WriteSpinLock lg(globals.ocr_pool_lock, "tesseract_ocr_read()");
iter = ocr_pool.find(language);
if (iter == ocr_pool.end()){
iter = ocr_pool.emplace(language, language).first;
Expand All @@ -229,7 +229,7 @@ void ensure_instances(Language language, size_t instances){
iter->second.ensure_instances(instances);
}

void clear_cache(){
void clear_tesseract_cache(){
OcrGlobals& globals = OcrGlobals::instance();
std::map<Language, TesseractPool>& ocr_pool = globals.ocr_pool;
WriteSpinLock lg(globals.ocr_pool_lock, "ocr_clear_cache()");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
*
*/

#ifndef PokemonAutomation_CommonTools_OCR_RawOCR_H
#define PokemonAutomation_CommonTools_OCR_RawOCR_H
// NOTE: This file should only be inluded in OCR_Routines.h
// This file should not be inluded in other files.
// Use OCR_Routines.h instead

#ifndef PokemonAutomation_CommonTools_OCR_RawTesseractOCR_H
#define PokemonAutomation_CommonTools_OCR_RawTesseractOCR_H

#include <string>
#include "CommonFramework/Language.h"
Expand Down Expand Up @@ -39,19 +43,19 @@ enum class PageSegMode : int {


// Check if Tesseract training data exists for the given language.
bool language_available(Language language);
bool tesseract_language_available(Language language);


// OCR the image in the specified language.
// Main OCR entry point. Performs OCR on the image using the specified language.
// Thread-safe: internally uses a pool of Tesseract API instances, able to accept
// multiple concurrent calls without delay or queueing.
// It creates a new Tesseract instances if no available idle instance. You can
// call `ensure_instances()` to pre-warm to pool with a given number of instances.
// call `ensure_tesseract_instances()` to pre-warm to pool with a given number of instances.
//
// psm: Page segmentation mode - controls how Tesseract interprets the image layout.
// Defaults to SINGLE_BLOCK (Tesseract C++ API's default) for best performance.
std::string ocr_read(
std::string tesseract_ocr_read(
Language language,
const ImageViewRGB32& image,
PageSegMode psm = PageSegMode::SINGLE_BLOCK
Expand All @@ -63,12 +67,12 @@ std::string ocr_read(
// Avoids lazy initialization delays during runtime. Thread-safe.
// Call this if you expect to need to do many OCR instances in parallel and you
// want to preload the OCR instances.
void ensure_instances(Language language, size_t instances);
void ensure_tesseract_instances(Language language, size_t instances);

// Clear all TesseractAPI instances for all languages. Used for cleanup or
// forcing re-initialization.
// This is not safe to call while in any OCR is still running!
void clear_cache();
void clear_tesseract_cache();



Expand Down
71 changes: 53 additions & 18 deletions SerialPrograms/Source/CommonTools/OCR/OCR_Routines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,68 @@
#include "CommonFramework/ImageTypes/ImageRGB32.h"
#include "CommonFramework/Tools/GlobalThreadPools.h"
#include "CommonFramework/GlobalSettingsPanel.h"
#include "CommonFramework/Exceptions/OperationFailedException.h"
#include "CommonTools/Images/ImageFilter.h"
#include "OCR_RawPaddleOCR.h"
#include "OCR_RawOCR.h"
#include "OCR_RawTesseractOCR.h"
#include "OCR_DictionaryMatcher.h"
#include "OCR_Routines.h"

// #include <iostream>
// using std::cout;
// using std::endl;
#include <iostream>
using std::cout;
using std::endl;



namespace PokemonAutomation{
namespace OCR{

// return true if the user enabled PaddleOCR and its resource has been downloaded
// NOTE: we are making the assumption that if English is downloaded,
// that all the other languages are downloaded too, since they're all downloaded
// as a bundle.
bool use_paddle_ocr(){
static bool use_paddle_ocr = GlobalSettings::instance().USE_PADDLE_OCR && paddle_ocr_language_available(Language::English);

return use_paddle_ocr;
}

bool ocr_language_available(Language language){
if (use_paddle_ocr()){
return OCR::paddle_ocr_language_available(language);
}else{
return OCR::tesseract_language_available(language);
}
}


std::string ocr_read(Language language, const ImageViewRGB32& image, PageSegMode psm){
std::string ocr_text = "";
if (use_paddle_ocr()){
ocr_text = OCR::paddle_ocr_read(language, image);
}else{
ocr_text = OCR::tesseract_ocr_read(language, image, OCR::PageSegMode::SINGLE_LINE);
}
return ocr_text;
}

void ensure_ocr_instances(Language language, size_t instances){
if (use_paddle_ocr()){
OCR::ensure_paddle_ocr_instance(language);
}else{
OCR::ensure_tesseract_instances(language, instances);
}
}

void clear_ocr_cache(){
if (use_paddle_ocr()){
OCR::clear_paddle_ocr_cache();
}else{
OCR::clear_tesseract_cache();
}
}



StringMatchResult multifiltered_OCR(
Language language, const DictionaryMatcher& dictionary, const ImageViewRGB32& image,
Expand All @@ -44,21 +91,14 @@ StringMatchResult multifiltered_OCR(

double pixels_inv = 1. / (image.width() * image.height());

bool use_paddle_ocr = GlobalSettings::instance().USE_PADDLE_OCR;

// Run all the filters.
SpinLock lock;
StringMatchResult ret;
GlobalThreadPools::computation_normal().run_in_parallel(
[&](size_t index){
const std::pair<ImageRGB32, size_t>& filtered = filtered_images[index];

std::string text;
if (use_paddle_ocr){
text = paddle_ocr_read(language, filtered.first);
}else{
text = ocr_read(language, filtered.first, psm);
}
std::string text = OCR::ocr_read(language, filtered.first, psm);

// cout << "multifiltered_OCR: " << index << " -> " << text << endl;
// filtered.first.save("test_" + std::to_string(index) + ".png");
Expand Down Expand Up @@ -110,12 +150,7 @@ StringMatchResult dictionary_OCR(
}

// Run all the filters.
std::string text;
if (GlobalSettings::instance().USE_PADDLE_OCR){
text = paddle_ocr_read(language, image);
}else{
text = ocr_read(language, image, psm);
}
std::string text = OCR::ocr_read(language, image, psm);

// cout << "dictionary_OCR: " << text << endl;
// image.save("test_dictionary_OCR.png");
Expand Down
11 changes: 9 additions & 2 deletions SerialPrograms/Source/CommonTools/OCR/OCR_Routines.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <cstdint>
#include <vector>
#include "CommonFramework/Language.h"
#include "OCR_RawOCR.h"
#include "OCR_RawTesseractOCR.h"

namespace PokemonAutomation{
class ImageViewRGB32;
Expand All @@ -30,9 +30,16 @@ struct TextColorRange{
{}
};

bool ocr_language_available(Language language);

std::string ocr_read(Language language, const ImageViewRGB32& image, PageSegMode psm = PageSegMode::SINGLE_LINE);

void ensure_ocr_instances(Language language, size_t instances = 1);

void clear_ocr_cache();

// psm: Tesseract Page Segmentation mode. See
// SerialPrograms/Source/CommonTools/OCR/OCR_RawOCR.h:PageSegMode
// SerialPrograms/Source/CommonTools/OCR/OCR_RawTesseractOCR.h:PageSegMode
StringMatchResult multifiltered_OCR(
Language language, const DictionaryMatcher& dictionary, const ImageViewRGB32& image,
const std::vector<TextColorRange>& text_color_ranges,
Expand Down
1 change: 0 additions & 1 deletion SerialPrograms/Source/CommonTools/OCR/OCR_TextMatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#include <set>
#include <map>
#include <QString>
#include "OCR_RawOCR.h"
#include "OCR_StringMatchResult.h"

namespace PokemonAutomation{
Expand Down
Loading
Loading