123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776 |
- // Tencent is pleased to support the open source community by making ncnn available.
- //
- // Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved.
- //
- // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
- // in compliance with the License. You may obtain a copy of the License at
- //
- // https://opensource.org/licenses/BSD-3-Clause
- //
- // Unless required by applicable law or agreed to in writing, software distributed
- // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
- // CONDITIONS OF ANY KIND, either express or implied. See the License for the
- // specific language governing permissions and limitations under the License.
- #include "layer.h"
- #include "net.h"
- #include <opencv2/core/core.hpp>
- #include <opencv2/highgui/highgui.hpp>
- #include <opencv2/imgproc/imgproc.hpp>
- #include <cfloat>
- #include <vector>
- #include <opencv2/imgproc.hpp>
- #include <iostream>
- #include <fstream>
- #include "math.h"
- #include <locale>
- #include <codecvt>
- #include "android/log.h"
- #include <datareader.h>
- using namespace cv;
- using namespace std;
- std::vector<int> prebLabel;
- std::vector<string> alphabet;
- struct TextBlock
- {
- std::vector<Point2f> boxVertices; // 矩形框的顶点坐标
- float angle; // 矩形框的角度
- float boxScore;
- float blockTime;
- };
- // 该函数计算二进制图像中指定轮廓的分数
- float contourScore(cv::Mat& binary, std::vector<Point>& contour)
- {
- // 计算轮廓的边界矩形
- Rect rect = boundingRect(contour);
- // 计算边界框在二进制图像中的有效范围
- int xmin = max(rect.x, 0);
- int xmax = min(rect.x + rect.width, binary.cols - 1);
- int ymin = max(rect.y, 0);
- int ymax = min(rect.y + rect.height, binary.rows - 1);
- // 提取二进制图像中边界框的ROI(感兴趣区域)
- cv::Mat binROI = binary(Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1));
- // 创建一个掩码,用于标识ROI中的像素
- cv::Mat mask = cv::Mat::zeros(ymax - ymin + 1, xmax - xmin + 1, CV_8U);
- // 将轮廓中的点坐标调整为ROI内的坐标
- std::vector<Point> roiContour;
- for (size_t i = 0; i < contour.size(); i++) {
- Point pt = Point(contour[i].x - xmin, contour[i].y - ymin);
- roiContour.push_back(pt);
- }
- // 使用填充多边形函数将ROI内的轮廓标记为1
- std::vector<std::vector<Point>> roiContours = { roiContour };
- fillPoly(mask, roiContours, Scalar(1));
- // 计算ROI内二进制图像的均值,以掩码为权重
- float score = mean(binROI, mask).val[0];
- return score;
- }
- void unclip(std::vector<Point2f>& inPoly, std::vector<Point2f>& outPoly)
- {
- float unclipRatio = 1.6;
- // 计算轮廓的面积
- float area = contourArea(inPoly);
- float length = arcLength(inPoly, true); // 计算轮廓的周长
- float distance = area * unclipRatio / length; // 计算解剪距离
- // 获取输入轮廓的点数
- size_t numPoints = inPoly.size();
- // 存储新的轮廓线段
- std::vector<std::vector<Point2f>> newLines;
- // 遍历原始轮廓的每个点
- for (size_t i = 0; i < numPoints; i++)
- {
- std::vector<Point2f> newLine;
- Point pt1 = inPoly[i];
- Point pt2 = inPoly[(i - 1) % numPoints];
- Point vec = pt1 - pt2;
- // 计算解剪距离
- float unclipDis = (float)(distance / norm(vec));
- // 计算旋转后的向量
- Point2f rotateVec = Point2f(vec.y * unclipDis, -vec.x * unclipDis);
- // 添加旋转后的点到新线段
- newLine.push_back(Point2f(pt1.x + rotateVec.x, pt1.y + rotateVec.y));
- newLine.push_back(Point2f(pt2.x + rotateVec.x, pt2.y + rotateVec.y));
- newLines.push_back(newLine);
- }
- // 获取新线段的数量
- size_t numLines = newLines.size();
- // 遍历新线段集合
- for (size_t i = 0; i < numLines; i++)
- {
- Point2f a = newLines[i][0];
- Point2f b = newLines[i][1];
- Point2f c = newLines[(i + 1) % numLines][0];
- Point2f d = newLines[(i + 1) % numLines][1];
- Point2f pt;
- // 计算两向量的夹角余弦值
- Point2f v1 = b - a;
- Point2f v2 = d - c;
- float cosAngle = (v1.x * v2.x + v1.y * v2.y) / (norm(v1) * norm(v2));
- // 根据夹角余弦值判断旋转后的点位置
- if (fabs(cosAngle) > 0.7)
- {
- pt.x = (b.x + c.x) * 0.5;
- pt.y = (b.y + c.y) * 0.5;
- }
- else
- {
- float denom = a.x * (float)(d.y - c.y) + b.x * (float)(c.y - d.y) +
- d.x * (float)(b.y - a.y) + c.x * (float)(a.y - b.y);
- float num = a.x * (float)(d.y - c.y) + c.x * (float)(a.y - d.y) + d.x * (float)(c.y - a.y);
- float s = num / denom;
- pt.x = a.x + s * (b.x - a.x);
- pt.y = a.y + s * (b.y - a.y);
- }
- // 将计算得到的点添加到输出轮廓
- outPoly.push_back(pt);
- }
- }
- void GetTextBoxes(cv::Mat& binaryIN, cv::Mat& srcimgIN, std::vector<TextBlock> &rsBoxes)
- {
- __android_log_print(ANDROID_LOG_INFO, "EvaluateOneImage", "begin get boxes");
- float binaryThreshold = 0.3f;
- int maxCandidates = 1000;
- float polygonThreshold = 0.5;
- int longSideThresh = 3;//minBox 长边门限
- // 获取图像的高度和宽度
- int h = srcimgIN.rows;
- int w = srcimgIN.cols;
- // 二值化处理
- Mat bitmap;
- threshold(binaryIN, bitmap, binaryThreshold, 255, THRESH_BINARY);
- //// 计算图像缩放比例
- float scaleHeight = (float)(h) / (float)(binaryIN.size[0]);
- float scaleWidth = (float)(w) / (float)(binaryIN.size[1]);
- // 寻找轮廓
- vector< vector<Point> > contours;
- bitmap.convertTo(bitmap, CV_8UC1);
- __android_log_print(ANDROID_LOG_INFO, "EvaluateOneImage", "3 %d %d %d", bitmap.rows, bitmap.cols, bitmap.channels());
- findContours(bitmap, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
- // 限制候选框的数量
- size_t numCandidate = min(contours.size(), (size_t)(maxCandidates > 0 ? maxCandidates : INT_MAX));
- vector<float> confidences;
- // 遍历每个候选框
- for (size_t i = 0; i < numCandidate; i++)
- {
- vector<Point>& contour = contours[i];
- // 计算文本轮廓分数
- float score = contourScore(binaryIN, contour);
- float boxScore = 0.0f;
- if (score < polygonThreshold) {
- boxScore = score;
- continue;
- }
- // 对轮廓进行缩放
- vector<Point> contourScaled; contourScaled.reserve(contour.size());
- for (size_t j = 0; j < contour.size(); j++)
- {
- contourScaled.push_back(Point(int(contour[j].x * scaleWidth),
- int(contour[j].y * scaleHeight)));
- }
- // 检查坐标是否有效
- bool coordinatesValid = true;
- for (size_t j = 0; j < contourScaled.size(); j++) {
- if (contourScaled[j].x < 0 || contourScaled[j].y < 0 ||
- contourScaled[j].x >= w || contourScaled[j].y >= h) {
- coordinatesValid = false;
- break;
- }
- }
- // 如果坐标有效,则处理该结果
- if (coordinatesValid)
- {
- TextBlock detectedBox;
- // 解除裁剪
- RotatedRect box = minAreaRect(contourScaled);
- float longSide = std::max(box.size.width, box.size.height);
- if (longSide < longSideThresh)
- {
- continue;
- }
- // minArea() rect is not normalized, it may return rectangles with angle=-90 or height < width
- const float angle_threshold = 60; // do not expect vertical text, TODO detection algo property
- bool swap_size = false;
- if (box.size.width < box.size.height) // horizontal-wide text area is expected
- swap_size = true;
- else if (fabs(box.angle) >= angle_threshold) // don't work with vertical rectangles
- swap_size = true;
- if (swap_size)
- {
- swap(box.size.width, box.size.height);
- if (box.angle < 0)
- box.angle += 90;
- else if (box.angle > 0)
- box.angle -= 90;
- }
- Point2f vertex[4];
- box.points(vertex); // order: bl, tl, tr, br
- vector<Point2f> approx;
- for (int j = 0; j < 4; j++)
- approx.emplace_back(vertex[j]);
- vector<Point2f> polygon;
- unclip(approx, polygon);
- box = minAreaRect(polygon);
- longSide = std::max(box.size.width, box.size.height);
- if (longSide < longSideThresh + 2)
- {
- continue;
- }
- detectedBox.boxVertices = polygon;
- detectedBox.angle = box.angle;
- detectedBox.boxScore = boxScore;
- rsBoxes.push_back(detectedBox);
- __android_log_print(ANDROID_LOG_INFO, "EvaluateOneImage", "box is (%f %f) (%f %f) (%f %f) (%f %f)", detectedBox.boxVertices[0].x, detectedBox.boxVertices[0].y,
- detectedBox.boxVertices[1].x, detectedBox.boxVertices[1].y,
- detectedBox.boxVertices[2].x, detectedBox.boxVertices[2].y,
- detectedBox.boxVertices[3].x, detectedBox.boxVertices[3].y);
- }
- }
- confidences = vector<float>(contours.size(), 1.0f);
- __android_log_print(ANDROID_LOG_INFO, "EvaluateOneImage", "finish run detect %d", rsBoxes.size());
- // 对 results 进行倒序处理
- std::reverse(rsBoxes.begin(), rsBoxes.end());
- }
- // 该函数用于对输入图像进行预处理,包括颜色空间转换和图像缩放
- cv::Mat preprocess(cv::Mat srcimg)
- {
- int shortSize = 736;
- cv::Mat dstimg;
- // 将输入图像从BGR颜色空间转换为RGB颜色空间
- cvtColor(srcimg, dstimg, COLOR_BGR2RGB);
- int h = srcimg.rows;
- int w = srcimg.cols;
- // 初始化高度和宽度的缩放比例
- float scale_h = 1;
- float scale_w = 1;
- // 根据图像的高度和宽度选择缩放比例
- if (h < w)
- {
- // 如果图像高度小于宽度 计算高度缩放比例
- scale_h = (float)shortSize / (float)h;
- float tar_w = (float)w * scale_h;
- tar_w = tar_w - (int)tar_w % 32;
- tar_w = max((float)32, tar_w);
- scale_w = tar_w / (float)w;
- }
- else
- {
- // 如果图像宽度小于等于高度 计算宽度缩放比例
- scale_w = (float)shortSize / (float)w;
- float tar_h = (float)h * scale_w;
- tar_h = tar_h - (int)tar_h % 32;
- tar_h = max((float)32, tar_h);
- scale_h = tar_h / (float)h;
- }
- // 使用线性插值对图像进行缩放,以调整到目标尺寸
- resize(dstimg, dstimg, Size(int(scale_w * dstimg.cols), int(scale_h * dstimg.rows)), INTER_LINEAR);
- return dstimg;
- }
- std::vector<float> normalize_(cv::Mat img)
- {
- float meanValues[3] = { 0.485, 0.456, 0.406 };
- float normValues[3] = { 0.229, 0.224, 0.225 };
- std::vector<float> input_image;
- // img.convertTo(img, CV_32F);
- int row = img.rows;
- int col = img.cols;
- input_image.resize(row * col * img.channels());
- for (int c = 0; c < 3; c++)
- {
- for (int i = 0; i < row; i++)
- {
- for (int j = 0; j < col; j++)
- {
- float pix = img.ptr<uchar>(i)[j * 3 + c];
- input_image[c * row * col + i * col + j] = (pix / 255.0 - meanValues[c]) / normValues[c];
- }
- }
- }
- return input_image;
- }
- cv::Mat getRotateCropImage(cv::Mat& frame, std::vector<Point2f> vertices)
- {
- // 计算包围轮廓的最小矩形
- Rect rect = boundingRect(cv::Mat(vertices));
- // 从原始图像中提取感兴趣区域(ROI)
- cv::Mat crop_img = frame(rect);
- // 设置输出图像的大小为矩形的宽度和高度
- const Size outputSize = Size(rect.width, rect.height);
- // 定义目标矩形的四个顶点坐标
- std::vector<Point2f> targetVertices{ Point2f(0, outputSize.height), Point2f(0, 0), Point2f(outputSize.width, 0), Point2f(outputSize.width, outputSize.height) };
- // 将原始轮廓的顶点坐标调整为在裁剪后的图像中的坐标
- for (int i = 0; i < 4; i++)
- {
- vertices[i].x -= rect.x;
- vertices[i].y -= rect.y;
- }
- // 计算透视变换矩阵,将原始轮廓映射到目标矩形
- //Mat rotationcv::Matrix = getPerspectiveTransform(vertices, targetVertices);
- cv::Mat rotationMatrix = getPerspectiveTransform(vertices, targetVertices);
- // 应用透视变换,旋转和裁剪原始图像的感兴趣区域
- Mat result;
- //warpPerspective(crop_img, result, rotationcv::Matrix, outputSize, cv::BORDER_REPLICATE);
- warpPerspective(crop_img, result, rotationMatrix, outputSize, cv::BORDER_REPLICATE);
- return result;
- }
- string PostProcess(int wIn, int hIn, float* pdataIn)
- {
- int i = 0, j = 0;
- // 遍历输出,获取每列的最大值的索引作为标签
- for (i = 0; i < wIn; i++)
- {
- int one_label_idx = 0;
- float max_data = -10000;
- for (j = 0; j < hIn; j++)
- {
- float data_ = pdataIn[i * hIn + j];
- if (data_ > max_data)
- {
- max_data = data_;
- one_label_idx = j;
- }
- }
- prebLabel[i] = one_label_idx;
- }
- // 存储去重后的非空白标签
- std::vector<int> no_repeat_blank_label;
- for (size_t elementIndex = 0; elementIndex < wIn; ++elementIndex)
- {
- if (prebLabel[elementIndex] != 0 && !(elementIndex > 0 && prebLabel[elementIndex - 1] == prebLabel[elementIndex]))
- {
- no_repeat_blank_label.push_back(prebLabel[elementIndex] - 1);
- }
- }
- // 构建最终的预测文本
- int len_s = no_repeat_blank_label.size();
- std::string plate_text;
- // todo
- for (i = 0; i < len_s; i++)
- {
- plate_text += alphabet[no_repeat_blank_label[i]];
- }
- return plate_text;
- }
- int inpWidth = 320;
- int inpHeight = 48;
- //cv::Mat preprocessRec(cv::Mat srcimg)
- //{
- // cv::Mat dstimg;
- // int h = srcimg.rows;
- // int w = srcimg.cols;
- // const float ratio = w / float(h);
- // int resized_w = int(ceil((float)inpHeight * ratio));
- // if (ceil(inpHeight * ratio) > inpWidth)
- // {
- // resized_w = inpWidth;
- // }
- //
- // resize(srcimg, dstimg, Size(resized_w, inpHeight), INTER_LINEAR);
- // return dstimg;
- //}
- ////std::vector<float> normalizeRec(cv::Mat img)
- ////{
- ////
- //// std::vector<float> input_image;
- //// // img.convertTo(img, CV_32F);
- //// int row = img.rows;
- //// int col = img.cols;
- //// input_image.resize(inpHeight * inpWidth * img.channels());
- //// for (int c = 0; c < 3; c++)
- //// {
- //// for (int i = 0; i < row; i++)
- //// {
- //// for (int j = 0; j < inpWidth; j++)
- //// {
- //// if (j < col)
- //// {
- //// float pix = img.ptr<uchar>(i)[j * 3 + c];
- //// //input_image[c * row * inpWidth + i * inpWidth + j] = (pix / 255.0 - 0.5) / 0.5;
- //// input_image[c * row * inpWidth + i * inpWidth + j] = (pix);
- //// }
- //// else
- //// {
- //// input_image[c * row * inpWidth + i * inpWidth + j] = 0;
- //// }
- //// }
- //// }
- //// }
- //// return input_image;
- ////}
- //struct TextBox {
- // std::vector<cv::Point> boxPoint;
- // float score;
- // std::string text;
- //};
- //bool compareBoxWidth(const TextBox& a, const TextBox& b)
- //{
- // return abs(a.boxPoint[0].x - a.boxPoint[1].x) > abs(b.boxPoint[0].x - b.boxPoint[1].x);
- //}
- //cv::Mat getRotateCropImage2(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;
- // }
- //}
- //std::vector<cv::Mat> getPartImages(const cv::Mat& src, std::vector<TextBox>& textBoxes)
- //{
- // std::sort(textBoxes.begin(), textBoxes.end(), compareBoxWidth);
- // std::vector<cv::Mat> partImages;
- // if (textBoxes.size() > 0)
- // {
- // for (int i = 0; i < textBoxes.size(); ++i)
- // {
- // cv::Mat partImg = getRotateCropImage2(src, textBoxes[i].boxPoint);
- // partImages.emplace_back(partImg);
- // }
- // }
- //
- // return partImages;
- //}
- //struct TextLine {
- // std::string text;
- // std::vector<float> charScores;
- //};
- //
- //template<class ForwardIterator>
- //inline static size_t argmax(ForwardIterator first, ForwardIterator last) {
- // return std::distance(first, std::max_element(first, last));
- //}
- //
- //TextLine scoreToTextLine(const std::vector<float>& outputData, int h, int w)
- //{
- // int keySize = alphabet.size();
- // std::string strRes;
- // std::vector<float> scores;
- // int lastIndex = 0;
- // int maxIndex;
- // float maxValue;
- //
- // for (int i = 0; i < h; i++)
- // {
- // maxIndex = 0;
- // maxValue = -1000.f;
- //
- // maxIndex = int(argmax(outputData.begin() + i * w, outputData.begin() + i * w + w));
- // maxValue = float(*std::max_element(outputData.begin() + i * w, outputData.begin() + i * w + w));// / partition;
- // if (maxIndex > 0 && maxIndex < keySize && (!(i > 0 && maxIndex == lastIndex))) {
- // scores.emplace_back(maxValue);
- // strRes.append(alphabet[maxIndex - 1]);
- // }
- // lastIndex = maxIndex;
- // }
- // return { strRes, scores };
- //}
- static int ocrProcess(ncnn::Net* dectModel, ncnn::Net* recModel, const cv::Mat& bgr, std::vector<string>& textList)
- {
- __android_log_print(ANDROID_LOG_INFO, "EvaluateOneImage", "start");
- prebLabel.clear();
- const float prob_threshold = 0.25f;
- const float nms_threshold = 0.45f;
- int img_w = bgr.cols;
- int img_h = bgr.rows;
- cv::Mat dstimg = preprocess(bgr);
- float pix = dstimg.ptr<uchar>(200)[200 * 3 + 1];
- std::vector<float>result = normalize_(dstimg);
- __android_log_print(ANDROID_LOG_INFO, "EvaluateOneImage", "(200, 200, 1))%f ", pix);
- ncnn::Mat in_pad(dstimg.cols, dstimg.rows, 3, (void*)result.data());
- ncnn::Extractor dect = dectModel->create_extractor();
- dect.input("x", in_pad);
- ncnn::Mat out;
- dect.extract("sigmoid_0.tmp_0", out);
- Mat binary(out.h, out.w, CV_32FC1);
- memcpy(binary.data, out.data, out.w* out.h * sizeof(float));
- __android_log_print(ANDROID_LOG_INFO, "EvaluateOneImage", "dect out %d %d ", out.w , out.h);
- std::vector<TextBlock> textBlocks;
- GetTextBoxes(binary, const_cast<cv::Mat&>(bgr), textBlocks);
- __android_log_print(ANDROID_LOG_INFO, "EvaluateOneImage", "finish get boxes");
- for (size_t i = 0; i < textBlocks.size(); i++)
- {
- cv::Mat textimg = getRotateCropImage(const_cast<cv::Mat&>(bgr), textBlocks[i].boxVertices);
- const float mean_vals[3] = { 127.5, 127.5, 127.5 };
- const float norm_vals[3] = { 1.0 / 127.5, 1.0 / 127.5, 1.0 / 127.5 };
- float scale = (float)inpHeight / (float)textimg.rows;
- int dstWidth = int((float)textimg.cols * scale);
- cv::Mat srcResize;
- cv::resize(textimg, srcResize, cv::Size(dstWidth, inpHeight));
- //if you use PP-OCRv3 you should change PIXEL_RGB to PIXEL_RGB2BGR
- ncnn::Mat input = ncnn::Mat::from_pixels(srcResize.data, ncnn::Mat::PIXEL_RGB2BGR, srcResize.cols, srcResize.rows);
- input.substract_mean_normalize(mean_vals, norm_vals);
- ncnn::Mat in_pack3;
- ncnn::convert_packing(input, in_pack3, 3);
- cv::Mat aa(input.h, input.w, CV_32FC3);
- memcpy((uchar*)aa.data, in_pack3.data, input.w * input.h * 3 * sizeof(float));
- ncnn::Extractor rec = recModel->create_extractor();
- rec.input("input", input);
- ncnn::Mat out;
- rec.extract("out", out);
- __android_log_print(ANDROID_LOG_INFO, "EvaluateOneImage", "finish run rec, out %d %d", out.w, out.h);
- float* floatArray = (float*)out.data;
- std::vector<float> outputData(floatArray, floatArray + out.h * out.w);
- string textResult = "";
- // 存储预测的标签
- prebLabel.resize(out.h);
- string text = PostProcess(out.h, out.w, floatArray);
- // 删除标点符号和空格
- text.erase(std::remove_if(text.begin(), text.end(), [](unsigned char c) {
- return std::ispunct(c) || std::isspace(c);
- }), text.end());
- // 如果文本内容不为空,则处理结果
- if (!text.empty())
- {
- textResult = text;
- }
- textList.push_back(textResult);
- }
- for (int i=0; i< textBlocks.size(); ++i)
- {
- textBlocks[i].boxVertices.clear();
- }
- textBlocks.clear();
- textBlocks.shrink_to_fit();
- __android_log_print(ANDROID_LOG_INFO, "EvaluateOneImage", "End");
- return 0;
- }
- extern "C" void CreateNet(void** detectModel, void** recModel, char* decBinMem, char* decParamMem, char* recBinMem, char* recParamMem, const void* modelDataKeys, size_t modelDataLengthKeys)
- {
- const auto resultDetect = new ncnn::Net;
- *detectModel = resultDetect;
- const auto resultDetectRec = new ncnn::Net;
- *recModel = resultDetectRec;
- int ret[4] = {-2};
- const unsigned char* dectBinMemP = reinterpret_cast<const unsigned char*>(decBinMem);
- ncnn::DataReaderFromMemory drDect(dectBinMemP);
- const unsigned char* recBinMemP = reinterpret_cast<const unsigned char*>(recBinMem);
- ncnn::DataReaderFromMemory drRec(recBinMemP);
- resultDetect->opt.use_vulkan_compute = false;
- ret[0] = resultDetect->load_param_mem(decParamMem);
- ret[1] = resultDetect->load_model(drDect);
- ret[2] = resultDetectRec->load_param_mem(recParamMem);
- ret[3] = resultDetectRec->load_model(drRec);
- __android_log_print(ANDROID_LOG_INFO, "EvaluateOneImage", "LoadDectBin %d %d %d %d", ret[0], ret[1], ret[2], ret[3]);
- //string keys_path = keysName;
- //ifstream ifs(keys_path);
- //std::string line;
- //while (getline(ifs, line))
- //{
- // alphabet.push_back(line);
- //}
- //alphabet.push_back(" ");
- // 将字节数据转换为字符串
- std::string text(reinterpret_cast<const char*>(modelDataKeys), modelDataLengthKeys);
- // 使用字符串流处理字符串
- std::istringstream iss(text);
- std::string line;
- // 逐行读取并添加到 alphabet 中
- while (std::getline(iss, line))
- {
- alphabet.push_back(line);
- }
- alphabet.push_back(" ");
- }
- extern "C" void FreeNet(void* detectModel, void* recModel)
- {
- const auto yolo = static_cast<ncnn::Net*>(detectModel);
- yolo->clear();
- const auto rec = static_cast<ncnn::Net*>(recModel);
- rec->clear();
- delete yolo;
- delete rec;
- }
- typedef struct _StructStringInfo
- {
- char* result;
- int bufferSize;
- }StructStringInfo;
- extern "C" void Test(void* detectModel, void* recModel, unsigned char* input, int iw, int ih, StructStringInfo*& ob, int* cnt)
- {
- ncnn::Net* dect = static_cast<ncnn::Net*>(detectModel);
- ncnn::Net* rec = static_cast<ncnn::Net*>(recModel);
- __android_log_print(ANDROID_LOG_INFO, "EvaluateOneImage", "image in");
- cv::Mat m = cv::Mat(ih, iw, CV_8UC4, (void*)input);
- cvtColor(m, m, cv::COLOR_RGBA2BGR);
- __android_log_print(ANDROID_LOG_INFO, "EvaluateOneImage", "image cvt out");
- // 获取图像在指定坐标(x, y)处的像素值
- cv::Vec3b pixel = m.at<cv::Vec3b>(100, 100);
- // 输出像素值到Android Logcat
- __android_log_print(ANDROID_LOG_INFO, "EvaluateOneImage", "Pixel value at (%d, %d): B=%d, G=%d, R=%d",
- 100, 100, pixel[0], pixel[1], pixel[2]);
- // 获取图像在指定坐标(x, y)处的像素值
- pixel = m.at<cv::Vec3b>(200, 200);
- // 输出像素值到Android Logcat
- __android_log_print(ANDROID_LOG_INFO, "EvaluateOneImage", "Pixel value at (%d, %d): B=%d, G=%d, R=%d",
- 200, 200, pixel[0], pixel[1], pixel[2]);
- // 获取图像在指定坐标(x, y)处的像素值
- pixel = m.at<cv::Vec3b>(300, 300);
- // 输出像素值到Android Logcat
- __android_log_print(ANDROID_LOG_INFO, "EvaluateOneImage", "Pixel value at (%d, %d): B=%d, G=%d, R=%d",
- 300, 300, pixel[0], pixel[1], pixel[2]);
- std::vector<string> textLists;
- ocrProcess(dect, rec, m, textLists);
- int count = static_cast<int>(textLists.size());
- if(count > 100)
- {
- count = 100;
- }
- *cnt = count;
- ob = new StructStringInfo[count];
- for (int i=0; i< count; ++i)
- {
- ob[i].result = new char[textLists[i].length()+1];
- std::copy(textLists[i].begin(), textLists[i].end(), ob[i].result);
- ob[i].result[textLists[i].length()] = '\0'; // 添加null终止符
- }
- textLists.clear();
- }
|