This commit is contained in:
UnknownObject
2026-07-17 15:50:06 +08:00
parent 1c65b30a64
commit 7f30fb78a4
4 changed files with 174 additions and 15 deletions
+136 -14
View File
@@ -1,16 +1,146 @@
// DLLUsageDemo.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // DLLUsageDemo.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
// //
#include <set>
#include <iostream> #include <iostream>
#include "LibEasyOCR-CPP.h" #include "LibEasyOCR-CPP.h"
#include <opencv2/highgui/highgui.hpp> #include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp> #include <opencv2/imgproc/imgproc.hpp>
#include <range/v3/view/enumerate.hpp>
#include <opencv2/photo/photo.hpp>
#include <opencv2/features2d.hpp>
static const std::set<char> validate_vin_chars = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','J','K','L','M','N','P','R','S','T','U','V','W','X','Y','Z' };
std::string PreProcessVIN(const std::string& vin)
{
std::string res;
for (const auto& chr : vin)
{
if ((chr == 'i') || (chr == 'I'))
res.push_back('1');
else if ((chr == 'o') || (chr == 'O'))
res.push_back('0');
else if (chr == 'q')
res.push_back('9');
else if (chr == 'Q')
res.push_back('0');
else if (validate_vin_chars.count(toupper(chr)) >= 1)
res.push_back(toupper(chr));
}
return res;
}
void RecognizeSingleImage(const std::string& img, int image_no)
{
cv::Mat image = cv::imread(img);
if (image.empty())
{
std::cout << "RSI: Unable to read image" << std::endl;
return;
}
//cv::blur(image, image, cv::Size(3, 3));
// 1. 灰度
cv::Mat gray;
cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
// 2. 去高光(inpaint
cv::Mat mask = gray > 240;
cv::inpaint(gray, mask, gray, 5, cv::INPAINT_TELEA);
// 3. 伽马校正(弱化阴影)
cv::Mat lut(1, 256, CV_8U);
const float gamma = 0.8f;
for (int i = 0; i < 256; i++)
lut.at<uchar>(i) = cv::saturate_cast<uchar>(std::pow(i / 255.0, gamma) * 255);
cv::LUT(gray, lut, gray);
// 4. CLAHE 局部对比度增强
cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE(2.0, cv::Size(8, 8));
clahe->apply(gray, gray);
// 2. 形态学 Top-hat & Black-hat 提取高频细节
cv::Mat kernel = cv::getStructuringElement(
cv::MORPH_RECT, cv::Size(15, 15));
cv::Mat tophat, blackhat;
cv::morphologyEx(gray, tophat, cv::MORPH_TOPHAT, kernel);
cv::morphologyEx(gray, blackhat, cv::MORPH_BLACKHAT, kernel);
// 3. 高频增强:原图 + tophat - blackhat
cv::Mat enhanced;
enhanced = gray + tophat - blackhat;
// 4. 平滑降噪
cv::GaussianBlur(enhanced, enhanced, cv::Size(3, 3), 0);
// 5. 全局 Otsu 阈值
cv::Mat bw;
cv::threshold(
enhanced, bw,
0, 255,
cv::THRESH_BINARY | cv::THRESH_OTSU
);
// 保证文字白底黑字
double m = cv::mean(bw.row(bw.rows / 2))[0];
if (m < 128) cv::bitwise_not(bw, bw);
// 6. 小核闭运算补笔画断裂
cv::morphologyEx(
bw, bw,
cv::MORPH_CLOSE,
cv::getStructuringElement(
cv::MORPH_RECT, cv::Size(3, 3)
),
cv::Point(-1, -1), 1
);
// 7. 小核开运算去孤立噪点
cv::morphologyEx(
bw, bw,
cv::MORPH_OPEN,
cv::getStructuringElement(
cv::MORPH_RECT, cv::Size(3, 3)
),
cv::Point(-1, -1), 1
);
// 8. 转三通道输出
cv::Mat finalBGR;
cv::cvtColor(bw, finalBGR, cv::COLOR_GRAY2BGR);
cv::Mat output = finalBGR.clone();
cv::imshow("Processed Image " + std::to_string(image_no), output);
cv::imwrite("G:\\Users\\15819\\Desktop\\temp\\Processed Image " + std::to_string(image_no) + ".jpg", output);
auto results = uns::EasyOCR_CPP::FullAuto(image);
for (const auto& [index, info] : results)
{
const auto& [text, conf, rect] = info;
std::string a_text = uns::EOCR_SupportTools::WtoA(text);
std::string processed_vin = PreProcessVIN(a_text);
printf("RSI(%d): Result %d: Text = {%s(%d) -> |%s|(%d)}, Box = [%d, %d, %d, %d], Confidence = %.3f\n", image_no, (int)index, a_text.c_str(), (int)a_text.length(), processed_vin.c_str(), (int)processed_vin.length(), rect.tl().x, rect.tl().y, rect.br().x, rect.br().y, conf);
}
if (results.empty())
printf("RSI(%d): No Text Found\n", image_no);
}
int main() int main()
{ {
std::wstring detect_model = L"..\\EasyOCR-CPP\\DetectionModel.onnx"; std::wstring detect_model = L"..\\EasyOCR-CPP\\DetectionModel.onnx";
std::wstring recognize_model = L"..\\EasyOCR-CPP\\RecognitionModel-EN.onnx"; std::wstring recognize_model = L"..\\EasyOCR-CPP\\RecognitionModel-EN.onnx";
std::string image = "..\\..\\vin.jpg";
std::vector<std::string> images =
{
"G:\\Users\\15819\\Desktop\\error\\UPLOAD-20250709184942-99F24141-6C0A31D2.jpg",
"G:\\Users\\15819\\Desktop\\error\\UPLOAD-20250709185025-99F24141-A56037A2.jpg",
"G:\\Users\\15819\\Desktop\\error\\UPLOAD-20250709185205-99F24141-1D0C341A.jpg",
"G:\\Users\\15819\\Desktop\\error\\UPLOAD-20250709185450-99F24141-EC43D7FD.jpg",
"G:\\Users\\15819\\Desktop\\error\\UPLOAD-20250708185403-99F24141-1F2233FA.jpg",
"G:\\Users\\15819\\Desktop\\error\\UPLOAD-20250708184942-99F24141-C138BA94.jpg"
};
uns::EasyOCR_CPP::GlobalOCRConfig().SetDetectModelPath(detect_model); uns::EasyOCR_CPP::GlobalOCRConfig().SetDetectModelPath(detect_model);
uns::EasyOCR_CPP::GlobalOCRConfig().SetGPUUsage(uns::easyocr::GPUUsage::CPUOnly); uns::EasyOCR_CPP::GlobalOCRConfig().SetGPUUsage(uns::easyocr::GPUUsage::CPUOnly);
@@ -27,20 +157,12 @@ int main()
return -2; return -2;
} }
cv::Mat img = uns::EOCR_SupportTools::ReadImage(image, true); for (auto&& [index, file] : images | ranges::views::enumerate)
if (img.empty()) RecognizeSingleImage(file, static_cast<int>(index));
{
std::cerr << "Failed to load image: " << image << std::endl;
return -1;
}
auto results = uns::EasyOCR_CPP::FullAuto(img);
for (const auto& [index, info] : results)
{
const auto& [text, conf, rect] = info;
printf("Result %d: Text = {%s}, Box = [%d, %d, %d, %d], Confidence = %.3f\n", (int)index, uns::EOCR_SupportTools::WtoA(text).c_str(), rect.tl().x, rect.tl().y, rect.br().x, rect.br().y, conf);
}
cv::waitKey(0);
uns::EasyOCR_CPP::CleanupOCR(); uns::EasyOCR_CPP::CleanupOCR();
return 0; return 0;
} }
//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
+9 -1
View File
@@ -5,13 +5,15 @@
#include <iostream> #include <iostream>
#include "EasyOCR_Detector.h" #include "EasyOCR_Detector.h"
#include "EasyOCR_Recognizer.h" #include "EasyOCR_Recognizer.h"
#include "OCRCharset.h"
int main() int main()
{ {
const std::wstring detModelPath = L".\\DetectionModel.onnx"; const std::wstring detModelPath = L".\\DetectionModel.onnx";
const std::wstring recModelPath = L".\\RecognitionModel-EN.onnx"; const std::wstring recModelPath = L".\\RecognitionModel-EN.onnx";
const std::wstring recModelWithChnPath = L".\\RecognitionModel_EN+CH_SIM.onnx"; const std::wstring recModelWithChnPath = L".\\RecognitionModel_EN+CH_SIM.onnx";
const std::string imagePath = "..\\..\\vin-err.jpg"; //const std::string imagePath = "..\\..\\vin-err.jpg";
const std::string imagePath = "G:\\Users\\15819\\Desktop\\error\\UPLOAD-20250709185205-99F24141-1D0C341A.jpg";
//Init Config //Init Config
uns::G_OCRConfig.SetGPUUsage(uns::OCRConfig::GPUUsage::CPUOnly); uns::G_OCRConfig.SetGPUUsage(uns::OCRConfig::GPUUsage::CPUOnly);
@@ -35,6 +37,12 @@ int main()
return -2; return -2;
} }
if (!uns::OCRCharset::CheckCharSet())
{
std::cout << "Charset Error" << std::endl;
return -3;
}
//Load Image //Load Image
cv::Mat image = cv::imread(imagePath); cv::Mat image = cv::imread(imagePath);
if (image.empty()) if (image.empty())
+27
View File
@@ -68,6 +68,7 @@ std::map<int, std::wstring> uns::OCRCharset::en_charmap =
{60, L"P"}, {60, L"P"},
{61, L"Q"}, {61, L"Q"},
{62, L"R"}, {62, L"R"},
{63, L"S"},
{64, L"T"}, {64, L"T"},
{65, L"U"}, {65, L"U"},
{66, L"V"}, {66, L"V"},
@@ -6826,6 +6827,32 @@ std::map<int, std::wstring> uns::OCRCharset::ch_en_charmap =
{6718, L""} {6718, L""}
}; };
bool uns::OCRCharset::CheckCharSet()
{
size_t siz_en = en_charmap.size();
size_t siz_ch_en = ch_en_charmap.size();
bool success_en = true, success_ch_en = true;
for (size_t i = 0; i < siz_en; i++)
if (en_charmap.find(i) == en_charmap.end())
{
std::cout << "EN CharMap: Error at " << i << std::endl;
success_en = false;
}
for (size_t i = 0; i < siz_ch_en; i++)
if (ch_en_charmap.find(i) == ch_en_charmap.end())
{
std::cout << "CH+EN CharMap: Error at " << i << std::endl;
success_ch_en = false;
}
std::cout << "Charset Check: EN: " << (success_en ? "Success" : "Failure") << ", CH+EN: " << (success_en ? "Success" : "Failure") << std::endl;
return (success_en && success_ch_en);
}
std::wstring uns::OCRCharset::GetChar(int index) std::wstring uns::OCRCharset::GetChar(int index)
{ {
if (index == 0) if (index == 0)
+2
View File
@@ -16,6 +16,8 @@ namespace uns
OCRCharset(const OCRCharset&) = delete; OCRCharset(const OCRCharset&) = delete;
public: public:
static bool CheckCharSet();
static std::wstring GetChar(int index); static std::wstring GetChar(int index);
static std::wstring GetString(const std::vector<int>& indexs); static std::wstring GetString(const std::vector<int>& indexs);
}; };