Commit 3b86a3cf authored by benjaminwan's avatar benjaminwan
Browse files

version: 1.1.0

parent 22437c6f
#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/imgproc.hpp>
#include <opencv2/imgcodecs.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 (int i = 0; i < textBoxes.size(); ++i) {
drawTextBox(boxImg, textBoxes[i].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 (int i = 0; i < points.size(); i++) {
points[i].x -= left;
points[i].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 = cv::mean(croppedImg, mask)[0];
return score;
}
float getContourArea(const std::vector<cv::Point2f> &box, float unClipRatio) {
int size = box.size();
float area = 0.0f;
float dist = 0.0f;
for (int 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 (int j = 0; j < soln.size(); j++) {
for (int 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 (int i = 0; i < angles.size(); ++i) {
angleIndexes.push_back(angles[i].index);
}
return angleIndexes;
}
std::vector<char *> getInputNames(Ort::Session *session) {
Ort::AllocatorWithDefaultOptions allocator;
size_t numInputNodes = session->GetInputCount();
std::vector<char *> inputNodeNames(numInputNodes);
//std::vector<int64_t> inputNodeDims;
//printf("Number of inputs = %zu\n", numInputNodes);
for (int i = 0; i < numInputNodes; i++) {
// print input node names
char *inputName = session->GetInputName(i, allocator);
//printf("InputName[%d]=%s\n", i, inputName);
inputNodeNames[i] = inputName;
// print input node types
//Ort::TypeInfo typeInfo = session->GetInputTypeInfo(i);
//auto tensorInfo = typeInfo.GetTensorTypeAndShapeInfo();
//ONNXTensorElementDataType type = tensorInfo.GetElementType();
//printf("Input[%d] type=%d\n", i, type);
// print input shapes/dims
//inputNodeDims = tensorInfo.GetShape();
//printf("Input[%d] num_dims=%zu\n", i, inputNodeDims.size());
/*for (int j = 0; j < inputNodeDims.size(); j++)
printf("Input[%d] dim%d=%jd\n", i, j, inputNodeDims[j]);*/
}
return inputNodeNames;
}
std::vector<char *> getOutputNames(Ort::Session *session) {
Ort::AllocatorWithDefaultOptions allocator;
size_t numOutputNodes = session->GetOutputCount();
std::vector<char *> outputNodeNames(numOutputNodes);
//std::vector<int64_t> outputNodeDims;
//printf("Number of outputs = %zu\n", numOutputNodes);
for (int i = 0; i < numOutputNodes; i++) {
// print input node names
char *outputName = session->GetOutputName(i, allocator);
//printf("OutputName[%d]=%s\n", i, outputName);
outputNodeNames[i] = outputName;
// print input node types
//Ort::TypeInfo type_info = session->GetOutputTypeInfo(i);
//auto tensorInfo = type_info.GetTensorTypeAndShapeInfo();
//ONNXTensorElementDataType type = tensorInfo.GetElementType();
//printf("Output %d : type=%d\n", i, type);
// print input shapes/dims
//outputNodeDims = tensorInfo.GetShape();
//printf("Output %d : num_dims=%zu\n", i, outputNodeDims.size());
/*for (int j = 0; j < outputNodeDims.size(); j++)
printf("Output %d : dim %d=%jd\n", i, j, outputNodeDims[j]);*/
}
return outputNodeNames;
}
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, int 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.
/*
* getopt - POSIX like getopt for Windows console Application
*
* win-c - Windows Console Library
* Copyright (c) 2015 Koji Takami
* Released under the MIT license
* https://github.com/takamin/win-c/blob/master/LICENSE
*/
#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);
}
/********************************************************
int getopt_long_only(int argc, char* const argv[],
const char* optstring,
const struct option* longopts, int* longindex)
{
return -1;
}
********************************************************/
#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, modelDetPath, modelClsPath, modelRecPath, keysPath;
std::string imgPath, imgDir, imgName;
int numThread = 4;
int padding = 0;
int maxSideLen = 1024;
float boxScoreThresh = 0.5f;
float boxThresh = 0.3f;
float unClipRatio = 2.0f;
bool doAngle = true;
int flagDoAngle = 1;
bool mostAngle = true;
int flagMostAngle = 1;
int opt;
int optionIndex = 0;
while ((opt = getopt_long(argc, argv, "d:1:2:3:4:i:t:p:s:b:o:u:a:A:v:h", long_options, &optionIndex)) != -1) {
//printf("option(-%c)=%s\n", opt, optarg);
switch (opt) {
case 'd':
modelsDir = optarg;
printf("modelsPath=%s\n", modelsDir.c_str());
break;
case '1':
modelDetPath = modelsDir + "/" + optarg;
printf("model det path=%s\n", modelDetPath.c_str());
break;
case '2':
modelClsPath = modelsDir + "/" + optarg;
printf("model cls path=%s\n", modelClsPath.c_str());
break;
case '3':
modelRecPath = modelsDir + "/" + optarg;
printf("model rec path=%s\n", modelRecPath.c_str());
break;
case '4':
keysPath = modelsDir + "/" + optarg;
printf("keys path=%s\n", keysPath.c_str());
break;
case 'i':
imgPath.assign(optarg);
imgDir.assign(imgPath.substr(0, imgPath.find_last_of('/') + 1));
imgName.assign(imgPath.substr(imgPath.find_last_of('/') + 1));
printf("imgDir=%s, imgName=%s\n", imgDir.c_str(), imgName.c_str());
break;
case 't':
numThread = (int) strtol(optarg, NULL, 10);
//printf("numThread=%d\n", numThread);
break;
case 'p':
padding = (int) strtol(optarg, NULL, 10);
//printf("padding=%d\n", padding);
break;
case 's':
maxSideLen = (int) strtol(optarg, NULL, 10);
//printf("maxSideLen=%d\n", maxSideLen);
break;
case 'b':
boxScoreThresh = strtof(optarg, NULL);
//printf("boxScoreThresh=%f\n", boxScoreThresh);
break;
case 'o':
boxThresh = strtof(optarg, NULL);
//printf("boxThresh=%f\n", boxThresh);
break;
case 'u':
unClipRatio = strtof(optarg, NULL);
//printf("unClipRatio=%f\n", unClipRatio);
break;
case 'a':
flagDoAngle = (int) strtol(optarg, NULL, 10);
if (flagDoAngle == 0) {
doAngle = false;
} else {
doAngle = true;
}
//printf("doAngle=%d\n", doAngle);
break;
case 'A':
flagMostAngle = (int) strtol(optarg, NULL, 10);
if (flagMostAngle == 0) {
mostAngle = false;
} else {
mostAngle = true;
}
//printf("mostAngle=%d\n", mostAngle);
break;
case 'v':
printf("%s\n", VERSION);
return 0;
case 'h':
printHelp(stdout, argv[0]);
return 0;
default:
printf("other option %c :%s\n", opt, optarg);
}
}
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.Logger("=====Input Params=====\n");
ocrLite.Logger(
"numThread(%d),padding(%d),maxSideLen(%d),boxScoreThresh(%f),boxThresh(%f),unClipRatio(%f),doAngle(%d),mostAngle(%d)\n",
numThread, padding, maxSideLen, boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle);
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
#!/bin/bash
## script for 内存占用检查
# ========== macOS ==========
# https://github.com/LouisBrunner/valgrind-macos
# brew tap LouisBrunner/valgrind
# brew install --HEAD LouisBrunner/valgrind/valgrind
# ========== linux ==========
# https://www.valgrind.org/
# apt install valgrind
NUM_THREADS=1
set OMP_NUM_THREADS=$NUM_THREADS
TARGET_IMG=images/1.jpg
if [ ! -f "$TARGET_IMG" ]; then
echo "找不到待识别的目标图片:${TARGET_IMG},请打开本文件并编辑TARGET_IMG"
exit
fi
##### run test on MacOS or Linux
valgrind --tool=massif --pages-as-heap=yes \
./${EXE_PATH}/RapidOcrOnnx --models models \
--det ch_PP-OCRv3_det_infer.onnx \
--cls ch_ppocr_mobile_v2.0_cls_infer.onnx \
--rec ch_PP-OCRv3_rec_infer.onnx \
--keys ppocr_keys_v1.txt \
--image $TARGET_IMG \
--numThread $NUM_THREADS \
--padding 50 \
--maxSideLen 1024 \
--boxScoreThresh 0.6 \
--boxThresh 0.3 \
--unClipRatio 2.0 \
--doAngle 1 \
--mostAngle 1
#!/bin/bash
## script for 内存泄露检查
# ========== macOS ==========
# https://github.com/LouisBrunner/valgrind-macos
# brew tap LouisBrunner/valgrind
# brew install --HEAD LouisBrunner/valgrind/valgrind
# ========== linux ==========
# https://www.valgrind.org/
# apt install valgrind
NUM_THREADS=1
set OMP_NUM_THREADS=$NUM_THREADS
TARGET_IMG=images/1.jpg
if [ ! -f "$TARGET_IMG" ]; then
echo "找不到待识别的目标图片:${TARGET_IMG},请打开本文件并编辑TARGET_IMG"
exit
fi
sysOS=`uname -s`
EXE_PATH=${sysOS}-BIN
##### run test on MacOS or Linux
valgrind --tool=memcheck --leak-check=full --leak-resolution=med --track-origins=yes --vgdb=no --log-file=valgrind-memcheck.txt \
./${EXE_PATH}/RapidOcrOnnx --models models \
--det ch_PP-OCRv3_det_infer.onnx \
--cls ch_ppocr_mobile_v2.0_cls_infer.onnx \
--rec ch_PP-OCRv3_rec_infer.onnx \
--keys ppocr_keys_v1.txt \
--image $TARGET_IMG \
--numThread $NUM_THREADS \
--padding 50 \
--maxSideLen 1024 \
--boxScoreThresh 0.5 \
--boxThresh 0.3 \
--unClipRatio 1.5 \
--doAngle 1 \
--mostAngle 1
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