rn-opencv-doc-perspective-correction 1.0.4 → 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 +31 -13
- package/package.json +1 -1
- package/src/index.ts +32 -14
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,20 +41,29 @@ 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
|
-
|
|
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;
|
|
56
64
|
const approx = react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.PointVector);
|
|
57
|
-
|
|
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);
|
|
58
67
|
const approxJS = react_native_fast_opencv_1.OpenCV.toJSValue(approx);
|
|
59
68
|
if (approxJS && approxJS.array && approxJS.array.length === 4) {
|
|
60
69
|
maxArea = area;
|
|
@@ -62,6 +71,10 @@ class DocumentScanner {
|
|
|
62
71
|
}
|
|
63
72
|
}
|
|
64
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);
|
|
65
78
|
if (largestPoly && largestPoly.length === 4) {
|
|
66
79
|
return this.sortCorners(largestPoly);
|
|
67
80
|
}
|
|
@@ -69,7 +82,9 @@ class DocumentScanner {
|
|
|
69
82
|
}
|
|
70
83
|
catch (e) {
|
|
71
84
|
console.error('Lỗi khi dò tìm góc tài liệu (OpenCV):', e);
|
|
72
|
-
|
|
85
|
+
if (onLog)
|
|
86
|
+
onLog(`[OpenCV Corner Detection Error]: ${e.message}`);
|
|
87
|
+
throw new Error(`[OpenCV Corner Detection Error]: ${e.message}`);
|
|
73
88
|
}
|
|
74
89
|
finally {
|
|
75
90
|
react_native_fast_opencv_1.OpenCV.clearBuffers();
|
|
@@ -78,7 +93,7 @@ class DocumentScanner {
|
|
|
78
93
|
/**
|
|
79
94
|
* Bước 2: Perspective Correction
|
|
80
95
|
*/
|
|
81
|
-
static applyPerspectiveCorrection(imageBase64, corners) {
|
|
96
|
+
static applyPerspectiveCorrection(imageBase64, corners, onLog) {
|
|
82
97
|
let src = null;
|
|
83
98
|
let dst = null;
|
|
84
99
|
try {
|
|
@@ -108,13 +123,16 @@ class DocumentScanner {
|
|
|
108
123
|
react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.Point2f, maxWidth - 1, maxHeight - 1),
|
|
109
124
|
react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.Point2f, 0, maxHeight - 1)
|
|
110
125
|
]);
|
|
111
|
-
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);
|
|
112
127
|
const size = react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.Size, maxWidth, maxHeight);
|
|
113
|
-
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);
|
|
114
130
|
return react_native_fast_opencv_1.OpenCV.invoke('toBase64', dst);
|
|
115
131
|
}
|
|
116
132
|
catch (e) {
|
|
117
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}`);
|
|
118
136
|
return undefined;
|
|
119
137
|
}
|
|
120
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,25 +51,36 @@ 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
|
|
78
|
+
if (area > maxArea && area > 10000) {
|
|
79
|
+
const periObj = OpenCV.invoke('arcLength', contour, true);
|
|
80
|
+
const peri = periObj ? periObj.value : 0;
|
|
71
81
|
const approx = OpenCV.createObject(ObjectType.PointVector);
|
|
72
|
-
|
|
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
85
|
const approxJS = OpenCV.toJSValue(approx);
|
|
75
86
|
if (approxJS && approxJS.array && approxJS.array.length === 4) {
|
|
@@ -78,14 +89,18 @@ export class DocumentScanner {
|
|
|
78
89
|
}
|
|
79
90
|
}
|
|
80
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);
|
|
81
95
|
|
|
82
96
|
if (largestPoly && largestPoly.length === 4) {
|
|
83
97
|
return this.sortCorners(largestPoly);
|
|
84
98
|
}
|
|
85
99
|
return undefined;
|
|
86
|
-
} catch (e) {
|
|
100
|
+
} catch (e: any) {
|
|
87
101
|
console.error('Lỗi khi dò tìm góc tài liệu (OpenCV):', e);
|
|
88
|
-
|
|
102
|
+
if (onLog) onLog(`[OpenCV Corner Detection Error]: ${e.message}`);
|
|
103
|
+
throw new Error(`[OpenCV Corner Detection Error]: ${e.message}`);
|
|
89
104
|
} finally {
|
|
90
105
|
OpenCV.clearBuffers();
|
|
91
106
|
}
|
|
@@ -94,7 +109,7 @@ export class DocumentScanner {
|
|
|
94
109
|
/**
|
|
95
110
|
* Bước 2: Perspective Correction
|
|
96
111
|
*/
|
|
97
|
-
public static applyPerspectiveCorrection(imageBase64: string, corners: Point[]): string | undefined {
|
|
112
|
+
public static applyPerspectiveCorrection(imageBase64: string, corners: Point[], onLog?: (msg: string) => void): string | undefined {
|
|
98
113
|
let src: OpenCVMat | null = null;
|
|
99
114
|
let dst: OpenCVMat | null = null;
|
|
100
115
|
|
|
@@ -134,14 +149,17 @@ export class DocumentScanner {
|
|
|
134
149
|
]
|
|
135
150
|
);
|
|
136
151
|
|
|
137
|
-
const perspectiveMatrix = OpenCV.invoke('getPerspectiveTransform', srcPoints, dstPoints);
|
|
152
|
+
const perspectiveMatrix = OpenCV.invoke('getPerspectiveTransform', srcPoints, dstPoints, 0);
|
|
138
153
|
|
|
139
154
|
const size = OpenCV.createObject(ObjectType.Size, maxWidth, maxHeight);
|
|
140
|
-
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);
|
|
141
158
|
|
|
142
159
|
return OpenCV.invoke('toBase64', dst);
|
|
143
160
|
} catch (e) {
|
|
144
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}`);
|
|
145
163
|
return undefined;
|
|
146
164
|
} finally {
|
|
147
165
|
OpenCV.clearBuffers();
|