rn-opencv-doc-perspective-correction 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -2
- package/dist/index.js +35 -27
- package/package.json +1 -1
- package/src/index.ts +44 -34
package/dist/index.d.ts
CHANGED
|
@@ -14,9 +14,9 @@ export declare class DocumentScanner {
|
|
|
14
14
|
/**
|
|
15
15
|
* Bước 1: Page Corner Detection (Auto-detect góc tài liệu)
|
|
16
16
|
*/
|
|
17
|
-
static detectPageCorners(imageBase64: string): Point[] | undefined;
|
|
17
|
+
static detectPageCorners(imageBase64: string, onLog?: (msg: string) => void): Point[] | undefined;
|
|
18
18
|
/**
|
|
19
19
|
* Bước 2: Perspective Correction
|
|
20
20
|
*/
|
|
21
|
-
static applyPerspectiveCorrection(imageBase64: string, corners: Point[]): string | undefined;
|
|
21
|
+
static applyPerspectiveCorrection(imageBase64: string, corners: Point[], onLog?: (msg: string) => void): string | undefined;
|
|
22
22
|
}
|
package/dist/index.js
CHANGED
|
@@ -26,7 +26,7 @@ class DocumentScanner {
|
|
|
26
26
|
/**
|
|
27
27
|
* Bước 1: Page Corner Detection (Auto-detect góc tài liệu)
|
|
28
28
|
*/
|
|
29
|
-
static detectPageCorners(imageBase64) {
|
|
29
|
+
static detectPageCorners(imageBase64, onLog) {
|
|
30
30
|
let src = null;
|
|
31
31
|
let gray = null;
|
|
32
32
|
let blurred = null;
|
|
@@ -41,37 +41,40 @@ class DocumentScanner {
|
|
|
41
41
|
react_native_fast_opencv_1.OpenCV.invoke('cvtColor', src, gray, react_native_fast_opencv_1.ColorConversionCodes.COLOR_BGR2GRAY);
|
|
42
42
|
const ksize = react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.Size, 5, 5);
|
|
43
43
|
react_native_fast_opencv_1.OpenCV.invoke('GaussianBlur', gray, blurred, ksize, 0);
|
|
44
|
-
react_native_fast_opencv_1.OpenCV.invoke('Canny', blurred, edges,
|
|
44
|
+
react_native_fast_opencv_1.OpenCV.invoke('Canny', blurred, edges, 50, 150);
|
|
45
45
|
contoursObj = react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.MatVector);
|
|
46
46
|
hierarchyObj = react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.Mat, 0, 0, react_native_fast_opencv_1.DataTypes.CV_8U);
|
|
47
|
-
react_native_fast_opencv_1.OpenCV.invoke('
|
|
48
|
-
const
|
|
47
|
+
react_native_fast_opencv_1.OpenCV.invoke('findContoursWithHierarchy', edges, contoursObj, hierarchyObj, 1 /* RETR_LIST */, 2 /* CHAIN_APPROX_SIMPLE */);
|
|
48
|
+
const contoursJS = react_native_fast_opencv_1.OpenCV.toJSValue(contoursObj);
|
|
49
|
+
const contoursArray = (contoursJS === null || contoursJS === void 0 ? void 0 : contoursJS.array) || [];
|
|
50
|
+
const contoursSize = contoursArray.length;
|
|
49
51
|
let maxArea = 0;
|
|
50
52
|
let largestPoly = undefined;
|
|
53
|
+
let foundContoursCount = 0;
|
|
51
54
|
for (let i = 0; i < contoursSize; i++) {
|
|
52
|
-
const contour = react_native_fast_opencv_1.OpenCV.
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
const contour = react_native_fast_opencv_1.OpenCV.copyObjectFromVector(contoursObj, i);
|
|
56
|
+
const areaObj = react_native_fast_opencv_1.OpenCV.invoke('contourArea', contour);
|
|
57
|
+
const area = areaObj ? areaObj.value : 0;
|
|
58
|
+
if (area > 10000) { // Lọc bỏ các contour quá nhỏ
|
|
59
|
+
foundContoursCount++;
|
|
60
|
+
}
|
|
61
|
+
if (area > maxArea && area > 10000) {
|
|
62
|
+
const periObj = react_native_fast_opencv_1.OpenCV.invoke('arcLength', contour, true);
|
|
63
|
+
const peri = periObj ? periObj.value : 0;
|
|
64
|
+
const approx = react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.PointVector);
|
|
65
|
+
// Tăng eplison lên một chút để cho phép viền mấp mô hơn
|
|
66
|
+
react_native_fast_opencv_1.OpenCV.invoke('approxPolyDP', contour, approx, 0.04 * peri, true);
|
|
67
|
+
const approxJS = react_native_fast_opencv_1.OpenCV.toJSValue(approx);
|
|
68
|
+
if (approxJS && approxJS.array && approxJS.array.length === 4) {
|
|
60
69
|
maxArea = area;
|
|
61
|
-
|
|
62
|
-
for (let v = 0; v < 4; v++) {
|
|
63
|
-
try {
|
|
64
|
-
const pt = react_native_fast_opencv_1.OpenCV.invoke('row', approx, v);
|
|
65
|
-
if (pt && typeof pt === 'object' && 'x' in pt)
|
|
66
|
-
points.push(pt);
|
|
67
|
-
}
|
|
68
|
-
catch (err) { }
|
|
69
|
-
}
|
|
70
|
-
if (points.length === 4)
|
|
71
|
-
largestPoly = points;
|
|
70
|
+
largestPoly = approxJS.array;
|
|
72
71
|
}
|
|
73
72
|
}
|
|
74
73
|
}
|
|
74
|
+
const logMsg = `[OpenCV] Đã tìm thấy ${contoursSize} contours. Số contour đủ lớn: ${foundContoursCount}`;
|
|
75
|
+
console.log(logMsg);
|
|
76
|
+
if (onLog)
|
|
77
|
+
onLog(logMsg);
|
|
75
78
|
if (largestPoly && largestPoly.length === 4) {
|
|
76
79
|
return this.sortCorners(largestPoly);
|
|
77
80
|
}
|
|
@@ -79,7 +82,9 @@ class DocumentScanner {
|
|
|
79
82
|
}
|
|
80
83
|
catch (e) {
|
|
81
84
|
console.error('Lỗi khi dò tìm góc tài liệu (OpenCV):', e);
|
|
82
|
-
|
|
85
|
+
if (onLog)
|
|
86
|
+
onLog(`[OpenCV Corner Detection Error]: ${e.message}`);
|
|
87
|
+
throw new Error(`[OpenCV Corner Detection Error]: ${e.message}`);
|
|
83
88
|
}
|
|
84
89
|
finally {
|
|
85
90
|
react_native_fast_opencv_1.OpenCV.clearBuffers();
|
|
@@ -88,7 +93,7 @@ class DocumentScanner {
|
|
|
88
93
|
/**
|
|
89
94
|
* Bước 2: Perspective Correction
|
|
90
95
|
*/
|
|
91
|
-
static applyPerspectiveCorrection(imageBase64, corners) {
|
|
96
|
+
static applyPerspectiveCorrection(imageBase64, corners, onLog) {
|
|
92
97
|
let src = null;
|
|
93
98
|
let dst = null;
|
|
94
99
|
try {
|
|
@@ -118,13 +123,16 @@ class DocumentScanner {
|
|
|
118
123
|
react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.Point2f, maxWidth - 1, maxHeight - 1),
|
|
119
124
|
react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.Point2f, 0, maxHeight - 1)
|
|
120
125
|
]);
|
|
121
|
-
const perspectiveMatrix = react_native_fast_opencv_1.OpenCV.invoke('getPerspectiveTransform', srcPoints, dstPoints);
|
|
126
|
+
const perspectiveMatrix = react_native_fast_opencv_1.OpenCV.invoke('getPerspectiveTransform', srcPoints, dstPoints, 0);
|
|
122
127
|
const size = react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.Size, maxWidth, maxHeight);
|
|
123
|
-
react_native_fast_opencv_1.OpenCV.
|
|
128
|
+
const borderValue = react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.Scalar, 0);
|
|
129
|
+
react_native_fast_opencv_1.OpenCV.invoke('warpPerspective', src, dst, perspectiveMatrix, size, 1 /* INTER_LINEAR */, 0 /* BORDER_CONSTANT */, borderValue);
|
|
124
130
|
return react_native_fast_opencv_1.OpenCV.invoke('toBase64', dst);
|
|
125
131
|
}
|
|
126
132
|
catch (e) {
|
|
127
133
|
console.error('Lỗi khi bóp phối cảnh tài liệu (OpenCV):', e);
|
|
134
|
+
if (onLog)
|
|
135
|
+
onLog(`[OpenCV Perspective Correction Error]: ${e.message || e}`);
|
|
128
136
|
return undefined;
|
|
129
137
|
}
|
|
130
138
|
finally {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rn-opencv-doc-perspective-correction",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "A React Native library for document corner detection and perspective correction using react-native-fast-opencv",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
package/src/index.ts
CHANGED
|
@@ -32,7 +32,7 @@ export class DocumentScanner {
|
|
|
32
32
|
/**
|
|
33
33
|
* Bước 1: Page Corner Detection (Auto-detect góc tài liệu)
|
|
34
34
|
*/
|
|
35
|
-
public static detectPageCorners(imageBase64: string): Point[] | undefined {
|
|
35
|
+
public static detectPageCorners(imageBase64: string, onLog?: (msg: string) => void): Point[] | undefined {
|
|
36
36
|
let src: OpenCVMat | null = null;
|
|
37
37
|
let gray: OpenCVMat | null = null;
|
|
38
38
|
let blurred: OpenCVMat | null = null;
|
|
@@ -51,49 +51,56 @@ export class DocumentScanner {
|
|
|
51
51
|
const ksize = OpenCV.createObject(ObjectType.Size, 5, 5);
|
|
52
52
|
OpenCV.invoke('GaussianBlur', gray, blurred, ksize, 0);
|
|
53
53
|
|
|
54
|
-
OpenCV.invoke('Canny', blurred, edges,
|
|
54
|
+
OpenCV.invoke('Canny', blurred, edges, 50, 150);
|
|
55
55
|
|
|
56
56
|
contoursObj = OpenCV.createObject(ObjectType.MatVector);
|
|
57
57
|
hierarchyObj = OpenCV.createObject(ObjectType.Mat, 0, 0, DataTypes.CV_8U);
|
|
58
58
|
|
|
59
|
-
OpenCV.invoke('
|
|
59
|
+
OpenCV.invoke('findContoursWithHierarchy', edges, contoursObj, hierarchyObj, 1 /* RETR_LIST */, 2 /* CHAIN_APPROX_SIMPLE */);
|
|
60
|
+
|
|
61
|
+
const contoursJS = OpenCV.toJSValue(contoursObj);
|
|
62
|
+
const contoursArray = contoursJS?.array || [];
|
|
63
|
+
const contoursSize = contoursArray.length;
|
|
60
64
|
|
|
61
|
-
const contoursSize = OpenCV.invoke('size', contoursObj) || 0;
|
|
62
65
|
let maxArea = 0;
|
|
63
66
|
let largestPoly: Point[] | undefined = undefined;
|
|
67
|
+
let foundContoursCount = 0;
|
|
64
68
|
|
|
65
69
|
for (let i = 0; i < contoursSize; i++) {
|
|
66
|
-
const contour = OpenCV.
|
|
67
|
-
const
|
|
70
|
+
const contour = OpenCV.copyObjectFromVector(contoursObj, i);
|
|
71
|
+
const areaObj = OpenCV.invoke('contourArea', contour);
|
|
72
|
+
const area = areaObj ? areaObj.value : 0;
|
|
73
|
+
|
|
74
|
+
if (area > 10000) { // Lọc bỏ các contour quá nhỏ
|
|
75
|
+
foundContoursCount++;
|
|
76
|
+
}
|
|
68
77
|
|
|
69
|
-
if (area > maxArea) {
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
|
|
78
|
+
if (area > maxArea && area > 10000) {
|
|
79
|
+
const periObj = OpenCV.invoke('arcLength', contour, true);
|
|
80
|
+
const peri = periObj ? periObj.value : 0;
|
|
81
|
+
const approx = OpenCV.createObject(ObjectType.PointVector);
|
|
82
|
+
// Tăng eplison lên một chút để cho phép viền mấp mô hơn
|
|
83
|
+
OpenCV.invoke('approxPolyDP', contour, approx, 0.04 * peri, true);
|
|
73
84
|
|
|
74
|
-
const
|
|
75
|
-
if (
|
|
85
|
+
const approxJS = OpenCV.toJSValue(approx);
|
|
86
|
+
if (approxJS && approxJS.array && approxJS.array.length === 4) {
|
|
76
87
|
maxArea = area;
|
|
77
|
-
|
|
78
|
-
const points: Point[] = [];
|
|
79
|
-
for (let v = 0; v < 4; v++) {
|
|
80
|
-
try {
|
|
81
|
-
const pt = OpenCV.invoke('row', approx, v);
|
|
82
|
-
if (pt && typeof pt === 'object' && 'x' in pt) points.push(pt as Point);
|
|
83
|
-
} catch (err) { }
|
|
84
|
-
}
|
|
85
|
-
if (points.length === 4) largestPoly = points;
|
|
88
|
+
largestPoly = approxJS.array as Point[];
|
|
86
89
|
}
|
|
87
90
|
}
|
|
88
91
|
}
|
|
92
|
+
const logMsg = `[OpenCV] Đã tìm thấy ${contoursSize} contours. Số contour đủ lớn: ${foundContoursCount}`;
|
|
93
|
+
console.log(logMsg);
|
|
94
|
+
if (onLog) onLog(logMsg);
|
|
89
95
|
|
|
90
96
|
if (largestPoly && largestPoly.length === 4) {
|
|
91
97
|
return this.sortCorners(largestPoly);
|
|
92
98
|
}
|
|
93
99
|
return undefined;
|
|
94
|
-
} catch (e) {
|
|
100
|
+
} catch (e: any) {
|
|
95
101
|
console.error('Lỗi khi dò tìm góc tài liệu (OpenCV):', e);
|
|
96
|
-
|
|
102
|
+
if (onLog) onLog(`[OpenCV Corner Detection Error]: ${e.message}`);
|
|
103
|
+
throw new Error(`[OpenCV Corner Detection Error]: ${e.message}`);
|
|
97
104
|
} finally {
|
|
98
105
|
OpenCV.clearBuffers();
|
|
99
106
|
}
|
|
@@ -102,7 +109,7 @@ export class DocumentScanner {
|
|
|
102
109
|
/**
|
|
103
110
|
* Bước 2: Perspective Correction
|
|
104
111
|
*/
|
|
105
|
-
public static applyPerspectiveCorrection(imageBase64: string, corners: Point[]): string | undefined {
|
|
112
|
+
public static applyPerspectiveCorrection(imageBase64: string, corners: Point[], onLog?: (msg: string) => void): string | undefined {
|
|
106
113
|
let src: OpenCVMat | null = null;
|
|
107
114
|
let dst: OpenCVMat | null = null;
|
|
108
115
|
|
|
@@ -127,29 +134,32 @@ export class DocumentScanner {
|
|
|
127
134
|
|
|
128
135
|
const srcPoints = OpenCV.createObject(ObjectType.Point2fVector,
|
|
129
136
|
[
|
|
130
|
-
OpenCV.createObject(ObjectType.Point2f, tl.x, tl.y)
|
|
131
|
-
OpenCV.createObject(ObjectType.Point2f, tr.x, tr.y)
|
|
132
|
-
OpenCV.createObject(ObjectType.Point2f, br.x, br.y)
|
|
133
|
-
OpenCV.createObject(ObjectType.Point2f, bl.x, bl.y)
|
|
137
|
+
OpenCV.createObject(ObjectType.Point2f, tl.x, tl.y),
|
|
138
|
+
OpenCV.createObject(ObjectType.Point2f, tr.x, tr.y),
|
|
139
|
+
OpenCV.createObject(ObjectType.Point2f, br.x, br.y),
|
|
140
|
+
OpenCV.createObject(ObjectType.Point2f, bl.x, bl.y)
|
|
134
141
|
]
|
|
135
142
|
);
|
|
136
143
|
const dstPoints = OpenCV.createObject(ObjectType.Point2fVector,
|
|
137
144
|
[
|
|
138
|
-
OpenCV.createObject(ObjectType.Point2f, 0, 0)
|
|
139
|
-
OpenCV.createObject(ObjectType.Point2f, maxWidth - 1, 0)
|
|
140
|
-
OpenCV.createObject(ObjectType.Point2f, maxWidth - 1, maxHeight - 1)
|
|
141
|
-
OpenCV.createObject(ObjectType.Point2f, 0, maxHeight - 1)
|
|
145
|
+
OpenCV.createObject(ObjectType.Point2f, 0, 0),
|
|
146
|
+
OpenCV.createObject(ObjectType.Point2f, maxWidth - 1, 0),
|
|
147
|
+
OpenCV.createObject(ObjectType.Point2f, maxWidth - 1, maxHeight - 1),
|
|
148
|
+
OpenCV.createObject(ObjectType.Point2f, 0, maxHeight - 1)
|
|
142
149
|
]
|
|
143
150
|
);
|
|
144
151
|
|
|
145
|
-
const perspectiveMatrix = OpenCV.invoke('getPerspectiveTransform', srcPoints, dstPoints);
|
|
152
|
+
const perspectiveMatrix = OpenCV.invoke('getPerspectiveTransform', srcPoints, dstPoints, 0);
|
|
146
153
|
|
|
147
154
|
const size = OpenCV.createObject(ObjectType.Size, maxWidth, maxHeight);
|
|
148
|
-
OpenCV.
|
|
155
|
+
const borderValue = OpenCV.createObject(ObjectType.Scalar, 0);
|
|
156
|
+
|
|
157
|
+
OpenCV.invoke('warpPerspective', src, dst, perspectiveMatrix, size, 1 /* INTER_LINEAR */, 0 /* BORDER_CONSTANT */, borderValue);
|
|
149
158
|
|
|
150
159
|
return OpenCV.invoke('toBase64', dst);
|
|
151
160
|
} catch (e) {
|
|
152
161
|
console.error('Lỗi khi bóp phối cảnh tài liệu (OpenCV):', e);
|
|
162
|
+
if (onLog) onLog(`[OpenCV Perspective Correction Error]: ${(e as Error).message || e}`);
|
|
153
163
|
return undefined;
|
|
154
164
|
} finally {
|
|
155
165
|
OpenCV.clearBuffers();
|