Files
wehub-resource-sync e904b667c6
Build/Publish Develop Docs / deploy (push) Failing after 1s
PaddleOCR Code Style Check / check-code-style (push) Failing after 1s
PaddleOCR PR Tests GPU / detect-changes (push) Failing after 1s
PaddleOCR PR Tests / detect-changes (push) Failing after 1s
PaddleOCR PR Tests GPU / test-pr-gpu (push) Has been cancelled
PaddleOCR PR Tests / test-pr (push) Has been cancelled
PaddleOCR PR Tests GPU / test-pr-gpu-impl (push) Has been cancelled
PaddleOCR PR Tests / test-pr-python (3.13) (push) Has been cancelled
PaddleOCR PR Tests / test-pr-python (3.8) (push) Has been cancelled
PaddleOCR PR Tests / test-pr-python (3.9) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 11:59:26 +08:00

206 lines
7.1 KiB
Plaintext

// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// 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.
#import "OpenCVImageBridge.h"
#import <algorithm>
#import <cfloat>
#import <cmath>
#import <opencv2/core.hpp>
#import <opencv2/imgproc.hpp>
#import <UIKit/UIKit.h>
@implementation PDBPerspectiveCropOutput
@end
@implementation PDBOpenCVImageBridge
+ (NSData *)resizeRGBU8:(NSData *)data
srcWidth:(NSInteger)srcWidth
srcHeight:(NSInteger)srcHeight
dstWidth:(NSInteger)dstWidth
dstHeight:(NSInteger)dstHeight {
if (srcWidth <= 0 || srcHeight <= 0 || dstWidth <= 0 || dstHeight <= 0) {
return [NSData data];
}
if (data.length < (NSUInteger)(srcWidth * srcHeight * 3)) {
return [NSData data];
}
cv::Mat src((int)srcHeight, (int)srcWidth, CV_8UC3, (void *)data.bytes);
cv::Mat dst;
cv::resize(src, dst, cv::Size((int)dstWidth, (int)dstHeight), 0, 0, cv::INTER_LINEAR);
return [NSData dataWithBytes:dst.data length:(NSUInteger)(dst.rows * dst.cols * 3)];
}
+ (NSData *)padRGBU8:(NSData *)data
width:(NSInteger)width
height:(NSInteger)height
padWidth:(NSInteger)padWidth
padHeight:(NSInteger)padHeight {
if (width <= 0 || height <= 0 || padWidth < width || padHeight < height) {
return data ?: [NSData data];
}
if (data.length < (NSUInteger)(width * height * 3)) {
return [NSData data];
}
cv::Mat src((int)height, (int)width, CV_8UC3, (void *)data.bytes);
int bot = (int)(padHeight - height);
int right = (int)(padWidth - width);
cv::Mat dst;
cv::copyMakeBorder(src, dst, 0, bot, 0, right, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0));
return [NSData dataWithBytes:dst.data length:(NSUInteger)(dst.rows * dst.cols * 3)];
}
+ (nullable PDBPerspectiveCropOutput *)quadTextLineCropBGR:(NSData *)src
srcWidth:(NSInteger)srcWidth
srcHeight:(NSInteger)srcHeight
quad:(NSArray<NSValue *> *)quad {
if (srcWidth <= 0 || srcHeight <= 0) {
return nil;
}
if (quad.count != 4 || src.length < (NSUInteger)(srcWidth * srcHeight * 3)) {
return nil;
}
cv::Mat im((int)srcHeight, (int)srcWidth, CV_8UC3, (void *)src.bytes);
std::vector<cv::Point2f> raw(4);
for (int i = 0; i < 4; i++) {
CGPoint p = [quad[i] CGPointValue];
raw[i] = cv::Point2f((float)(int32_t)p.x, (float)(int32_t)p.y);
}
cv::RotatedRect rr = cv::minAreaRect(raw);
cv::Point2f boxPts[4];
rr.points(boxPts);
std::vector<cv::Point2f> sorted(boxPts, boxPts + 4);
std::sort(sorted.begin(), sorted.end(),
[](const cv::Point2f &a, const cv::Point2f &b) { return a.x < b.x; });
int index_a, index_b, index_c, index_d;
if (sorted[1].y > sorted[0].y) {
index_a = 0;
index_d = 1;
} else {
index_a = 1;
index_d = 0;
}
if (sorted[3].y > sorted[2].y) {
index_b = 2;
index_c = 3;
} else {
index_b = 3;
index_c = 2;
}
cv::Point2f srcPts[4] = {sorted[index_a], sorted[index_b], sorted[index_c], sorted[index_d]};
double w1 = cv::norm(srcPts[0] - srcPts[1]);
double w2 = cv::norm(srcPts[2] - srcPts[3]);
double h1 = cv::norm(srcPts[0] - srcPts[3]);
double h2 = cv::norm(srcPts[1] - srcPts[2]);
int img_crop_width = (int)std::max(w1, w2);
int img_crop_height = (int)std::max(h1, h2);
if (img_crop_width <= 0 || img_crop_height <= 0) {
return nil;
}
cv::Point2f dstPts[4] = {
cv::Point2f(0, 0),
cv::Point2f((float)img_crop_width, 0),
cv::Point2f((float)img_crop_width, (float)img_crop_height),
cv::Point2f(0, (float)img_crop_height),
};
cv::Mat M = cv::getPerspectiveTransform(srcPts, dstPts);
cv::Mat warped;
cv::warpPerspective(im, warped, M, cv::Size(img_crop_width, img_crop_height), cv::INTER_CUBIC,
cv::BORDER_REPLICATE);
cv::Mat outMat;
double ratio = (double)warped.rows / (double)warped.cols;
if (ratio >= 1.5) {
cv::rotate(warped, outMat, cv::ROTATE_90_COUNTERCLOCKWISE);
} else {
outMat = warped;
}
PDBPerspectiveCropOutput *result = [[PDBPerspectiveCropOutput alloc] init];
result.rgbData = [NSData dataWithBytes:outMat.data length:(NSUInteger)(outMat.rows * outMat.cols * 3)];
result.width = outMat.cols;
result.height = outMat.rows;
return result;
}
+ (float)meanPredInQuad:(NSData *)pred
width:(NSInteger)width
height:(NSInteger)height
box:(NSArray<NSArray<NSNumber *> *> *)box {
if (width <= 0 || height <= 0 || box.count != 4) {
return 0;
}
size_t need = (size_t)(width * height) * sizeof(float);
if (pred.length < need) {
return 0;
}
float xminF = FLT_MAX, xmaxF = -FLT_MAX, yminF = FLT_MAX, ymaxF = -FLT_MAX;
for (NSArray<NSNumber *> *pt in box) {
if (pt.count < 2) {
return 0;
}
float x = [pt[0] floatValue];
float y = [pt[1] floatValue];
xminF = std::min(xminF, x);
xmaxF = std::max(xmaxF, x);
yminF = std::min(yminF, y);
ymaxF = std::max(ymaxF, y);
}
int w = (int)width;
int h = (int)height;
// Clamp ROI to bitmap bounds before masking and mean (avoids out-of-range reads).
int xmin = std::max(0, std::min((int)std::floor(xminF), w - 1));
int xmax = std::max(0, std::min((int)std::ceil(xmaxF), w - 1));
int ymin = std::max(0, std::min((int)std::floor(yminF), h - 1));
int ymax = std::max(0, std::min((int)std::ceil(ymaxF), h - 1));
if (xmax < xmin || ymax < ymin) {
return 0;
}
const float *p = (const float *)pred.bytes;
cv::Mat bitmap(h, w, CV_32FC1, (void *)const_cast<float *>(p));
cv::Rect roi(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
cv::Mat crop = bitmap(roi);
cv::Mat mask = cv::Mat::zeros(crop.rows, crop.cols, CV_8UC1);
std::vector<cv::Point> pts;
pts.reserve(4);
for (NSArray<NSNumber *> *pt in box) {
float fx = [pt[0] floatValue] - static_cast<float>(xmin);
float fy = [pt[1] floatValue] - static_cast<float>(ymin);
int px = static_cast<int>(fx);
int py = static_cast<int>(fy);
pts.push_back(cv::Point(px, py));
}
std::vector<std::vector<cv::Point>> contours;
contours.push_back(pts);
cv::fillPoly(mask, contours, cv::Scalar(1));
cv::Scalar m = cv::mean(crop, mask);
return (float)m[0];
}
@end