react-native-rectangle-doc-scanner 0.36.0 → 0.37.0
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/DocScanner.js +47 -7
- package/package.json +1 -1
- package/src/DocScanner.tsx +51 -7
package/dist/DocScanner.js
CHANGED
|
@@ -91,12 +91,52 @@ const DocScanner = ({ onCapture, overlayColor = '#e7a649', autoCapture = true, m
|
|
|
91
91
|
(0, react_1.useEffect)(() => {
|
|
92
92
|
requestPermission();
|
|
93
93
|
}, [requestPermission]);
|
|
94
|
+
const lastQuadRef = (0, react_1.useRef)(null);
|
|
95
|
+
const smoothingBufferRef = (0, react_1.useRef)([]);
|
|
94
96
|
const updateQuad = (0, react_native_worklets_core_1.useRunOnJS)((value) => {
|
|
95
97
|
if (__DEV__) {
|
|
96
98
|
console.log('[DocScanner] quad', value);
|
|
97
99
|
}
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
+
// Add to smoothing buffer
|
|
101
|
+
smoothingBufferRef.current.push(value);
|
|
102
|
+
// Keep only last 3 frames for smoothing
|
|
103
|
+
if (smoothingBufferRef.current.length > 3) {
|
|
104
|
+
smoothingBufferRef.current.shift();
|
|
105
|
+
}
|
|
106
|
+
// If we have a valid quad, smooth it
|
|
107
|
+
if (value && value.length === 4) {
|
|
108
|
+
// Average with previous frames if available
|
|
109
|
+
if (smoothingBufferRef.current.length >= 2) {
|
|
110
|
+
const validQuads = smoothingBufferRef.current.filter(q => q !== null && q.length === 4);
|
|
111
|
+
if (validQuads.length >= 2) {
|
|
112
|
+
// Average the positions
|
|
113
|
+
const smoothed = value.map((_, idx) => {
|
|
114
|
+
let sumX = 0;
|
|
115
|
+
let sumY = 0;
|
|
116
|
+
validQuads.forEach(quad => {
|
|
117
|
+
sumX += quad[idx].x;
|
|
118
|
+
sumY += quad[idx].y;
|
|
119
|
+
});
|
|
120
|
+
return {
|
|
121
|
+
x: sumX / validQuads.length,
|
|
122
|
+
y: sumY / validQuads.length,
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
lastQuadRef.current = smoothed;
|
|
126
|
+
setQuad(smoothed);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
lastQuadRef.current = value;
|
|
131
|
+
setQuad(value);
|
|
132
|
+
}
|
|
133
|
+
else if (lastQuadRef.current) {
|
|
134
|
+
// Keep showing last quad for 1 frame to reduce flickering
|
|
135
|
+
setQuad(lastQuadRef.current);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
setQuad(null);
|
|
139
|
+
}
|
|
100
140
|
}, []);
|
|
101
141
|
const reportError = (0, react_native_worklets_core_1.useRunOnJS)((step, error) => {
|
|
102
142
|
const message = error instanceof Error ? error.message : `${error}`;
|
|
@@ -115,8 +155,8 @@ const DocScanner = ({ onCapture, overlayColor = '#e7a649', autoCapture = true, m
|
|
|
115
155
|
try {
|
|
116
156
|
// Report frame size for coordinate transformation
|
|
117
157
|
updateFrameSize(frame.width, frame.height);
|
|
118
|
-
// Use higher resolution for better accuracy -
|
|
119
|
-
const ratio =
|
|
158
|
+
// Use higher resolution for better accuracy - 960p
|
|
159
|
+
const ratio = 960 / frame.width;
|
|
120
160
|
const width = Math.floor(frame.width * ratio);
|
|
121
161
|
const height = Math.floor(frame.height * ratio);
|
|
122
162
|
step = 'resize';
|
|
@@ -145,7 +185,7 @@ const DocScanner = ({ onCapture, overlayColor = '#e7a649', autoCapture = true, m
|
|
|
145
185
|
react_native_fast_opencv_1.OpenCV.invoke('GaussianBlur', mat, mat, gaussianKernel, 0);
|
|
146
186
|
step = 'Canny';
|
|
147
187
|
reportStage(step);
|
|
148
|
-
react_native_fast_opencv_1.OpenCV.invoke('Canny', mat, mat,
|
|
188
|
+
react_native_fast_opencv_1.OpenCV.invoke('Canny', mat, mat, 30, 100);
|
|
149
189
|
step = 'createContours';
|
|
150
190
|
reportStage(step);
|
|
151
191
|
const contours = react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.PointVectorOfVectors);
|
|
@@ -187,8 +227,8 @@ const DocScanner = ({ onCapture, overlayColor = '#e7a649', autoCapture = true, m
|
|
|
187
227
|
const { value: perimeter } = react_native_fast_opencv_1.OpenCV.invoke('arcLength', contour, true);
|
|
188
228
|
const approx = react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.PointVector);
|
|
189
229
|
let approxArray = [];
|
|
190
|
-
// Try epsilon values from 0.
|
|
191
|
-
const epsilonValues = [0.
|
|
230
|
+
// Try epsilon values from 0.3% to 6% of perimeter for better corner detection
|
|
231
|
+
const epsilonValues = [0.003, 0.005, 0.007, 0.009, 0.011, 0.013, 0.015, 0.018, 0.02, 0.025, 0.03, 0.04, 0.05, 0.06];
|
|
192
232
|
for (let attempt = 0; attempt < epsilonValues.length; attempt += 1) {
|
|
193
233
|
const epsilon = epsilonValues[attempt] * perimeter;
|
|
194
234
|
step = `contour_${i}_approxPolyDP_attempt_${attempt}`;
|
package/package.json
CHANGED
package/src/DocScanner.tsx
CHANGED
|
@@ -96,13 +96,57 @@ export const DocScanner: React.FC<Props> = ({
|
|
|
96
96
|
requestPermission();
|
|
97
97
|
}, [requestPermission]);
|
|
98
98
|
|
|
99
|
+
const lastQuadRef = useRef<Point[] | null>(null);
|
|
100
|
+
const smoothingBufferRef = useRef<(Point[] | null)[]>([]);
|
|
101
|
+
|
|
99
102
|
const updateQuad = useRunOnJS((value: Point[] | null) => {
|
|
100
103
|
if (__DEV__) {
|
|
101
104
|
console.log('[DocScanner] quad', value);
|
|
102
105
|
}
|
|
103
106
|
|
|
104
|
-
//
|
|
105
|
-
|
|
107
|
+
// Add to smoothing buffer
|
|
108
|
+
smoothingBufferRef.current.push(value);
|
|
109
|
+
|
|
110
|
+
// Keep only last 3 frames for smoothing
|
|
111
|
+
if (smoothingBufferRef.current.length > 3) {
|
|
112
|
+
smoothingBufferRef.current.shift();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// If we have a valid quad, smooth it
|
|
116
|
+
if (value && value.length === 4) {
|
|
117
|
+
// Average with previous frames if available
|
|
118
|
+
if (smoothingBufferRef.current.length >= 2) {
|
|
119
|
+
const validQuads = smoothingBufferRef.current.filter(q => q !== null && q.length === 4) as Point[][];
|
|
120
|
+
|
|
121
|
+
if (validQuads.length >= 2) {
|
|
122
|
+
// Average the positions
|
|
123
|
+
const smoothed: Point[] = value.map((_, idx) => {
|
|
124
|
+
let sumX = 0;
|
|
125
|
+
let sumY = 0;
|
|
126
|
+
validQuads.forEach(quad => {
|
|
127
|
+
sumX += quad[idx].x;
|
|
128
|
+
sumY += quad[idx].y;
|
|
129
|
+
});
|
|
130
|
+
return {
|
|
131
|
+
x: sumX / validQuads.length,
|
|
132
|
+
y: sumY / validQuads.length,
|
|
133
|
+
};
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
lastQuadRef.current = smoothed;
|
|
137
|
+
setQuad(smoothed);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
lastQuadRef.current = value;
|
|
143
|
+
setQuad(value);
|
|
144
|
+
} else if (lastQuadRef.current) {
|
|
145
|
+
// Keep showing last quad for 1 frame to reduce flickering
|
|
146
|
+
setQuad(lastQuadRef.current);
|
|
147
|
+
} else {
|
|
148
|
+
setQuad(null);
|
|
149
|
+
}
|
|
106
150
|
}, []);
|
|
107
151
|
|
|
108
152
|
const reportError = useRunOnJS((step: string, error: unknown) => {
|
|
@@ -128,8 +172,8 @@ export const DocScanner: React.FC<Props> = ({
|
|
|
128
172
|
// Report frame size for coordinate transformation
|
|
129
173
|
updateFrameSize(frame.width, frame.height);
|
|
130
174
|
|
|
131
|
-
// Use higher resolution for better accuracy -
|
|
132
|
-
const ratio =
|
|
175
|
+
// Use higher resolution for better accuracy - 960p
|
|
176
|
+
const ratio = 960 / frame.width;
|
|
133
177
|
const width = Math.floor(frame.width * ratio);
|
|
134
178
|
const height = Math.floor(frame.height * ratio);
|
|
135
179
|
step = 'resize';
|
|
@@ -162,7 +206,7 @@ export const DocScanner: React.FC<Props> = ({
|
|
|
162
206
|
OpenCV.invoke('GaussianBlur', mat, mat, gaussianKernel, 0);
|
|
163
207
|
step = 'Canny';
|
|
164
208
|
reportStage(step);
|
|
165
|
-
OpenCV.invoke('Canny', mat, mat,
|
|
209
|
+
OpenCV.invoke('Canny', mat, mat, 30, 100);
|
|
166
210
|
|
|
167
211
|
step = 'createContours';
|
|
168
212
|
reportStage(step);
|
|
@@ -217,8 +261,8 @@ export const DocScanner: React.FC<Props> = ({
|
|
|
217
261
|
|
|
218
262
|
let approxArray: Array<{ x: number; y: number }> = [];
|
|
219
263
|
|
|
220
|
-
// Try epsilon values from 0.
|
|
221
|
-
const epsilonValues = [0.
|
|
264
|
+
// Try epsilon values from 0.3% to 6% of perimeter for better corner detection
|
|
265
|
+
const epsilonValues = [0.003, 0.005, 0.007, 0.009, 0.011, 0.013, 0.015, 0.018, 0.02, 0.025, 0.03, 0.04, 0.05, 0.06];
|
|
222
266
|
|
|
223
267
|
for (let attempt = 0; attempt < epsilonValues.length; attempt += 1) {
|
|
224
268
|
const epsilon = epsilonValues[attempt] * perimeter;
|