| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include "utility.h" |
|
|
| #include <dirent.h> |
| #include <sys/stat.h> |
|
|
| #include <regex> |
|
|
| #include "ilogger.h" |
|
|
| absl::Status Utility::FileExists(const std::string &path) { |
| struct stat st; |
| if (stat(path.c_str(), &st) == 0) { |
| return absl::OkStatus(); |
| } else { |
| return absl::NotFoundError("File is not exist:" + path); |
| } |
| } |
| absl::StatusOr<std::map<std::string, std::pair<std::string, std::string>>> |
| Utility::GetModelPaths(const std::string &model_dir, |
| const std::string &model_file_prefix) { |
| std::map<std::string, std::pair<std::string, std::string>> model_paths; |
| std::string model_path; |
|
|
| std::string json_path = |
| model_dir + PATH_SEPARATOR + model_file_prefix + ".json"; |
| std::string pdmodel_path = |
| model_dir + PATH_SEPARATOR + model_file_prefix + ".pdmodel"; |
| std::string params_path = |
| model_dir + PATH_SEPARATOR + model_file_prefix + ".pdiparams"; |
| if (FileExists(json_path).ok()) { |
| model_path = json_path; |
| } else if (FileExists(pdmodel_path).ok()) { |
| model_path = pdmodel_path; |
| } else { |
| return absl::NotFoundError(FileExists(json_path).ToString() + " and " + |
| FileExists(pdmodel_path).ToString()); |
| } |
|
|
| if (model_path.empty()) { |
| return absl::NotFoundError( |
| "No PaddlePaddle model file (.json or .pdmodel) found!"); |
| } |
|
|
| if (FileExists(params_path).ok()) { |
| model_paths["paddle"] = std::make_pair(model_path, params_path); |
| } else { |
| return absl::NotFoundError( |
| "No PaddlePaddle params file (.pdiparams) found!"); |
| } |
|
|
| return model_paths; |
| } |
|
|
| absl::StatusOr<std::string> |
| Utility::FindModelPath(const std::string &model_dir, |
| const std::string &model_name) { |
| char last_char = model_dir.back(); |
| std::string model_path; |
| if (last_char == PATH_SEPARATOR) |
| model_path = model_dir + model_name; |
| else |
| model_path = model_dir + PATH_SEPARATOR + model_name; |
| auto status = FileExists(model_path); |
| if (!status.ok()) { |
| return status; |
| } |
| return model_path; |
| } |
| absl::StatusOr<std::string> |
| Utility::GetDefaultConfig(std::string pipeline_name) { |
| std::string current_path = __FILE__; |
| for (int i = 0; i < 2; i++) { |
| size_t pos = current_path.find_last_of(PATH_SEPARATOR); |
| if (pos == std::string::npos) { |
| return absl::NotFoundError("Could not find pipeline config yaml :" + |
| pipeline_name); |
| } |
| current_path = current_path.substr(0, pos); |
| } |
| std::string config_path_yaml = current_path + PATH_SEPARATOR + "configs" + |
| PATH_SEPARATOR + pipeline_name + ".yaml"; |
| std::string config_path_yml = current_path + PATH_SEPARATOR + "configs" + |
| PATH_SEPARATOR + pipeline_name + ".yml"; |
| if (FileExists(config_path_yaml).ok()) { |
| return config_path_yaml; |
| } else if (FileExists(config_path_yml).ok()) { |
| return config_path_yml; |
| } |
| return absl::NotFoundError("Could not find pipeline config yaml :" + |
| pipeline_name); |
| } |
| absl::StatusOr<std::string> |
| Utility::GetConfigPaths(const std::string &model_dir, |
| const std::string &model_file_prefix) { |
| std::string config_path = ""; |
| std::string config_path_find = |
| model_dir + PATH_SEPARATOR + model_file_prefix + ".yml"; |
| if (FileExists(config_path_find).ok()) { |
| config_path = config_path_find; |
| } else { |
| return FileExists(config_path_find); |
| } |
| return config_path; |
| }; |
|
|
| bool Utility::IsMkldnnAvailable() { |
| #ifdef _WIN32 |
| SYSTEM_INFO si; |
| GetSystemInfo(&si); |
|
|
| char cpuBrand[0x40] = {0}; |
| int cpuInfo[4] = {0}; |
| __cpuid(cpuInfo, 0x80000002); |
| memcpy(cpuBrand, cpuInfo, sizeof(cpuInfo)); |
| __cpuid(cpuInfo, 0x80000003); |
| memcpy(cpuBrand + 16, cpuInfo, sizeof(cpuInfo)); |
| __cpuid(cpuInfo, 0x80000004); |
| memcpy(cpuBrand + 32, cpuInfo, sizeof(cpuInfo)); |
| std::string brandStr(cpuBrand); |
| if (brandStr.find("Intel") != std::string::npos) { |
| return true; |
| } |
| return false; |
| #else |
| std::ifstream cpuinfo("/proc/cpuinfo"); |
| std::string line; |
| while (std::getline(cpuinfo, line)) { |
| if (line.find("vendor_id") != std::string::npos) { |
| auto pos = line.find(":"); |
| if (pos != std::string::npos) { |
| if (line.substr(pos + 2).find("Intel") != std::string::npos) { |
| return true; |
| } |
| } |
| } |
| } |
| return false; |
| #endif |
| }; |
|
|
| void Utility::PrintShape(const cv::Mat &img) { |
| for (int i = 0; i < img.dims; i++) { |
| std::cout << img.size[i] << " "; |
| } |
| std::cout << std::endl; |
| } |
|
|
| absl::Status Utility::MyCreateDirectory(const std::string &path) { |
| #ifdef _WIN32 |
| int ret = _mkdir(path.c_str()); |
| #else |
| int ret = mkdir(path.c_str(), 0755); |
| #endif |
| if (ret == 0) { |
| return absl::OkStatus(); |
| } |
| if (errno == EEXIST) { |
| return absl::OkStatus(); |
| } |
| return absl::ErrnoToStatus(errno, "Failed to create directory: " + path); |
| } |
|
|
| absl::Status Utility::MyCreatePath(const std::string &path) { |
| std::vector<std::string> paths; |
| std::string tmp; |
| for (size_t i = 0; i < path.size(); ++i) { |
| tmp += path[i]; |
| if (path[i] == PATH_SEPARATOR) { |
| paths.push_back(tmp); |
| } |
| } |
| if (!tmp.empty() && tmp.back() != PATH_SEPARATOR) |
| paths.push_back(tmp); |
|
|
| std::string current; |
| for (size_t i = 0; i < paths.size(); ++i) { |
| current += paths[i]; |
| absl::Status status = MyCreateDirectory(current); |
| if (!status.ok()) { |
| return status; |
| } |
| } |
| return absl::OkStatus(); |
| } |
|
|
| absl::Status Utility::MyCreateFile(const std::string &filepath) { |
| std::ifstream infile(filepath.c_str()); |
| if (infile.good()) { |
| return absl::OkStatus(); |
| } |
|
|
| std::ofstream outfile(filepath.c_str(), std::ios::out | std::ios::trunc); |
| if (!outfile.is_open()) { |
| return absl::InternalError("Failed to create file: " + filepath); |
| } |
|
|
| outfile.close(); |
| return absl::OkStatus(); |
| } |
|
|
| absl::StatusOr<std::vector<cv::Mat>> Utility::SplitBatch(const cv::Mat &batch) { |
| if (batch.dims < 1) { |
| return absl::InvalidArgumentError( |
| "Input batch must have at least 1 dimension."); |
| } |
| if (batch.type() != CV_32F) { |
| return absl::InvalidArgumentError( |
| "Input batch must have CV_32F element type."); |
| } |
|
|
| std::vector<cv::Mat> split_mats; |
| int batch_size = batch.size[0]; |
| std::vector<cv::Range> myranges(batch.dims); |
| for (int i = 0; i < batch_size; ++i) { |
| myranges[0] = cv::Range(i, i + 1); |
| for (int d = 1; d < batch.dims; ++d) |
| myranges[d] = cv::Range::all(); |
| cv::Mat sub_mat = batch(&myranges[0]); |
|
|
| split_mats.push_back(sub_mat); |
| } |
|
|
| return split_mats; |
| } |
|
|
| std::string Utility::GetFileExtension(const std::string &file_path) { |
| size_t pos = file_path.find_last_of('.'); |
| if (pos == std::string::npos || pos == file_path.length() - 1) { |
| return ""; |
| } |
| return file_path.substr(pos + 1); |
| } |
|
|
| std::string Utility::ToLower(const std::string &str) { |
| std::string result = str; |
| std::transform(result.begin(), result.end(), result.begin(), ::tolower); |
| return result; |
| } |
|
|
| bool Utility::IsDirectory(const std::string &path) { |
| struct stat path_stat; |
| if (stat(path.c_str(), &path_stat) != 0) { |
| return false; |
| } |
| return S_ISDIR(path_stat.st_mode); |
| } |
|
|
| void Utility::GetFilesRecursive(const std::string &dir_path, |
| std::vector<std::string> &file_list) { |
| DIR *dir = opendir(dir_path.c_str()); |
| if (dir == NULL) { |
| return; |
| } |
|
|
| struct dirent *entry; |
| while ((entry = readdir(dir)) != NULL) { |
| std::string name = entry->d_name; |
| if (name == "." || name == "..") { |
| continue; |
| } |
|
|
| std::string full_path = ""; |
| if (dir_path.back() == PATH_SEPARATOR) { |
| full_path = dir_path + name; |
| } else { |
| full_path = dir_path + PATH_SEPARATOR + name; |
| } |
|
|
| if (Utility::IsDirectory(full_path)) { |
| Utility::GetFilesRecursive(full_path, file_list); |
| } else if (IsImageFile(full_path)) { |
| file_list.push_back(full_path); |
| } |
| } |
|
|
| closedir(dir); |
| } |
|
|
| bool Utility::IsImageFile(const std::string &file_path) { |
| std::string extension = GetFileExtension(file_path); |
| std::string lower_ext = ToLower(extension); |
| return kImgSuffixes.find(lower_ext) != kImgSuffixes.end(); |
| } |
|
|
| absl::StatusOr<cv::Mat> Utility::MyLoadImage(const std::string &file_path) { |
| cv::Mat image = cv::imread(file_path, cv::IMREAD_COLOR); |
| if (image.empty()) { |
| return absl::InvalidArgumentError("Failed to load image: " + file_path); |
| } |
| return image; |
| } |
|
|
| int Utility::MakeDir(const std::string &path) { |
| #ifdef _WIN32 |
| return _mkdir(path.c_str()); |
| #else |
| return mkdir(path.c_str(), 0755); |
| #endif |
| } |
|
|
| absl::Status Utility::CreateDirectoryRecursive(const std::string &path) { |
| if (path.empty()) { |
| return absl::InvalidArgumentError("Path cannot be empty"); |
| } |
|
|
| size_t pos = 0; |
| std::string dir = path; |
| #ifdef _WIN32 |
| #define ACCESS _access |
| #define F_OK 0 |
| #else |
| #define ACCESS access |
| #endif |
| while (pos < dir.size()) { |
| pos = dir.find_first_of(PATH_SEPARATOR, pos + 1); |
| std::string subdir = (pos == std::string::npos) ? dir : dir.substr(0, pos); |
|
|
| if (!subdir.empty() && ACCESS(subdir.c_str(), F_OK) != 0) { |
| if (MakeDir(subdir) != 0) { |
| return absl::InternalError("Failed to create directory: " + subdir); |
| } |
| } |
|
|
| if (pos == std::string::npos) { |
| break; |
| } |
| } |
| return absl::OkStatus(); |
| } |
|
|
| absl::Status Utility::CreateDirectoryForFile(const std::string &filePath) { |
| size_t found = filePath.find_last_of(PATH_SEPARATOR); |
| if (found != std::string::npos) { |
| std::string dirPath = filePath.substr(0, found); |
| if (!CreateDirectoryRecursive(dirPath).ok()) { |
| return absl::InternalError("Failed to create file: " + filePath); |
| ; |
| } |
| } |
| return absl::OkStatus(); |
| } |
|
|
| absl::StatusOr<std::string> |
| Utility::SmartCreateDirectoryForImage(std::string save_path, |
| const std::string &input_path, |
| const std::string &suffix) { |
| size_t pos = save_path.find_last_of("/\\"); |
| std::string lastPart = save_path.substr(pos + 1); |
| if (lastPart.find(".") == std::string::npos) { |
| save_path += PATH_SEPARATOR; |
| } |
| std::string full_path = save_path; |
| auto status = CreateDirectoryForFile(save_path); |
| if (!status.ok()) { |
| return status; |
| } |
| if (Utility::IsDirectory(save_path)) { |
| auto file_path = input_path; |
| size_t pos = file_path.find_last_of("/\\"); |
| std::string file_name = |
| (pos == std::string::npos) ? file_path : file_path.substr(pos + 1); |
| size_t dot_pos = file_name.find_last_of('.'); |
| if (dot_pos == std::string::npos) { |
| file_name = file_name + suffix; |
| } else { |
| file_name.insert(dot_pos, suffix); |
| } |
| if (save_path.back() != PATH_SEPARATOR) { |
| full_path += PATH_SEPARATOR; |
| } |
| full_path += file_name; |
| } |
| return full_path; |
| } |
|
|
| absl::StatusOr<std::string> |
| Utility::SmartCreateDirectoryForJson(const std::string &save_path, |
| const std::string &input_path, |
| const std::string &suffix) { |
| auto full_path = SmartCreateDirectoryForImage(save_path, input_path, suffix); |
| if (!full_path.ok()) { |
| return full_path.status(); |
| } |
| size_t pos = full_path.value().rfind('.'); |
| if (pos != std::string::npos) { |
| full_path.value().replace(pos, std::string::npos, ".json"); |
| } |
| return full_path.value(); |
| } |
|
|
| absl::StatusOr<int> Utility::StringToInt(std::string s) { |
| std::regex pattern("(\\d+)"); |
| std::smatch match; |
| if (std::regex_search(s, match, pattern)) { |
| int value = std::stoi(match[1]); |
| return value; |
| } else { |
| return absl::NotFoundError("Could not find int !"); |
| } |
| } |
|
|
| bool Utility::StringToBool(const std::string &str) { |
| std::string result = str; |
| std::transform(result.begin(), result.end(), result.begin(), ::tolower); |
| assert(result == "true" || result == "false"); |
| if (result == "true") { |
| return true; |
| } else { |
| return false; |
| } |
| } |
|
|
| std::string Utility::VecToString(const std::vector<int> &input) { |
| std::string result; |
| for (auto it = input.begin(); it != input.end(); ++it) { |
| if (it != input.begin()) |
| result += ","; |
| result += std::to_string(*it); |
| } |
| return result; |
| } |
|
|
| absl::StatusOr<std::tuple<std::string, std::string, std::string>> |
| Utility::GetOcrModelInfo(std::string lang, std::string ppocr_version) { |
| |
| const static std::string PINGFANG_FONT = "PingFang-SC-Regular.ttf"; |
| const static std::string SIMFANG_FONT = "simfang.ttf"; |
| const static std::string LATIN_FONT = "latin.ttf"; |
| const static std::string KOREAN_FONT = "korean.ttf"; |
| const static std::string ARABIC_FONT = "arabic.ttf"; |
| const static std::string CYRILLIC_FONT = "cyrillic.ttf"; |
| const static std::string KANNADA_FONT = "kannada.ttf"; |
| const static std::string TELUGU_FONT = "telugu.ttf"; |
| const static std::string TAMIL_FONT = "tamil.ttf"; |
| const static std::string DEVANAGARI_FONT = "devanagari.ttf"; |
|
|
| |
| const static std::unordered_set<std::string> SUPPORT_PPOCR_VERSION = { |
| "PP-OCRv5", "PP-OCRv4", "PP-OCRv3"}; |
|
|
| |
| const static std::unordered_set<std::string> LATIN_LANGS = { |
| "af", "az", "bs", "cs", "cy", "da", "de", "es", "et", |
| "fr", "ga", "hr", "hu", "id", "is", "it", "ku", "la", |
| "lt", "lv", "mi", "ms", "mt", "nl", "no", "oc", "pi", |
| "pl", "pt", "ro", "rs_latin", "sk", "sl", "sq", "sv", "sw", |
| "tl", "tr", "uz", "vi", "french", "german"}; |
|
|
| const static std::unordered_set<std::string> ARABIC_LANGS = {"ar", "fa", "ug", |
| "ur"}; |
| const static std::unordered_set<std::string> ESLAV_LANGS = {"ru", "be", "uk"}; |
| const static std::unordered_set<std::string> CYRILLIC_LANGS = { |
| "ru", "rs_cyrillic", "be", "bg", "uk", "mn", "abq", "ady", |
| "kbd", "ava", "dar", "inh", "che", "lbe", "lez", "tab"}; |
| const static std::unordered_set<std::string> DEVANAGARI_LANGS = { |
| "hi", "mr", "ne", "bh", "mai", "ang", "bho", |
| "mah", "sck", "new", "gom", "sa", "bgc"}; |
| const static std::unordered_set<std::string> SPECIFIC_LANGS = { |
| "ch", "en", "korean", "japan", "chinese_cht", "te", "ka", "ta"}; |
|
|
| |
| if (!ppocr_version.empty() && |
| SUPPORT_PPOCR_VERSION.count(ppocr_version) == 0) { |
| return absl::InvalidArgumentError("Unsupported ppocr_version: " + |
| ppocr_version); |
| } |
|
|
| if (lang.empty()) |
| lang = "ch"; |
|
|
| |
| const static std::unordered_set<std::string> supported_langs = []() { |
| std::unordered_set<std::string> s; |
| s.insert(LATIN_LANGS.begin(), LATIN_LANGS.end()); |
| s.insert(ARABIC_LANGS.begin(), ARABIC_LANGS.end()); |
| s.insert(ESLAV_LANGS.begin(), ESLAV_LANGS.end()); |
| s.insert(CYRILLIC_LANGS.begin(), CYRILLIC_LANGS.end()); |
| s.insert(DEVANAGARI_LANGS.begin(), DEVANAGARI_LANGS.end()); |
| s.insert(SPECIFIC_LANGS.begin(), SPECIFIC_LANGS.end()); |
| s.insert("ch"); |
| return s; |
| }(); |
|
|
| if (supported_langs.count(lang) == 0) { |
| return absl::InvalidArgumentError("Unsupported lang: " + lang); |
| } |
|
|
| |
| if (ppocr_version.empty()) { |
| std::unordered_set<std::string> v5_langs = {"ch", "chinese_cht", "en", |
| "japan", "korean"}; |
| v5_langs.insert(LATIN_LANGS.begin(), LATIN_LANGS.end()); |
| v5_langs.insert(ESLAV_LANGS.begin(), ESLAV_LANGS.end()); |
|
|
| if (v5_langs.count(lang)) { |
| ppocr_version = "PP-OCRv5"; |
| } else { |
| std::unordered_set<std::string> v3_langs = LATIN_LANGS; |
| v3_langs.insert(ARABIC_LANGS.begin(), ARABIC_LANGS.end()); |
| v3_langs.insert(CYRILLIC_LANGS.begin(), CYRILLIC_LANGS.end()); |
| v3_langs.insert(DEVANAGARI_LANGS.begin(), DEVANAGARI_LANGS.end()); |
| v3_langs.insert(SPECIFIC_LANGS.begin(), SPECIFIC_LANGS.end()); |
|
|
| if (v3_langs.count(lang)) { |
| ppocr_version = "PP-OCRv3"; |
| } else { |
| return absl::InvalidArgumentError( |
| "Invalid lang and ocr_version combination!"); |
| } |
| } |
| } |
|
|
| |
| std::string det_model_name; |
| std::string rec_model_name; |
| std::string font_name = SIMFANG_FONT; |
|
|
| |
| if (ppocr_version == "PP-OCRv5") { |
| det_model_name = "PP-OCRv5_server_det"; |
| std::string rec_lang; |
|
|
| if (lang == "ch" || lang == "chinese_cht" || lang == "en" || |
| lang == "japan") { |
| rec_model_name = "PP-OCRv5_server_rec"; |
| font_name = SIMFANG_FONT; |
| } else if (LATIN_LANGS.count(lang)) { |
| rec_lang = "latin"; |
| font_name = LATIN_FONT; |
| } else if (ESLAV_LANGS.count(lang)) { |
| rec_lang = "eslav"; |
| font_name = CYRILLIC_FONT; |
| } else if (lang == "korean") { |
| rec_lang = "korean"; |
| font_name = KOREAN_FONT; |
| } |
|
|
| if (!rec_lang.empty()) { |
| rec_model_name = rec_lang + "_PP-OCRv5_mobile_rec"; |
| } |
| } else if (ppocr_version == "PP-OCRv4") { |
| if (lang == "ch") { |
| det_model_name = "PP-OCRv4_mobile_det"; |
| rec_model_name = "PP-OCRv4_mobile_rec"; |
| font_name = SIMFANG_FONT; |
| } else if (lang == "en") { |
| det_model_name = "PP-OCRv4_mobile_det"; |
| rec_model_name = "en_PP-OCRv4_mobile_rec"; |
| font_name = SIMFANG_FONT; |
| } else { |
| return absl::InvalidArgumentError( |
| "PP-OCRv4 only support ch and en languages!"); |
| } |
| } else { |
| det_model_name = "PP-OCRv3_mobile_det"; |
| std::string rec_lang; |
|
|
| if (LATIN_LANGS.count(lang)) { |
| rec_lang = "latin"; |
| font_name = LATIN_FONT; |
| } else if (ARABIC_LANGS.count(lang)) { |
| rec_lang = "arabic"; |
| font_name = ARABIC_FONT; |
| } else if (CYRILLIC_LANGS.count(lang)) { |
| rec_lang = "cyrillic"; |
| font_name = CYRILLIC_FONT; |
| } else if (DEVANAGARI_LANGS.count(lang)) { |
| rec_lang = "devanagari"; |
| font_name = DEVANAGARI_FONT; |
| } else if (SPECIFIC_LANGS.count(lang)) { |
| rec_lang = lang; |
| if (lang == "ka") { |
| font_name = KANNADA_FONT; |
| } else if (lang == "te") { |
| font_name = TELUGU_FONT; |
| } else if (lang == "ta") { |
| font_name = TAMIL_FONT; |
| } else if (lang == "ch") { |
| font_name = SIMFANG_FONT; |
| } |
| } |
|
|
| if (rec_lang == "ch") { |
| rec_model_name = "PP-OCRv3_mobile_rec"; |
| } else if (!rec_lang.empty()) { |
| rec_model_name = rec_lang + "_PP-OCRv3_mobile_rec"; |
| } |
| } |
|
|
| if (rec_model_name.empty()) { |
| return absl::InvalidArgumentError( |
| "Invalid lang and ocr_version combination!"); |
| } |
|
|
| return std::make_tuple(det_model_name, rec_model_name, font_name); |
| } |
| const std::set<std::string> Utility::kImgSuffixes = {"jpg", "png", "jpeg", |
| "bmp"}; |
|
|