react-native-rectangle-doc-scanner 0.32.0 → 0.34.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 +11 -43
- package/package.json +1 -1
- package/src/DocScanner.tsx +12 -48
package/dist/DocScanner.js
CHANGED
|
@@ -184,7 +184,10 @@ const DocScanner = ({ onCapture, overlayColor = '#e7a649', autoCapture = true, m
|
|
|
184
184
|
reportStage(step);
|
|
185
185
|
const { value: area } = react_native_fast_opencv_1.OpenCV.invoke('contourArea', contour, false);
|
|
186
186
|
// Skip extremely small contours, but keep threshold very low to allow distant documents
|
|
187
|
-
if (area
|
|
187
|
+
if (typeof area !== 'number' || !isFinite(area)) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (area < 50) {
|
|
188
191
|
continue;
|
|
189
192
|
}
|
|
190
193
|
step = `contour_${i}_area`; // ratio stage
|
|
@@ -193,25 +196,23 @@ const DocScanner = ({ onCapture, overlayColor = '#e7a649', autoCapture = true, m
|
|
|
193
196
|
if (__DEV__) {
|
|
194
197
|
console.log('[DocScanner] area', area, 'ratio', areaRatio);
|
|
195
198
|
}
|
|
196
|
-
if
|
|
199
|
+
// Skip if area ratio is too small or too large
|
|
200
|
+
if (areaRatio < 0.01 || areaRatio > 0.95) {
|
|
197
201
|
continue;
|
|
198
202
|
}
|
|
199
|
-
// Use convex hull to simplify contour before polygon approximation
|
|
200
|
-
const hull = react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.PointVector);
|
|
201
|
-
react_native_fast_opencv_1.OpenCV.invoke('convexHull', contour, hull);
|
|
202
203
|
step = `contour_${i}_arcLength`;
|
|
203
204
|
reportStage(step);
|
|
204
|
-
const { value: perimeter } = react_native_fast_opencv_1.OpenCV.invoke('arcLength',
|
|
205
|
+
const { value: perimeter } = react_native_fast_opencv_1.OpenCV.invoke('arcLength', contour, true);
|
|
205
206
|
const approx = react_native_fast_opencv_1.OpenCV.createObject(react_native_fast_opencv_1.ObjectType.PointVector);
|
|
206
207
|
let approxArray = [];
|
|
207
208
|
// Start with smaller epsilon for more accurate corner detection
|
|
208
|
-
// Try epsilon values from 0.
|
|
209
|
-
const epsilonValues = [0.
|
|
209
|
+
// Try epsilon values from 0.5% to 5% of perimeter
|
|
210
|
+
const epsilonValues = [0.005, 0.01, 0.015, 0.02, 0.025, 0.03, 0.035, 0.04, 0.045, 0.05];
|
|
210
211
|
for (let attempt = 0; attempt < epsilonValues.length; attempt += 1) {
|
|
211
212
|
const epsilon = epsilonValues[attempt] * perimeter;
|
|
212
213
|
step = `contour_${i}_approxPolyDP_attempt_${attempt}`;
|
|
213
214
|
reportStage(step);
|
|
214
|
-
react_native_fast_opencv_1.OpenCV.invoke('approxPolyDP',
|
|
215
|
+
react_native_fast_opencv_1.OpenCV.invoke('approxPolyDP', contour, approx, epsilon, true);
|
|
215
216
|
step = `contour_${i}_toJS_attempt_${attempt}`;
|
|
216
217
|
reportStage(step);
|
|
217
218
|
const approxValue = react_native_fast_opencv_1.OpenCV.toJSValue(approx);
|
|
@@ -224,40 +225,7 @@ const DocScanner = ({ onCapture, overlayColor = '#e7a649', autoCapture = true, m
|
|
|
224
225
|
break;
|
|
225
226
|
}
|
|
226
227
|
}
|
|
227
|
-
if
|
|
228
|
-
// fallback: rotated rectangle using minAreaRect
|
|
229
|
-
try {
|
|
230
|
-
const rect = react_native_fast_opencv_1.OpenCV.invoke('minAreaRect', contour);
|
|
231
|
-
const rectValue = rect?.value ?? rect;
|
|
232
|
-
const centerX = rectValue.centerX ?? rectValue.center?.x ?? 0;
|
|
233
|
-
const centerY = rectValue.centerY ?? rectValue.center?.y ?? 0;
|
|
234
|
-
const rectW = rectValue.width ?? rectValue.size?.width ?? 0;
|
|
235
|
-
const rectH = rectValue.height ?? rectValue.size?.height ?? 0;
|
|
236
|
-
const angleDeg = rectValue.angle ?? rectValue.rotation ?? 0;
|
|
237
|
-
if (rectW > 0 && rectH > 0) {
|
|
238
|
-
const angleRad = (angleDeg * Math.PI) / 180;
|
|
239
|
-
const cosA = Math.cos(angleRad);
|
|
240
|
-
const sinA = Math.sin(angleRad);
|
|
241
|
-
const halfW = rectW / 2;
|
|
242
|
-
const halfH = rectH / 2;
|
|
243
|
-
approxArray = [
|
|
244
|
-
{ x: centerX - halfW * cosA + halfH * sinA, y: centerY - halfW * sinA - halfH * cosA },
|
|
245
|
-
{ x: centerX + halfW * cosA + halfH * sinA, y: centerY + halfW * sinA - halfH * cosA },
|
|
246
|
-
{ x: centerX + halfW * cosA - halfH * sinA, y: centerY + halfW * sinA + halfH * cosA },
|
|
247
|
-
{ x: centerX - halfW * cosA - halfH * sinA, y: centerY - halfW * sinA + halfH * cosA },
|
|
248
|
-
];
|
|
249
|
-
if (__DEV__) {
|
|
250
|
-
console.log('[DocScanner] minAreaRect fallback', rectValue, approxArray);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
catch (err) {
|
|
255
|
-
if (__DEV__) {
|
|
256
|
-
console.warn('[DocScanner] minAreaRect fallback failed', err);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
// Only proceed if we found exactly 4 corners after fallback
|
|
228
|
+
// Only proceed if we found exactly 4 corners
|
|
261
229
|
if (approxArray.length !== 4) {
|
|
262
230
|
continue;
|
|
263
231
|
}
|
package/package.json
CHANGED
package/src/DocScanner.tsx
CHANGED
|
@@ -208,7 +208,11 @@ export const DocScanner: React.FC<Props> = ({
|
|
|
208
208
|
const { value: area } = OpenCV.invoke('contourArea', contour, false);
|
|
209
209
|
|
|
210
210
|
// Skip extremely small contours, but keep threshold very low to allow distant documents
|
|
211
|
-
if (area
|
|
211
|
+
if (typeof area !== 'number' || !isFinite(area)) {
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (area < 50) {
|
|
212
216
|
continue;
|
|
213
217
|
}
|
|
214
218
|
|
|
@@ -220,30 +224,27 @@ export const DocScanner: React.FC<Props> = ({
|
|
|
220
224
|
console.log('[DocScanner] area', area, 'ratio', areaRatio);
|
|
221
225
|
}
|
|
222
226
|
|
|
223
|
-
if
|
|
227
|
+
// Skip if area ratio is too small or too large
|
|
228
|
+
if (areaRatio < 0.01 || areaRatio > 0.95) {
|
|
224
229
|
continue;
|
|
225
230
|
}
|
|
226
231
|
|
|
227
|
-
// Use convex hull to simplify contour before polygon approximation
|
|
228
|
-
const hull = OpenCV.createObject(ObjectType.PointVector);
|
|
229
|
-
OpenCV.invoke('convexHull', contour, hull);
|
|
230
|
-
|
|
231
232
|
step = `contour_${i}_arcLength`;
|
|
232
233
|
reportStage(step);
|
|
233
|
-
const { value: perimeter } = OpenCV.invoke('arcLength',
|
|
234
|
+
const { value: perimeter } = OpenCV.invoke('arcLength', contour, true);
|
|
234
235
|
const approx = OpenCV.createObject(ObjectType.PointVector);
|
|
235
236
|
|
|
236
237
|
let approxArray: Array<{ x: number; y: number }> = [];
|
|
237
238
|
|
|
238
239
|
// Start with smaller epsilon for more accurate corner detection
|
|
239
|
-
// Try epsilon values from 0.
|
|
240
|
-
const epsilonValues = [0.
|
|
240
|
+
// Try epsilon values from 0.5% to 5% of perimeter
|
|
241
|
+
const epsilonValues = [0.005, 0.01, 0.015, 0.02, 0.025, 0.03, 0.035, 0.04, 0.045, 0.05];
|
|
241
242
|
|
|
242
243
|
for (let attempt = 0; attempt < epsilonValues.length; attempt += 1) {
|
|
243
244
|
const epsilon = epsilonValues[attempt] * perimeter;
|
|
244
245
|
step = `contour_${i}_approxPolyDP_attempt_${attempt}`;
|
|
245
246
|
reportStage(step);
|
|
246
|
-
OpenCV.invoke('approxPolyDP',
|
|
247
|
+
OpenCV.invoke('approxPolyDP', contour, approx, epsilon, true);
|
|
247
248
|
|
|
248
249
|
step = `contour_${i}_toJS_attempt_${attempt}`;
|
|
249
250
|
reportStage(step);
|
|
@@ -260,44 +261,7 @@ export const DocScanner: React.FC<Props> = ({
|
|
|
260
261
|
}
|
|
261
262
|
}
|
|
262
263
|
|
|
263
|
-
if
|
|
264
|
-
// fallback: rotated rectangle using minAreaRect
|
|
265
|
-
try {
|
|
266
|
-
const rect = OpenCV.invoke('minAreaRect', contour);
|
|
267
|
-
const rectValue = rect?.value ?? rect;
|
|
268
|
-
|
|
269
|
-
const centerX = rectValue.centerX ?? rectValue.center?.x ?? 0;
|
|
270
|
-
const centerY = rectValue.centerY ?? rectValue.center?.y ?? 0;
|
|
271
|
-
const rectW = rectValue.width ?? rectValue.size?.width ?? 0;
|
|
272
|
-
const rectH = rectValue.height ?? rectValue.size?.height ?? 0;
|
|
273
|
-
const angleDeg = rectValue.angle ?? rectValue.rotation ?? 0;
|
|
274
|
-
|
|
275
|
-
if (rectW > 0 && rectH > 0) {
|
|
276
|
-
const angleRad = (angleDeg * Math.PI) / 180;
|
|
277
|
-
const cosA = Math.cos(angleRad);
|
|
278
|
-
const sinA = Math.sin(angleRad);
|
|
279
|
-
const halfW = rectW / 2;
|
|
280
|
-
const halfH = rectH / 2;
|
|
281
|
-
|
|
282
|
-
approxArray = [
|
|
283
|
-
{ x: centerX - halfW * cosA + halfH * sinA, y: centerY - halfW * sinA - halfH * cosA },
|
|
284
|
-
{ x: centerX + halfW * cosA + halfH * sinA, y: centerY + halfW * sinA - halfH * cosA },
|
|
285
|
-
{ x: centerX + halfW * cosA - halfH * sinA, y: centerY + halfW * sinA + halfH * cosA },
|
|
286
|
-
{ x: centerX - halfW * cosA - halfH * sinA, y: centerY - halfW * sinA + halfH * cosA },
|
|
287
|
-
];
|
|
288
|
-
|
|
289
|
-
if (__DEV__) {
|
|
290
|
-
console.log('[DocScanner] minAreaRect fallback', rectValue, approxArray);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
} catch (err) {
|
|
294
|
-
if (__DEV__) {
|
|
295
|
-
console.warn('[DocScanner] minAreaRect fallback failed', err);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// Only proceed if we found exactly 4 corners after fallback
|
|
264
|
+
// Only proceed if we found exactly 4 corners
|
|
301
265
|
if (approxArray.length !== 4) {
|
|
302
266
|
continue;
|
|
303
267
|
}
|