Commit 5713e0ca authored by yangql's avatar yangql
Browse files

Initial commit

parents
Pipeline #501 canceled with stages
#ifdef __JNI__
#include "version.h"
#include <jni.h>
#include "OcrLite.h"
#include "OcrResultUtils.h"
#include "OcrUtils.h"
static OcrLite *ocrLite;
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *vm, void *reserved) {
ocrLite = new OcrLite();
return JNI_VERSION_1_4;
}
JNIEXPORT void JNICALL
JNI_OnUnload(JavaVM *vm, void *reserved) {
//printf("JNI_OnUnload\n");
delete ocrLite;
}
#ifdef _WIN32
char *jstringToChar(JNIEnv *env, jstring jstr) {
char *rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("gbk");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte *ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0) {
rtn = (char *) malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
}
#else
char *jstringToChar(JNIEnv *env, jstring input) {
char *str = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray) env->CallObjectMethod(input, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte *ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0) {
str = (char *) malloc(alen + 1);
memcpy(str, ba, alen);
str[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return str;
}
#endif
extern "C" JNIEXPORT jstring JNICALL
Java_com_benjaminwan_ocrlibrary_OcrEngine_getVersion(JNIEnv *env, jobject thiz) {
jstring ver = env->NewStringUTF(VERSION);
return ver;
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_benjaminwan_ocrlibrary_OcrEngine_setNumThread(JNIEnv *env, jobject thiz, jint numThread) {
ocrLite->setNumThread(numThread);
printf("numThread=%d\n", numThread);
return JNI_TRUE;
}
extern "C" JNIEXPORT void JNICALL
Java_com_benjaminwan_ocrlibrary_OcrEngine_initLogger(JNIEnv *env, jobject thiz, jboolean isConsole,
jboolean isPartImg, jboolean isResultImg) {
ocrLite->initLogger(isConsole,//isOutputConsole
isPartImg,//isOutputPartImg
isResultImg);//isOutputResultImg
}
extern "C" JNIEXPORT void JNICALL
Java_com_benjaminwan_ocrlibrary_OcrEngine_enableResultText(JNIEnv *env, jobject thiz, jstring input) {
std::string imgPath = jstringToChar(env, input);
std::string imgDir = imgPath.substr(0, imgPath.find_last_of('/') + 1);
std::string imgName = imgPath.substr(imgPath.find_last_of('/') + 1);
ocrLite->enableResultTxt(imgDir.c_str(), imgName.c_str());
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_benjaminwan_ocrlibrary_OcrEngine_initModels(JNIEnv *env, jobject thiz, jstring path,
jstring det, jstring cls, jstring rec, jstring keys) {
std::string modelsDir = jstringToChar(env, path);
std::string detName = jstringToChar(env, det);
std::string clsName = jstringToChar(env, cls);
std::string recName = jstringToChar(env, rec);
std::string keysName = jstringToChar(env, keys);
std::string modelDetPath = modelsDir + "/" + detName;
std::string modelClsPath = modelsDir + "/" + clsName;
std::string modelRecPath = modelsDir + "/" + recName;
std::string keysPath = modelsDir + "/" + keysName;
printf("modelsDir=%s\ndet=%s\ncls=%s\nrec=%s\nkeys=%s\n", modelsDir.c_str(), detName.c_str(), clsName.c_str(),
recName.c_str(), keysName.c_str());
bool hasModelDetFile = isFileExists(modelDetPath);
if (!hasModelDetFile) {
fprintf(stderr, "Model det file not found: %s\n", modelDetPath.c_str());
return false;
}
bool hasModelClsFile = isFileExists(modelClsPath);
if (!hasModelClsFile) {
fprintf(stderr, "Model cls file not found: %s\n", modelClsPath.c_str());
return false;
}
bool hasModelRecFile = isFileExists(modelRecPath);
if (!hasModelRecFile) {
fprintf(stderr, "Model rec file not found: %s\n", modelRecPath.c_str());
return false;
}
bool hasKeysFile = isFileExists(keysPath);
if (!hasKeysFile) {
fprintf(stderr, "keys file not found: %s\n", keysPath.c_str());
return false;
}
ocrLite->initModels(modelDetPath, modelClsPath, modelRecPath, keysPath);
return true;
}
extern "C" JNIEXPORT jobject JNICALL
Java_com_benjaminwan_ocrlibrary_OcrEngine_detect(JNIEnv *env, jobject thiz, jstring input, jint padding,
jint maxSideLen,
jfloat boxScoreThresh, jfloat boxThresh, jfloat unClipRatio,
jboolean doAngle, jboolean mostAngle
) {
std::string imgPath = jstringToChar(env, input);
bool hasTargetImgFile = isFileExists(imgPath);
if (!hasTargetImgFile) {
fprintf(stderr, "Target image not found: %s\n", imgPath.c_str());
OcrResult result{};
return OcrResultUtils(env, result).getJObject();
}
std::string imgDir = imgPath.substr(0, imgPath.find_last_of('/') + 1);
std::string imgName = imgPath.substr(imgPath.find_last_of('/') + 1);
printf("imgDir=%s, imgName=%s\n", imgDir.c_str(), imgName.c_str());
OcrResult result = ocrLite->detect(imgDir.c_str(), imgName.c_str(), padding, maxSideLen,
boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle);
return OcrResultUtils(env, result).getJObject();
}
#endif
\ No newline at end of file
#ifdef __JNI__
#include <OcrUtils.h>
#include "OcrResultUtils.h"
OcrResultUtils::OcrResultUtils(JNIEnv *env, OcrResult &ocrResult) {
jniEnv = env;
jclass jOcrResultClass = env->FindClass("com/benjaminwan/ocrlibrary/OcrResult");
if (jOcrResultClass == NULL) {
printf("OcrResult class is null\n");
}
jmethodID jOcrResultConstructor = env->GetMethodID(jOcrResultClass, "<init>",
"(DLjava/util/ArrayList;DLjava/lang/String;)V");
jobject textBlocks = getTextBlocks(ocrResult.textBlocks);
jdouble dbNetTime = (jdouble) ocrResult.dbNetTime;
jdouble detectTime = (jdouble) ocrResult.detectTime;
jstring jStrRest = jniEnv->NewStringUTF(ocrResult.strRes.c_str());
jOcrResult = env->NewObject(jOcrResultClass, jOcrResultConstructor, dbNetTime,
textBlocks, detectTime, jStrRest);
}
OcrResultUtils::~OcrResultUtils() {
jniEnv = NULL;
}
jobject OcrResultUtils::getJObject() {
return jOcrResult;
}
jclass OcrResultUtils::newJListClass() {
jclass clazz = jniEnv->FindClass("java/util/ArrayList");
if (clazz == NULL) {
printf("ArrayList class is null\n");
return NULL;
}
return clazz;
}
jmethodID OcrResultUtils::getListConstructor(jclass clazz) {
jmethodID constructor = jniEnv->GetMethodID(clazz, "<init>", "()V");
return constructor;
}
jobject OcrResultUtils::newJPoint(cv::Point &point) {
jclass clazz = jniEnv->FindClass("com/benjaminwan/ocrlibrary/Point");
if (clazz == NULL) {
printf("Point class is null\n");
return NULL;
}
jmethodID constructor = jniEnv->GetMethodID(clazz, "<init>", "(II)V");
jobject obj = jniEnv->NewObject(clazz, constructor, point.x, point.y);
return obj;
}
jobject OcrResultUtils::newJBoxPoint(std::vector<cv::Point> &boxPoint) {
jclass jListClass = newJListClass();
jmethodID jListConstructor = getListConstructor(jListClass);
jobject jList = jniEnv->NewObject(jListClass, jListConstructor);
jmethodID jListAdd = jniEnv->GetMethodID(jListClass, "add", "(Ljava/lang/Object;)Z");
for (auto point : boxPoint) {
jobject jPoint = newJPoint(point);
jniEnv->CallBooleanMethod(jList, jListAdd, jPoint);
}
return jList;
}
jobject OcrResultUtils::getTextBlock(TextBlock &textBlock) {
jobject jBoxPint = newJBoxPoint(textBlock.boxPoint);
jfloat jBoxScore = (jfloat) textBlock.boxScore;
jfloat jAngleScore = (jfloat) textBlock.angleScore;
jdouble jAngleTime = (jdouble) textBlock.angleTime;
jstring jText = jniEnv->NewStringUTF(textBlock.text.c_str());
jobject jCharScores = newJScoreArray(textBlock.charScores);
jdouble jCrnnTime = (jdouble) textBlock.crnnTime;
jdouble jBlockTime = (jdouble) textBlock.blockTime;
jclass clazz = jniEnv->FindClass("com/benjaminwan/ocrlibrary/TextBlock");
if (clazz == NULL) {
printf("TextBlock class is null\n");
return NULL;
}
jmethodID constructor = jniEnv->GetMethodID(clazz, "<init>",
"(Ljava/util/ArrayList;FIFDLjava/lang/String;[FDD)V");
jobject obj = jniEnv->NewObject(clazz, constructor, jBoxPint, jBoxScore, textBlock.angleIndex,
jAngleScore, jAngleTime, jText, jCharScores, jCrnnTime,
jBlockTime);
return obj;
}
jobject OcrResultUtils::getTextBlocks(std::vector<TextBlock> &textBlocks) {
jclass jListClass = newJListClass();
jmethodID jListConstructor = getListConstructor(jListClass);
jobject jList = jniEnv->NewObject(jListClass, jListConstructor);
jmethodID jListAdd = jniEnv->GetMethodID(jListClass, "add", "(Ljava/lang/Object;)Z");
for (int i = 0; i < textBlocks.size(); ++i) {
auto textBlock = textBlocks[i];
jobject jTextBlock = getTextBlock(textBlock);
jniEnv->CallBooleanMethod(jList, jListAdd, jTextBlock);
}
return jList;
}
jfloatArray OcrResultUtils::newJScoreArray(std::vector<float> &scores) {
jfloatArray jScores = jniEnv->NewFloatArray(scores.size());
jniEnv->SetFloatArrayRegion(jScores, 0, scores.size(), (jfloat *) scores.data());
return jScores;
}
#endif
\ No newline at end of file
#include <opencv2/opencv.hpp>
#include <numeric>
#include "OcrUtils.h"
#include "clipper.hpp"
double getCurrentTime() {
return (static_cast<double>(cv::getTickCount())) / cv::getTickFrequency() * 1000;//单位毫秒
}
//onnxruntime init windows
std::wstring strToWstr(std::string str) {
if (str.length() == 0)
return L"";
std::wstring wstr;
wstr.assign(str.begin(), str.end());
return wstr;
}
ScaleParam getScaleParam(cv::Mat &src, const float scale) {
int srcWidth = src.cols;
int srcHeight = src.rows;
int dstWidth = int((float) srcWidth * scale);
int dstHeight = int((float) srcHeight * scale);
if (dstWidth % 32 != 0) {
dstWidth = (dstWidth / 32 - 1) * 32;
dstWidth = (std::max)(dstWidth, 32);
}
if (dstHeight % 32 != 0) {
dstHeight = (dstHeight / 32 - 1) * 32;
dstHeight = (std::max)(dstHeight, 32);
}
float scaleWidth = (float) dstWidth / (float) srcWidth;
float scaleHeight = (float) dstHeight / (float) srcHeight;
return {srcWidth, srcHeight, dstWidth, dstHeight, scaleWidth, scaleHeight};
}
ScaleParam getScaleParam(cv::Mat &src, const int targetSize) {
int srcWidth, srcHeight, dstWidth, dstHeight;
srcWidth = dstWidth = src.cols;
srcHeight = dstHeight = src.rows;
float ratio = 1.f;
if (srcWidth > srcHeight) {
ratio = float(targetSize) / float(srcWidth);
} else {
ratio = float(targetSize) / float(srcHeight);
}
dstWidth = int(float(srcWidth) * ratio);
dstHeight = int(float(srcHeight) * ratio);
if (dstWidth % 32 != 0) {
dstWidth = (dstWidth / 32) * 32;
dstWidth = (std::max)(dstWidth, 32);
}
if (dstHeight % 32 != 0) {
dstHeight = (dstHeight / 32) * 32;
dstHeight = (std::max)(dstHeight, 32);
}
float ratioWidth = (float) dstWidth / (float) srcWidth;
float ratioHeight = (float) dstHeight / (float) srcHeight;
return {srcWidth, srcHeight, dstWidth, dstHeight, ratioWidth, ratioHeight};
}
std::vector<cv::Point2f> getBox(const cv::RotatedRect &rect) {
cv::Point2f vertices[4];
rect.points(vertices);
//std::vector<cv::Point2f> ret(4);
std::vector<cv::Point2f> ret2(vertices, vertices + sizeof(vertices) / sizeof(vertices[0]));
//memcpy(vertices, &ret[0], ret.size() * sizeof(ret[0]));
return ret2;
}
int getThickness(cv::Mat &boxImg) {
int minSize = boxImg.cols > boxImg.rows ? boxImg.rows : boxImg.cols;
int thickness = minSize / 1000 + 2;
return thickness;
}
void drawTextBox(cv::Mat &boxImg, cv::RotatedRect &rect, int thickness) {
cv::Point2f vertices[4];
rect.points(vertices);
for (int i = 0; i < 4; i++)
cv::line(boxImg, vertices[i], vertices[(i + 1) % 4], cv::Scalar(0, 0, 255), thickness);
//cv::polylines(srcmat, textpoint, true, cv::Scalar(0, 255, 0), 2);
}
void drawTextBox(cv::Mat &boxImg, const std::vector<cv::Point> &box, int thickness) {
auto color = cv::Scalar(0, 0, 255);// B(0) G(0) R(255)
cv::line(boxImg, box[0], box[1], color, thickness);
cv::line(boxImg, box[1], box[2], color, thickness);
cv::line(boxImg, box[2], box[3], color, thickness);
cv::line(boxImg, box[3], box[0], color, thickness);
}
void drawTextBoxes(cv::Mat &boxImg, std::vector<TextBox> &textBoxes, int thickness) {
for (auto & textBox : textBoxes) {
drawTextBox(boxImg, textBox.boxPoint, thickness);
}
}
cv::Mat matRotateClockWise180(cv::Mat src) {
flip(src, src, 0);
flip(src, src, 1);
return src;
}
cv::Mat matRotateClockWise90(cv::Mat src) {
transpose(src, src);
flip(src, src, 1);
return src;
}
cv::Mat getRotateCropImage(const cv::Mat &src, std::vector<cv::Point> box) {
cv::Mat image;
src.copyTo(image);
std::vector<cv::Point> points = box;
int collectX[4] = {box[0].x, box[1].x, box[2].x, box[3].x};
int collectY[4] = {box[0].y, box[1].y, box[2].y, box[3].y};
int left = int(*std::min_element(collectX, collectX + 4));
int right = int(*std::max_element(collectX, collectX + 4));
int top = int(*std::min_element(collectY, collectY + 4));
int bottom = int(*std::max_element(collectY, collectY + 4));
cv::Mat imgCrop;
image(cv::Rect(left, top, right - left, bottom - top)).copyTo(imgCrop);
for (auto &point: points) {
point.x -= left;
point.y -= top;
}
int imgCropWidth = int(sqrt(pow(points[0].x - points[1].x, 2) +
pow(points[0].y - points[1].y, 2)));
int imgCropHeight = int(sqrt(pow(points[0].x - points[3].x, 2) +
pow(points[0].y - points[3].y, 2)));
cv::Point2f ptsDst[4];
ptsDst[0] = cv::Point2f(0., 0.);
ptsDst[1] = cv::Point2f(imgCropWidth, 0.);
ptsDst[2] = cv::Point2f(imgCropWidth, imgCropHeight);
ptsDst[3] = cv::Point2f(0.f, imgCropHeight);
cv::Point2f ptsSrc[4];
ptsSrc[0] = cv::Point2f(points[0].x, points[0].y);
ptsSrc[1] = cv::Point2f(points[1].x, points[1].y);
ptsSrc[2] = cv::Point2f(points[2].x, points[2].y);
ptsSrc[3] = cv::Point2f(points[3].x, points[3].y);
cv::Mat M = cv::getPerspectiveTransform(ptsSrc, ptsDst);
cv::Mat partImg;
cv::warpPerspective(imgCrop, partImg, M,
cv::Size(imgCropWidth, imgCropHeight),
cv::BORDER_REPLICATE);
if (float(partImg.rows) >= float(partImg.cols) * 1.5) {
cv::Mat srcCopy = cv::Mat(partImg.rows, partImg.cols, partImg.depth());
cv::transpose(partImg, srcCopy);
cv::flip(srcCopy, srcCopy, 0);
return srcCopy;
} else {
return partImg;
}
}
cv::Mat adjustTargetImg(cv::Mat &src, int dstWidth, int dstHeight) {
cv::Mat srcResize;
float scale = (float) dstHeight / (float) src.rows;
int angleWidth = int((float) src.cols * scale);
cv::resize(src, srcResize, cv::Size(angleWidth, dstHeight));
cv::Mat srcFit = cv::Mat(dstHeight, dstWidth, CV_8UC3, cv::Scalar(255, 255, 255));
if (angleWidth < dstWidth) {
cv::Rect rect(0, 0, srcResize.cols, srcResize.rows);
srcResize.copyTo(srcFit(rect));
} else {
cv::Rect rect(0, 0, dstWidth, dstHeight);
srcResize(rect).copyTo(srcFit);
}
return srcFit;
}
bool cvPointCompare(const cv::Point &a, const cv::Point &b) {
return a.x < b.x;
}
std::vector<cv::Point2f> getMinBoxes(const cv::RotatedRect &boxRect, float &maxSideLen) {
maxSideLen = std::max(boxRect.size.width, boxRect.size.height);
std::vector<cv::Point2f> boxPoint = getBox(boxRect);
std::sort(boxPoint.begin(), boxPoint.end(), cvPointCompare);
int index1, index2, index3, index4;
if (boxPoint[1].y > boxPoint[0].y) {
index1 = 0;
index4 = 1;
} else {
index1 = 1;
index4 = 0;
}
if (boxPoint[3].y > boxPoint[2].y) {
index2 = 2;
index3 = 3;
} else {
index2 = 3;
index3 = 2;
}
std::vector<cv::Point2f> minBox(4);
minBox[0] = boxPoint[index1];
minBox[1] = boxPoint[index2];
minBox[2] = boxPoint[index3];
minBox[3] = boxPoint[index4];
return minBox;
}
float boxScoreFast(const std::vector<cv::Point2f> &boxes, const cv::Mat &pred) {
int width = pred.cols;
int height = pred.rows;
float arrayX[4] = {boxes[0].x, boxes[1].x, boxes[2].x, boxes[3].x};
float arrayY[4] = {boxes[0].y, boxes[1].y, boxes[2].y, boxes[3].y};
int minX = clamp(int(std::floor(*(std::min_element(arrayX, arrayX + 4)))), 0, width - 1);
int maxX = clamp(int(std::ceil(*(std::max_element(arrayX, arrayX + 4)))), 0, width - 1);
int minY = clamp(int(std::floor(*(std::min_element(arrayY, arrayY + 4)))), 0, height - 1);
int maxY = clamp(int(std::ceil(*(std::max_element(arrayY, arrayY + 4)))), 0, height - 1);
cv::Mat mask = cv::Mat::zeros(maxY - minY + 1, maxX - minX + 1, CV_8UC1);
cv::Point box[4];
box[0] = cv::Point(int(boxes[0].x) - minX, int(boxes[0].y) - minY);
box[1] = cv::Point(int(boxes[1].x) - minX, int(boxes[1].y) - minY);
box[2] = cv::Point(int(boxes[2].x) - minX, int(boxes[2].y) - minY);
box[3] = cv::Point(int(boxes[3].x) - minX, int(boxes[3].y) - minY);
const cv::Point *pts[1] = {box};
int npts[] = {4};
cv::fillPoly(mask, pts, npts, 1, cv::Scalar(1));
cv::Mat croppedImg;
pred(cv::Rect(minX, minY, maxX - minX + 1, maxY - minY + 1))
.copyTo(croppedImg);
auto score = (float) cv::mean(croppedImg, mask)[0];
return score;
}
float getContourArea(const std::vector<cv::Point2f> &box, float unClipRatio) {
size_t size = box.size();
float area = 0.0f;
float dist = 0.0f;
for (size_t i = 0; i < size; i++) {
area += box[i].x * box[(i + 1) % size].y -
box[i].y * box[(i + 1) % size].x;
dist += sqrtf((box[i].x - box[(i + 1) % size].x) *
(box[i].x - box[(i + 1) % size].x) +
(box[i].y - box[(i + 1) % size].y) *
(box[i].y - box[(i + 1) % size].y));
}
area = fabs(float(area / 2.0));
return area * unClipRatio / dist;
}
cv::RotatedRect unClip(std::vector<cv::Point2f> box, float unClipRatio) {
float distance = getContourArea(box, unClipRatio);
ClipperLib::ClipperOffset offset;
ClipperLib::Path p;
p << ClipperLib::IntPoint(int(box[0].x), int(box[0].y))
<< ClipperLib::IntPoint(int(box[1].x), int(box[1].y))
<< ClipperLib::IntPoint(int(box[2].x), int(box[2].y))
<< ClipperLib::IntPoint(int(box[3].x), int(box[3].y));
offset.AddPath(p, ClipperLib::jtRound, ClipperLib::etClosedPolygon);
ClipperLib::Paths soln;
offset.Execute(soln, distance);
std::vector<cv::Point2f> points;
for (size_t j = 0; j < soln.size(); j++) {
for (size_t i = 0; i < soln[soln.size() - 1].size(); i++) {
points.emplace_back(soln[j][i].X, soln[j][i].Y);
}
}
cv::RotatedRect res;
if (points.empty()) {
res = cv::RotatedRect(cv::Point2f(0, 0), cv::Size2f(1, 1), 0);
} else {
res = cv::minAreaRect(points);
}
return res;
}
std::vector<float> substractMeanNormalize(cv::Mat &src, const float *meanVals, const float *normVals) {
auto inputTensorSize = src.cols * src.rows * src.channels();
std::vector<float> inputTensorValues(inputTensorSize);
size_t numChannels = src.channels();
size_t imageSize = src.cols * src.rows;
for (size_t pid = 0; pid < imageSize; pid++) {
for (size_t ch = 0; ch < numChannels; ++ch) {
float data = (float) (src.data[pid * numChannels + ch] * normVals[ch] - meanVals[ch] * normVals[ch]);
inputTensorValues[ch * imageSize + pid] = data;
}
}
return inputTensorValues;
}
std::vector<int> getAngleIndexes(std::vector<Angle> &angles) {
std::vector<int> angleIndexes;
angleIndexes.reserve(angles.size());
for (auto &angle: angles) {
angleIndexes.push_back(angle.index);
}
return angleIndexes;
}
std::vector<Ort::AllocatedStringPtr> getInputNames(Ort::Session *session) {
Ort::AllocatorWithDefaultOptions allocator;
const size_t numInputNodes = session->GetInputCount();
std::vector<Ort::AllocatedStringPtr> inputNamesPtr;
inputNamesPtr.reserve(numInputNodes);
std::vector<int64_t> input_node_dims;
// iterate over all input nodes
for (size_t i = 0; i < numInputNodes; i++) {
auto inputName = session->GetInputNameAllocated(i, allocator);
inputNamesPtr.push_back(std::move(inputName));
}
return inputNamesPtr;
}
std::vector<Ort::AllocatedStringPtr> getOutputNames(Ort::Session *session) {
Ort::AllocatorWithDefaultOptions allocator;
const size_t numOutputNodes = session->GetOutputCount();
std::vector<Ort::AllocatedStringPtr> outputNamesPtr;
outputNamesPtr.reserve(numOutputNodes);
std::vector<int64_t> output_node_dims;
for (size_t i = 0; i < numOutputNodes; i++) {
auto outputName = session->GetOutputNameAllocated(i, allocator);
outputNamesPtr.push_back(std::move(outputName));
}
return outputNamesPtr;
}
void saveImg(cv::Mat &img, const char *imgPath) {
cv::imwrite(imgPath, img);
}
std::string getSrcImgFilePath(const char *path, const char *imgName) {
std::string filePath;
filePath.append(path).append(imgName);
return filePath;
}
std::string getResultTxtFilePath(const char *path, const char *imgName) {
std::string filePath;
filePath.append(path).append(imgName).append("-result.txt");
return filePath;
}
std::string getResultImgFilePath(const char *path, const char *imgName) {
std::string filePath;
filePath.append(path).append(imgName).append("-result.jpg");
return filePath;
}
std::string getDebugImgFilePath(const char *path, const char *imgName, size_t i, const char *tag) {
std::string filePath;
filePath.append(path).append(imgName).append(tag).append(std::to_string(i)).append(".jpg");
return filePath;
}
\ No newline at end of file
This diff is collapsed.
#ifndef __CLIB__
#include <stdio.h>
#include <string.h>
#include "getopt.h"
char *optarg = 0;
int optind = 1;
int opterr = 1;
int optopt = 0;
int postpone_count = 0;
int nextchar = 0;
static void postpone(int argc, char *const argv[], int index) {
char **nc_argv = (char **) argv;
char *p = nc_argv[index];
int j = index;
for (; j < argc - 1; j++) {
nc_argv[j] = nc_argv[j + 1];
}
nc_argv[argc - 1] = p;
}
static int postpone_noopt(int argc, char *const argv[], int index) {
int i = index;
for (; i < argc; i++) {
if (*(argv[i]) == '-') {
postpone(argc, argv, index);
return 1;
}
}
return 0;
}
static int _getopt_(int argc, char *const argv[],
const char *optstring,
const struct option *longopts, int *longindex) {
while (1) {
int c;
const char *optptr = 0;
if (optind >= argc - postpone_count) {
c = 0;
optarg = 0;
break;
}
c = *(argv[optind] + nextchar);
if (c == '\0') {
nextchar = 0;
++optind;
continue;
}
if (nextchar == 0) {
if (optstring[0] != '+' && optstring[0] != '-') {
while (c != '-') {
/* postpone non-opt parameter */
if (!postpone_noopt(argc, argv, optind)) {
break; /* all args are non-opt param */
}
++postpone_count;
c = *argv[optind];
}
}
if (c != '-') {
if (optstring[0] == '-') {
optarg = argv[optind];
nextchar = 0;
++optind;
return 1;
}
break;
} else {
if (strcmp(argv[optind], "--") == 0) {
optind++;
break;
}
++nextchar;
if (longopts != 0 && *(argv[optind] + 1) == '-') {
char const *spec_long = argv[optind] + 2;
char const *pos_eq = strchr(spec_long, '=');
int spec_len = (pos_eq == NULL ? strlen(spec_long) : pos_eq - spec_long);
int index_search = 0;
int index_found = -1;
const struct option *optdef = 0;
while (longopts->name != 0) {
if (strncmp(spec_long, longopts->name, spec_len) == 0) {
if (optdef != 0) {
if (opterr) {
fprintf(stderr, "ambiguous option: %s\n", spec_long);
}
return '?';
}
optdef = longopts;
index_found = index_search;
}
longopts++;
index_search++;
}
if (optdef == 0) {
if (opterr) {
fprintf(stderr, "no such a option: %s\n", spec_long);
}
return '?';
}
switch (optdef->has_arg) {
case no_argument:
optarg = 0;
if (pos_eq != 0) {
if (opterr) {
fprintf(stderr, "no argument for %s\n", optdef->name);
}
return '?';
}
break;
case required_argument:
if (pos_eq == NULL) {
++optind;
optarg = argv[optind];
} else {
optarg = (char *) pos_eq + 1;
}
break;
}
++optind;
nextchar = 0;
if (longindex != 0) {
*longindex = index_found;
}
if (optdef->flag != 0) {
*optdef->flag = optdef->val;
return 0;
}
return optdef->val;
}
continue;
}
}
optptr = strchr(optstring, c);
if (optptr == NULL) {
optopt = c;
if (opterr) {
fprintf(stderr,
"%s: invalid option -- %c\n",
argv[0], c);
}
++nextchar;
return '?';
}
if (*(optptr + 1) != ':') {
nextchar++;
if (*(argv[optind] + nextchar) == '\0') {
++optind;
nextchar = 0;
}
optarg = 0;
} else {
nextchar++;
if (*(argv[optind] + nextchar) != '\0') {
optarg = argv[optind] + nextchar;
} else {
++optind;
if (optind < argc - postpone_count) {
optarg = argv[optind];
} else {
optopt = c;
if (opterr) {
fprintf(stderr,
"%s: option requires an argument -- %c\n",
argv[0], c);
}
if (optstring[0] == ':' || ((optstring[0] == '-' || optstring[0] == '+') && optstring[1] == ':')) {
c = ':';
} else {
c = '?';
}
}
}
++optind;
nextchar = 0;
}
return c;
}
/* end of option analysis */
/* fix the order of non-opt params to original */
while ((argc - optind - postpone_count) > 0) {
postpone(argc, argv, optind);
++postpone_count;
}
nextchar = 0;
postpone_count = 0;
return -1;
}
int getopt(int argc, char *const argv[],
const char *optstring) {
return _getopt_(argc, argv, optstring, 0, 0);
}
int getopt_long(int argc, char *const argv[],
const char *optstring,
const struct option *longopts, int *longindex) {
return _getopt_(argc, argv, optstring, longopts, longindex);
}
#endif // __CLIB__
#ifndef __JNI__
#ifndef __CLIB__
#include <cstdio>
#include "main.h"
#include "version.h"
#include "OcrLite.h"
#include "OcrUtils.h"
void printHelp(FILE *out, char *argv0) {
fprintf(out, " ------- Usage -------\n");
fprintf(out, "%s %s", argv0, usageMsg);
fprintf(out, " ------- Required Parameters -------\n");
fprintf(out, "%s", requiredMsg);
fprintf(out, " ------- Optional Parameters -------\n");
fprintf(out, "%s", optionalMsg);
fprintf(out, " ------- Other Parameters -------\n");
fprintf(out, "%s", otherMsg);
fprintf(out, " ------- Examples -------\n");
fprintf(out, example1Msg, argv0);
fprintf(out, example2Msg, argv0);
}
int main(int argc, char **argv) {
if (argc <= -1) {
printHelp(stderr, argv[0]);
return -1;
}
std::string modelsDir = "../Resource/Models";
std::string modelDetPath= "../Resource/Models/ch_PP-OCRv3_det_infer.onnx";
std::string modelClsPath = "../Resource/Models/ch_ppocr_mobile_v2.0_cls_infer.onnx";
std::string modelRecPath = "../Resource/Models/ch_PP-OCRv3_rec_infer.onnx";
std::string keysPath = "../Resource/Models/ppocr_keys_v1.txt";
std::string imgPath, imgDir, imgName;
imgPath = "../Resource/Images/";
imgDir = "../Resource/Images/";
imgName = "1.jpg";
int numThread = 4;
int padding = 50;
int maxSideLen = 1024;
float boxScoreThresh = 0.5f;
float boxThresh = 0.3f;
float unClipRatio = 1.6f;
bool doAngle = true;
int flagDoAngle = 1;
bool mostAngle = true;
int flagMostAngle = 1;
int flagGpu = -1;
int opt;
int optionIndex = 0;
//判断路径配置是否存在
bool hasTargetImgFile = isFileExists(imgPath);
if (!hasTargetImgFile) {
fprintf(stderr, "Target image not found: %s\n", imgPath.c_str());
return -1;
}
bool hasModelDetFile = isFileExists(modelDetPath);
if (!hasModelDetFile) {
fprintf(stderr, "Model det file not found: %s\n", modelDetPath.c_str());
return -1;
}
bool hasModelClsFile = isFileExists(modelClsPath);
if (!hasModelClsFile) {
fprintf(stderr, "Model cls file not found: %s\n", modelClsPath.c_str());
return -1;
}
bool hasModelRecFile = isFileExists(modelRecPath);
if (!hasModelRecFile) {
fprintf(stderr, "Model rec file not found: %s\n", modelRecPath.c_str());
return -1;
}
bool hasKeysFile = isFileExists(keysPath);
if (!hasKeysFile) {
fprintf(stderr, "keys file not found: %s\n", keysPath.c_str());
return -1;
}
OcrLite ocrLite;
ocrLite.setNumThread(numThread);
ocrLite.initLogger(
true,//isOutputConsole
false,//isOutputPartImg
true);//isOutputResultImg
ocrLite.enableResultTxt(imgDir.c_str(), imgName.c_str());
ocrLite.setGpuIndex(flagGpu);
ocrLite.Logger("=====Input Params=====\n");
ocrLite.Logger(
"numThread(%d),padding(%d),maxSideLen(%d),boxScoreThresh(%f),boxThresh(%f),unClipRatio(%f),doAngle(%d),mostAngle(%d),GPU(%d)\n",
numThread, padding, maxSideLen, boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle,
flagGpu);
ocrLite.initModels(modelDetPath, modelClsPath, modelRecPath, keysPath);
OcrResult result = ocrLite.detect(imgDir.c_str(), imgName.c_str(), padding, maxSideLen,
boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle);
ocrLite.Logger("%s\n", result.strRes.c_str());
return 0;
}
#endif
#endif
\ No newline at end of file
#ifndef __OCR_ANGLENET_H__
#define __OCR_ANGLENET_H__
#include "OcrStruct.h"
#include <onnxruntime/core/session/onnxruntime_cxx_api.h>
#include <opencv2/opencv.hpp>
class AngleNet {
public:
~AngleNet();
void setNumThread(int numOfThread);
void setGpuIndex(int gpuIndex);
void initModel(const std::string &pathStr);
std::vector<Angle> getAngles(std::vector<cv::Mat> &partImgs, const char *path,
const char *imgName, bool doAngle, bool mostAngle);
private:
bool isOutputAngleImg = false;
Ort::Session *session;
Ort::Env env = Ort::Env(ORT_LOGGING_LEVEL_ERROR, "AngleNet");
Ort::SessionOptions sessionOptions = Ort::SessionOptions();
int numThread = 0;
std::vector<Ort::AllocatedStringPtr> inputNamesPtr;
std::vector<Ort::AllocatedStringPtr> outputNamesPtr;
const float meanValues[3] = {127.5, 127.5, 127.5};
const float normValues[3] = {1.0 / 127.5, 1.0 / 127.5, 1.0 / 127.5};
const int dstWidth = 192;
const int dstHeight = 48;
Angle getAngle(cv::Mat &src);
};
#endif //__OCR_ANGLENET_H__
#ifndef __OCR_CRNNNET_H__
#define __OCR_CRNNNET_H__
#include "OcrStruct.h"
#include <onnxruntime/core/session/onnxruntime_cxx_api.h>
#include <opencv2/opencv.hpp>
class CrnnNet {
public:
~CrnnNet();
void setNumThread(int numOfThread);
void setGpuIndex(int gpuIndex);
void initModel(const std::string &pathStr, const std::string &keysPath);
std::vector<TextLine> getTextLines(std::vector<cv::Mat> &partImg, const char *path, const char *imgName);
private:
bool isOutputDebugImg = false;
Ort::Session *session;
Ort::Env env = Ort::Env(ORT_LOGGING_LEVEL_ERROR, "CrnnNet");
Ort::SessionOptions sessionOptions = Ort::SessionOptions();
int numThread = 0;
std::vector<Ort::AllocatedStringPtr> inputNamesPtr;
std::vector<Ort::AllocatedStringPtr> outputNamesPtr;
const float meanValues[3] = {127.5, 127.5, 127.5};
const float normValues[3] = {1.0 / 127.5, 1.0 / 127.5, 1.0 / 127.5};
const int dstHeight = 48;
std::vector<std::string> keys;
TextLine scoreToTextLine(const std::vector<float> &outputData, size_t h, size_t w);
TextLine getTextLine(const cv::Mat &src);
};
#endif //__OCR_CRNNNET_H__
#ifndef __OCR_DBNET_H__
#define __OCR_DBNET_H__
#include "OcrStruct.h"
#include <onnxruntime/core/session/onnxruntime_cxx_api.h>
#include <opencv2/opencv.hpp>
class DbNet {
public:
~DbNet();
void setNumThread(int numOfThread);
void setGpuIndex(int gpuIndex);
void initModel(const std::string &pathStr);
std::vector<TextBox> getTextBoxes(cv::Mat &src, ScaleParam &s, float boxScoreThresh,
float boxThresh, float unClipRatio);
private:
Ort::Session *session;
Ort::Env env = Ort::Env(ORT_LOGGING_LEVEL_ERROR, "DbNet");
Ort::SessionOptions sessionOptions = Ort::SessionOptions();
int numThread = 0;
std::vector<Ort::AllocatedStringPtr> inputNamesPtr;
std::vector<Ort::AllocatedStringPtr> outputNamesPtr;
const float meanValues[3] = {0.485 * 255, 0.456 * 255, 0.406 * 255};
const float normValues[3] = {1.0 / 0.229 / 255.0, 1.0 / 0.224 / 255.0, 1.0 / 0.225 / 255.0};
};
#endif //__OCR_DBNET_H__
#ifndef __OCR_LITE_H__
#define __OCR_LITE_H__
#include <opencv2/opencv.hpp>
#include <onnxruntime/core/session/onnxruntime_cxx_api.h>
#include "OcrStruct.h"
#include "DbNet.h"
#include "AngleNet.h"
#include "CrnnNet.h"
class OcrLite {
public:
OcrLite();
~OcrLite();
void setNumThread(int numOfThread);
void initLogger(bool isConsole, bool isPartImg, bool isResultImg);
void enableResultTxt(const char *path, const char *imgName);
void setGpuIndex(int gpuIndex);
bool initModels(const std::string &detPath, const std::string &clsPath,
const std::string &recPath, const std::string &keysPath);
void Logger(const char *format, ...);
OcrResult detect(const char *path, const char *imgName,
int padding, int maxSideLen,
float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle);
OcrResult detect(const cv::Mat &mat,
int padding, int maxSideLen,
float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle);
private:
bool isOutputConsole = false;
bool isOutputPartImg = false;
bool isOutputResultTxt = false;
bool isOutputResultImg = false;
FILE *resultTxt;
DbNet dbNet;
AngleNet angleNet;
CrnnNet crnnNet;
std::vector<cv::Mat> getPartImages(cv::Mat &src, std::vector<TextBox> &textBoxes,
const char *path, const char *imgName);
OcrResult detect(const char *path, const char *imgName,
cv::Mat &src, cv::Rect &originRect, ScaleParam &scale,
float boxScoreThresh = 0.6f, float boxThresh = 0.3f,
float unClipRatio = 2.0f, bool doAngle = true, bool mostAngle = true);
};
#endif //__OCR_LITE_H__
#ifdef __cplusplus
#ifndef __OCR_LITE_C_API_H__
#define __OCR_LITE_C_API_H__
extern "C"
{
#ifdef WIN32
#ifdef __CLIB__
#define _QM_OCR_API __declspec(dllexport)
#else
#define _QM_OCR_API __declspec(dllimport)
#endif
#else
#define _QM_OCR_API
#endif
typedef void *OCR_HANDLE;
typedef char OCR_BOOL;
#ifndef NULL
#define NULL 0
#endif
#define TRUE 1
#define FALSE 0
typedef struct __ocr_param {
int padding;
int maxSideLen;
float boxScoreThresh;
float boxThresh;
float unClipRatio;
int doAngle; // 1 means do
int mostAngle; // 1 means true
} OCR_PARAM;
/*
By default, nThreads should be the number of threads
*/
_QM_OCR_API OCR_HANDLE
OcrInit(const char *szDetModel, const char *szClsModel, const char *szRecModel, const char *szKeyPath, int nThreads);
_QM_OCR_API OCR_BOOL
OcrDetect(OCR_HANDLE handle, const char *imgPath, const char *imgName, OCR_PARAM *pParam);
_QM_OCR_API int OcrGetLen(OCR_HANDLE handle);
_QM_OCR_API OCR_BOOL OcrGetResult(OCR_HANDLE handle, char *szBuf, int nLen);
_QM_OCR_API void OcrDestroy(OCR_HANDLE handle);
};
#endif //__OCR_LITE_C_API_H__
#endif //__cplusplus
#ifdef __JNI__
#ifndef __OCR_RESULT_UTILS_H__
#define __OCR_RESULT_UTILS_H__
#include <jni.h>
#include "OcrStruct.h"
class OcrResultUtils {
public:
OcrResultUtils(JNIEnv *env, OcrResult &ocrResult);
~OcrResultUtils();
jobject getJObject();
private:
JNIEnv *jniEnv;
jobject jOcrResult;
jclass newJListClass();
jmethodID getListConstructor(jclass clazz);
jobject getTextBlock(TextBlock &textBlock);
jobject getTextBlocks(std::vector<TextBlock> &textBlocks);
jobject newJPoint(cv::Point &point);
jobject newJBoxPoint(std::vector<cv::Point> &boxPoint);
jfloatArray newJScoreArray(std::vector<float> &scores);
};
#endif //__OCR_RESULT_UTILS_H__
#endif
#ifndef __OCR_STRUCT_H__
#define __OCR_STRUCT_H__
#include <opencv2/opencv.hpp>
#include <vector>
struct ScaleParam {
int srcWidth;
int srcHeight;
int dstWidth;
int dstHeight;
float ratioWidth;
float ratioHeight;
};
struct TextBox {
std::vector<cv::Point> boxPoint;
float score;
};
struct Angle {
int index;
float score;
double time;
};
struct TextLine {
std::string text;
std::vector<float> charScores;
double time;
};
struct TextBlock {
std::vector<cv::Point> boxPoint;
float boxScore;
int angleIndex;
float angleScore;
double angleTime;
std::string text;
std::vector<float> charScores;
double crnnTime;
double blockTime;
};
struct OcrResult {
double dbNetTime;
std::vector<TextBlock> textBlocks;
cv::Mat boxImg;
double detectTime;
std::string strRes;
};
#endif //__OCR_STRUCT_H__
#ifndef __OCR_UTILS_H__
#define __OCR_UTILS_H__
#include <opencv2/opencv.hpp>
#include "OcrStruct.h"
#include <onnxruntime/core/session/onnxruntime_cxx_api.h>
#include <numeric>
#include <sys/stat.h>
template<typename T, typename... Ts>
static std::unique_ptr<T> makeUnique(Ts &&... params) {
return std::unique_ptr<T>(new T(std::forward<Ts>(params)...));
}
template<typename T>
static double getMean(std::vector<T> &input) {
auto sum = accumulate(input.begin(), input.end(), 0.0);
return sum / input.size();
}
template<typename T>
static double getStdev(std::vector<T> &input, double mean) {
if (input.size() <= 1) return 0;
double accum = 0.0;
for_each(input.begin(), input.end(), [&](const double d) {
accum += (d - mean) * (d - mean);
});
double stdev = sqrt(accum / (input.size() - 1));
return stdev;
}
template<class T>
inline T clamp(T x, T min, T max) {
if (x > max)
return max;
if (x < min)
return min;
return x;
}
double getCurrentTime();
inline bool isFileExists(const std::string &name) {
struct stat buffer;
return (stat(name.c_str(), &buffer) == 0);
}
std::wstring strToWstr(std::string str);
ScaleParam getScaleParam(cv::Mat &src, const float scale);
ScaleParam getScaleParam(cv::Mat &src, const int targetSize);
std::vector<cv::Point2f> getBox(const cv::RotatedRect &rect);
int getThickness(cv::Mat &boxImg);
void drawTextBox(cv::Mat &boxImg, cv::RotatedRect &rect, int thickness);
void drawTextBox(cv::Mat &boxImg, const std::vector<cv::Point> &box, int thickness);
void drawTextBoxes(cv::Mat &boxImg, std::vector<TextBox> &textBoxes, int thickness);
cv::Mat matRotateClockWise180(cv::Mat src);
cv::Mat matRotateClockWise90(cv::Mat src);
cv::Mat getRotateCropImage(const cv::Mat &src, std::vector<cv::Point> box);
cv::Mat adjustTargetImg(cv::Mat &src, int dstWidth, int dstHeight);
std::vector<cv::Point2f> getMinBoxes(const cv::RotatedRect &boxRect, float &maxSideLen);
float boxScoreFast(const std::vector<cv::Point2f> &boxes, const cv::Mat &pred);
cv::RotatedRect unClip(std::vector<cv::Point2f> box, float unClipRatio);
std::vector<float> substractMeanNormalize(cv::Mat &src, const float *meanVals, const float *normVals);
std::vector<int> getAngleIndexes(std::vector<Angle> &angles);
std::vector<Ort::AllocatedStringPtr> getInputNames(Ort::Session *session);
std::vector<Ort::AllocatedStringPtr> getOutputNames(Ort::Session *session);
void saveImg(cv::Mat &img, const char *imgPath);
std::string getSrcImgFilePath(const char *path, const char *imgName);
std::string getResultTxtFilePath(const char *path, const char *imgName);
std::string getResultImgFilePath(const char *path, const char *imgName);
std::string getDebugImgFilePath(const char *path, const char *imgName, size_t i, const char *tag);
#endif //__OCR_UTILS_H__
#ifndef clipper_hpp
#define clipper_hpp
#define CLIPPER_VERSION "6.4.2"
//use_int32: When enabled 32bit ints are used instead of 64bit ints. This
//improve performance but coordinate values are limited to the range +/- 46340
//#define use_int32
//use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance.
//#define use_xyz
//use_lines: Enables line clipping. Adds a very minor cost to performance.
#define use_lines
//use_deprecated: Enables temporary support for the obsolete functions
//#define use_deprecated
#include <vector>
#include <list>
#include <set>
#include <stdexcept>
#include <cstring>
#include <cstdlib>
#include <ostream>
#include <functional>
#include <queue>
namespace ClipperLib {
enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
enum PolyType { ptSubject, ptClip };
//By far the most widely used winding rules for polygon filling are
//EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32)
//Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL)
//see http://glprogramming.com/red/chapter11.html
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
#ifdef use_int32
typedef int cInt;
static cInt const loRange = 0x7FFF;
static cInt const hiRange = 0x7FFF;
#else
typedef signed long long cInt;
static cInt const loRange = 0x3FFFFFFF;
static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
typedef signed long long long64; //used by Int128 class
typedef unsigned long long ulong64;
#endif
struct IntPoint {
cInt X;
cInt Y;
#ifdef use_xyz
cInt Z;
IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {};
#else
IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {};
#endif
friend inline bool operator== (const IntPoint& a, const IntPoint& b)
{
return a.X == b.X && a.Y == b.Y;
}
friend inline bool operator!= (const IntPoint& a, const IntPoint& b)
{
return a.X != b.X || a.Y != b.Y;
}
};
//------------------------------------------------------------------------------
typedef std::vector< IntPoint > Path;
typedef std::vector< Path > Paths;
inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;}
inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;}
std::ostream& operator <<(std::ostream &s, const IntPoint &p);
std::ostream& operator <<(std::ostream &s, const Path &p);
std::ostream& operator <<(std::ostream &s, const Paths &p);
struct DoublePoint
{
double X;
double Y;
DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {}
DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {}
};
//------------------------------------------------------------------------------
#ifdef use_xyz
typedef void (*ZFillCallback)(IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt);
#endif
enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4};
enum JoinType {jtSquare, jtRound, jtMiter};
enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound};
class PolyNode;
typedef std::vector< PolyNode* > PolyNodes;
class PolyNode
{
public:
PolyNode();
virtual ~PolyNode(){};
Path Contour;
PolyNodes Childs;
PolyNode* Parent;
PolyNode* GetNext() const;
bool IsHole() const;
bool IsOpen() const;
int ChildCount() const;
private:
//PolyNode& operator =(PolyNode& other);
unsigned Index; //node index in Parent.Childs
bool m_IsOpen;
JoinType m_jointype;
EndType m_endtype;
PolyNode* GetNextSiblingUp() const;
void AddChild(PolyNode& child);
friend class Clipper; //to access Index
friend class ClipperOffset;
};
class PolyTree: public PolyNode
{
public:
~PolyTree(){ Clear(); };
PolyNode* GetFirst() const;
void Clear();
int Total() const;
private:
//PolyTree& operator =(PolyTree& other);
PolyNodes AllNodes;
friend class Clipper; //to access AllNodes
};
bool Orientation(const Path &poly);
double Area(const Path &poly);
int PointInPolygon(const IntPoint &pt, const Path &path);
void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd);
void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415);
void CleanPolygon(Path& poly, double distance = 1.415);
void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415);
void CleanPolygons(Paths& polys, double distance = 1.415);
void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed);
void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed);
void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution);
void PolyTreeToPaths(const PolyTree& polytree, Paths& paths);
void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths);
void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths);
void ReversePath(Path& p);
void ReversePaths(Paths& p);
struct IntRect { cInt left; cInt top; cInt right; cInt bottom; };
//enums that are used internally ...
enum EdgeSide { esLeft = 1, esRight = 2};
//forward declarations (for stuff used internally) ...
struct TEdge;
struct IntersectNode;
struct LocalMinimum;
struct OutPt;
struct OutRec;
struct Join;
typedef std::vector < OutRec* > PolyOutList;
typedef std::vector < TEdge* > EdgeList;
typedef std::vector < Join* > JoinList;
typedef std::vector < IntersectNode* > IntersectList;
//------------------------------------------------------------------------------
//ClipperBase is the ancestor to the Clipper class. It should not be
//instantiated directly. This class simply abstracts the conversion of sets of
//polygon coordinates into edge objects that are stored in a LocalMinima list.
class ClipperBase
{
public:
ClipperBase();
virtual ~ClipperBase();
virtual bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed);
virtual void Clear();
IntRect GetBounds();
bool PreserveCollinear() {return m_PreserveCollinear;};
void PreserveCollinear(bool value) {m_PreserveCollinear = value;};
protected:
void DisposeLocalMinimaList();
TEdge* AddBoundsToLML(TEdge *e, bool IsClosed);
virtual void Reset();
TEdge* ProcessBound(TEdge* E, bool IsClockwise);
void InsertScanbeam(const cInt Y);
bool PopScanbeam(cInt &Y);
bool LocalMinimaPending();
bool PopLocalMinima(cInt Y, const LocalMinimum *&locMin);
OutRec* CreateOutRec();
void DisposeAllOutRecs();
void DisposeOutRec(PolyOutList::size_type index);
void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
void DeleteFromAEL(TEdge *e);
void UpdateEdgeIntoAEL(TEdge *&e);
typedef std::vector<LocalMinimum> MinimaList;
MinimaList::iterator m_CurrentLM;
MinimaList m_MinimaList;
bool m_UseFullRange;
EdgeList m_edges;
bool m_PreserveCollinear;
bool m_HasOpenPaths;
PolyOutList m_PolyOuts;
TEdge *m_ActiveEdges;
typedef std::priority_queue<cInt> ScanbeamList;
ScanbeamList m_Scanbeam;
};
//------------------------------------------------------------------------------
class Clipper : public virtual ClipperBase
{
public:
Clipper(int initOptions = 0);
bool Execute(ClipType clipType,
Paths &solution,
PolyFillType fillType = pftEvenOdd);
bool Execute(ClipType clipType,
Paths &solution,
PolyFillType subjFillType,
PolyFillType clipFillType);
bool Execute(ClipType clipType,
PolyTree &polytree,
PolyFillType fillType = pftEvenOdd);
bool Execute(ClipType clipType,
PolyTree &polytree,
PolyFillType subjFillType,
PolyFillType clipFillType);
bool ReverseSolution() { return m_ReverseOutput; };
void ReverseSolution(bool value) {m_ReverseOutput = value;};
bool StrictlySimple() {return m_StrictSimple;};
void StrictlySimple(bool value) {m_StrictSimple = value;};
//set the callback function for z value filling on intersections (otherwise Z is 0)
#ifdef use_xyz
void ZFillFunction(ZFillCallback zFillFunc);
#endif
protected:
virtual bool ExecuteInternal();
private:
JoinList m_Joins;
JoinList m_GhostJoins;
IntersectList m_IntersectList;
ClipType m_ClipType;
typedef std::list<cInt> MaximaList;
MaximaList m_Maxima;
TEdge *m_SortedEdges;
bool m_ExecuteLocked;
PolyFillType m_ClipFillType;
PolyFillType m_SubjFillType;
bool m_ReverseOutput;
bool m_UsingPolyTree;
bool m_StrictSimple;
#ifdef use_xyz
ZFillCallback m_ZFill; //custom callback
#endif
void SetWindingCount(TEdge& edge);
bool IsEvenOddFillType(const TEdge& edge) const;
bool IsEvenOddAltFillType(const TEdge& edge) const;
void InsertLocalMinimaIntoAEL(const cInt botY);
void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge);
void AddEdgeToSEL(TEdge *edge);
bool PopEdgeFromSEL(TEdge *&edge);
void CopyAELToSEL();
void DeleteFromSEL(TEdge *e);
void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
bool IsContributing(const TEdge& edge) const;
bool IsTopHorz(const cInt XPos);
void DoMaxima(TEdge *e);
void ProcessHorizontals();
void ProcessHorizontal(TEdge *horzEdge);
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
OutRec* GetOutRec(int idx);
void AppendPolygon(TEdge *e1, TEdge *e2);
void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt);
OutPt* AddOutPt(TEdge *e, const IntPoint &pt);
OutPt* GetLastOutPt(TEdge *e);
bool ProcessIntersections(const cInt topY);
void BuildIntersectList(const cInt topY);
void ProcessIntersectList();
void ProcessEdgesAtTopOfScanbeam(const cInt topY);
void BuildResult(Paths& polys);
void BuildResult2(PolyTree& polytree);
void SetHoleState(TEdge *e, OutRec *outrec);
void DisposeIntersectNodes();
bool FixupIntersectionOrder();
void FixupOutPolygon(OutRec &outrec);
void FixupOutPolyline(OutRec &outrec);
bool IsHole(TEdge *e);
bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl);
void FixHoleLinkage(OutRec &outrec);
void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt);
void ClearJoins();
void ClearGhostJoins();
void AddGhostJoin(OutPt *op, const IntPoint offPt);
bool JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2);
void JoinCommonEdges();
void DoSimplePolygons();
void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec);
void FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec);
void FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec);
#ifdef use_xyz
void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2);
#endif
};
//------------------------------------------------------------------------------
class ClipperOffset
{
public:
ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25);
~ClipperOffset();
void AddPath(const Path& path, JoinType joinType, EndType endType);
void AddPaths(const Paths& paths, JoinType joinType, EndType endType);
void Execute(Paths& solution, double delta);
void Execute(PolyTree& solution, double delta);
void Clear();
double MiterLimit;
double ArcTolerance;
private:
Paths m_destPolys;
Path m_srcPoly;
Path m_destPoly;
std::vector<DoublePoint> m_normals;
double m_delta, m_sinA, m_sin, m_cos;
double m_miterLim, m_StepsPerRad;
IntPoint m_lowest;
PolyNode m_polyNodes;
void FixOrientations();
void DoOffset(double delta);
void OffsetPoint(int j, int& k, JoinType jointype);
void DoSquare(int j, int k);
void DoMiter(int j, int k, double r);
void DoRound(int j, int k);
};
//------------------------------------------------------------------------------
class clipperException : public std::exception
{
public:
clipperException(const char* description): m_descr(description) {}
virtual ~clipperException() throw() {}
virtual const char* what() const throw() {return m_descr.c_str();}
private:
std::string m_descr;
};
//------------------------------------------------------------------------------
} //ClipperLib namespace
#endif //clipper_hpp
#ifndef _GETOPT_H_
#define _GETOPT_H_
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
int getopt(int argc, char *const argv[],
const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
#define no_argument 0
#define required_argument 1
#define optional_argument 2
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
int getopt_long(int argc, char *const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
/****************************************************************************
int getopt_long_only(int argc, char* const argv[],
const char* optstring,
const struct option* longopts, int* longindex);
****************************************************************************/
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _GETOPT_H_
#ifndef __MAIN_H__
#define __MAIN_H__
#include "getopt.h"
static const struct option long_options[] = {
{"models", required_argument, NULL, 'd'},
{"det", required_argument, NULL, '1'},
{"cls", required_argument, NULL, '2'},
{"rec", required_argument, NULL, '3'},
{"keys", required_argument, NULL, '4'},
{"image", required_argument, NULL, 'i'},
{"numThread", required_argument, NULL, 't'},
{"padding", required_argument, NULL, 'p'},
{"maxSideLen", required_argument, NULL, 's'},
{"boxScoreThresh", required_argument, NULL, 'b'},
{"boxThresh", required_argument, NULL, 'o'},
{"unClipRatio", required_argument, NULL, 'u'},
{"doAngle", required_argument, NULL, 'a'},
{"mostAngle", required_argument, NULL, 'A'},
{"version", no_argument, NULL, 'v'},
{"help", no_argument, NULL, 'h'},
{"loopCount", required_argument, NULL, 'l'},
{"GPU", required_argument, NULL, 'G'},
{NULL, no_argument, NULL, 0}
};
const char *usageMsg = "(-d --models) (-1 --det) (-2 --cls) (-3 --rec) (-4 --keys) (-i --image)\n"\
"[-t --numThread] [-p --padding] [-s --maxSideLen]\n" \
"[-b --boxScoreThresh] [-o --boxThresh] [-u --unClipRatio]\n" \
"[-a --noAngle] [-A --mostAngle] [-G --GPU]\n\n";
const char *requiredMsg = "-d --models: models directory.\n" \
"-1 --det: model file name of det.\n" \
"-2 --cls: model file name of cls.\n" \
"-3 --rec: model file name of rec.\n" \
"-4 --keys: keys file name.\n" \
"-i --image: path of target image.\n\n";
const char *optionalMsg = "-t --numThread: value of numThread(int), default: 4\n" \
"-p --padding: value of padding(int), default: 50\n" \
"-s --maxSideLen: Long side of picture for resize(int), default: 1024\n" \
"-b --boxScoreThresh: value of boxScoreThresh(float), default: 0.5\n" \
"-o --boxThresh: value of boxThresh(float), default: 0.3\n" \
"-u --unClipRatio: value of unClipRatio(float), default: 1.6\n" \
"-a --doAngle: Enable(1)/Disable(0) Angle Net, default: Enable\n" \
"-A --mostAngle: Enable(1)/Disable(0) Most Possible AngleIndex, default: Enable\n\n" \
"-G --GPU: Disable(-1)/GPU0(0)/GPU1(1)/... Use Vulkan GPU accelerate, default: Disable(-1)\n\n";
const char *otherMsg = "-v --version: show version\n" \
"-h --help: print this help\n\n";
const char *example1Msg = "Example1: %s --models models --det det.onnx --cls cls.onnx --rec rec.onnx --keys keys.txt --image 1.jpg --GPU 0\n";
const char *example2Msg = "Example2: %s -d models -1 det.onnx -2 cls.onnx -3 rec.onnx -4 keys.txt -i 1.jpg -t 4 -p 50 -s 0 -b 0.6 -o 0.3 -u 2.0 -a 1 -A 1 -G 0\n";
#endif //__MAIN_H__
#ifndef __OCR_VERSION_H__
#define __OCR_VERSION_H__
#define VERSION "1.2.2"
#endif //__OCR_VERSION_H__
./3rdParty/opencv-3.4.11_mini.tar.gz
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment