react-native-rectangle-doc-scanner 3.231.0 → 3.233.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.
|
@@ -104,6 +104,7 @@ class DocumentDetector {
|
|
|
104
104
|
val grayMat = Mat()
|
|
105
105
|
val blurredMat = Mat()
|
|
106
106
|
val cannyMat = Mat()
|
|
107
|
+
val morphMat = Mat()
|
|
107
108
|
|
|
108
109
|
try {
|
|
109
110
|
// Convert to grayscale
|
|
@@ -113,17 +114,20 @@ class DocumentDetector {
|
|
|
113
114
|
srcMat.copyTo(grayMat)
|
|
114
115
|
}
|
|
115
116
|
|
|
116
|
-
// Apply
|
|
117
|
-
Imgproc.GaussianBlur(grayMat, blurredMat, Size(
|
|
117
|
+
// Apply a light blur to reduce noise without killing small edges.
|
|
118
|
+
Imgproc.GaussianBlur(grayMat, blurredMat, Size(3.0, 3.0), 0.0)
|
|
118
119
|
|
|
119
|
-
// Apply Canny edge detection
|
|
120
|
-
Imgproc.Canny(blurredMat, cannyMat,
|
|
120
|
+
// Apply Canny edge detection with slightly lower thresholds for small documents.
|
|
121
|
+
Imgproc.Canny(blurredMat, cannyMat, 50.0, 150.0)
|
|
122
|
+
val kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, Size(3.0, 3.0))
|
|
123
|
+
Imgproc.morphologyEx(cannyMat, morphMat, Imgproc.MORPH_CLOSE, kernel)
|
|
124
|
+
kernel.release()
|
|
121
125
|
|
|
122
126
|
// Find contours
|
|
123
127
|
val contours = mutableListOf<MatOfPoint>()
|
|
124
128
|
val hierarchy = Mat()
|
|
125
129
|
Imgproc.findContours(
|
|
126
|
-
|
|
130
|
+
morphMat,
|
|
127
131
|
contours,
|
|
128
132
|
hierarchy,
|
|
129
133
|
Imgproc.RETR_EXTERNAL,
|
|
@@ -133,12 +137,13 @@ class DocumentDetector {
|
|
|
133
137
|
// Find the largest contour that approximates to a quadrilateral
|
|
134
138
|
var largestRectangle: Rectangle? = null
|
|
135
139
|
var largestArea = 0.0
|
|
140
|
+
val minArea = max(1000.0, (srcMat.rows() * srcMat.cols()) * 0.002)
|
|
136
141
|
|
|
137
142
|
for (contour in contours) {
|
|
138
143
|
val contourArea = Imgproc.contourArea(contour)
|
|
139
144
|
|
|
140
145
|
// Filter small contours
|
|
141
|
-
if (contourArea <
|
|
146
|
+
if (contourArea < minArea) continue
|
|
142
147
|
|
|
143
148
|
// Approximate contour to polygon
|
|
144
149
|
val approx = MatOfPoint2f()
|
|
@@ -168,6 +173,7 @@ class DocumentDetector {
|
|
|
168
173
|
grayMat.release()
|
|
169
174
|
blurredMat.release()
|
|
170
175
|
cannyMat.release()
|
|
176
|
+
morphMat.release()
|
|
171
177
|
}
|
|
172
178
|
}
|
|
173
179
|
|
|
@@ -222,6 +228,42 @@ class DocumentDetector {
|
|
|
222
228
|
return RectangleQuality.GOOD
|
|
223
229
|
}
|
|
224
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Evaluate rectangle quality in view coordinates (closer to iOS behavior).
|
|
233
|
+
*/
|
|
234
|
+
fun evaluateRectangleQualityInView(
|
|
235
|
+
rectangle: Rectangle,
|
|
236
|
+
viewWidth: Int,
|
|
237
|
+
viewHeight: Int
|
|
238
|
+
): RectangleQuality {
|
|
239
|
+
if (viewWidth == 0 || viewHeight == 0) {
|
|
240
|
+
return RectangleQuality.TOO_FAR
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
val minDim = min(viewWidth.toDouble(), viewHeight.toDouble())
|
|
244
|
+
val angleThreshold = max(60.0, minDim * 0.05)
|
|
245
|
+
|
|
246
|
+
val topYDiff = abs(rectangle.topRight.y - rectangle.topLeft.y)
|
|
247
|
+
val bottomYDiff = abs(rectangle.bottomLeft.y - rectangle.bottomRight.y)
|
|
248
|
+
val leftXDiff = abs(rectangle.topLeft.x - rectangle.bottomLeft.x)
|
|
249
|
+
val rightXDiff = abs(rectangle.topRight.x - rectangle.bottomRight.x)
|
|
250
|
+
|
|
251
|
+
if (topYDiff > angleThreshold || bottomYDiff > angleThreshold || leftXDiff > angleThreshold || rightXDiff > angleThreshold) {
|
|
252
|
+
return RectangleQuality.BAD_ANGLE
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
val margin = max(150.0, minDim * 0.15)
|
|
256
|
+
if (rectangle.topLeft.y > margin ||
|
|
257
|
+
rectangle.topRight.y > margin ||
|
|
258
|
+
rectangle.bottomLeft.y < (viewHeight - margin) ||
|
|
259
|
+
rectangle.bottomRight.y < (viewHeight - margin)
|
|
260
|
+
) {
|
|
261
|
+
return RectangleQuality.TOO_FAR
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return RectangleQuality.GOOD
|
|
265
|
+
}
|
|
266
|
+
|
|
225
267
|
/**
|
|
226
268
|
* Calculate perimeter of rectangle
|
|
227
269
|
*/
|
|
@@ -186,17 +186,17 @@ class DocumentScannerView(context: ThemedReactContext) : FrameLayout(context), L
|
|
|
186
186
|
}
|
|
187
187
|
lastDetectionTimestamp = now
|
|
188
188
|
|
|
189
|
-
val quality = if (rectangle != null) {
|
|
190
|
-
DocumentDetector.evaluateRectangleQuality(rectangle, imageWidth, imageHeight)
|
|
191
|
-
} else {
|
|
192
|
-
RectangleQuality.TOO_FAR
|
|
193
|
-
}
|
|
194
|
-
|
|
195
189
|
val rectangleOnScreen = if (rectangle != null && width > 0 && height > 0) {
|
|
196
190
|
DocumentDetector.transformRectangleToViewCoordinates(rectangle, imageWidth, imageHeight, width, height)
|
|
197
191
|
} else {
|
|
198
192
|
null
|
|
199
193
|
}
|
|
194
|
+
val quality = when {
|
|
195
|
+
rectangleOnScreen != null && width > 0 && height > 0 ->
|
|
196
|
+
DocumentDetector.evaluateRectangleQualityInView(rectangleOnScreen, width, height)
|
|
197
|
+
rectangle != null -> DocumentDetector.evaluateRectangleQuality(rectangle, imageWidth, imageHeight)
|
|
198
|
+
else -> RectangleQuality.TOO_FAR
|
|
199
|
+
}
|
|
200
200
|
|
|
201
201
|
post {
|
|
202
202
|
onRectangleDetected(rectangleOnScreen, rectangle, quality, imageWidth, imageHeight)
|
package/package.json
CHANGED