push
This commit is contained in:
+136
-14
@@ -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
|
||||||
@@ -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())
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user