@@ -10,13 +10,12 @@ import kotlin.math.max
1010import kotlin.math.min
1111import kotlin.math.roundToInt
1212import org.opencv.android.Utils
13- import org.opencv.core.CvType
1413import org.opencv.core.Mat
1514import org.opencv.core.MatOfPoint
16- import org.opencv.core.MatOfPoint2f
17- import org.opencv.imgproc.Imgproc
1815
19- internal class RectangleDetectorImpl : RectangleDetector {
16+ internal class RectangleDetectorImpl (detectionAccuracy : DetectionAccuracy ) : RectangleDetector {
17+ private val strategy = detectionAccuracy.buildContourStrategy()
18+
2019 init {
2120 System .loadLibrary(" opencv_java4" )
2221 }
@@ -27,14 +26,13 @@ internal class RectangleDetectorImpl : RectangleDetector {
2726 val scaledBitmap = bitmap.scaled(scaleRatio, true )
2827
2928 val mat = Mat ().also { Utils .bitmapToMat(scaledBitmap, it) }
30- val edgeMat = markEdgesWithCannyAlgorithm(mat)
31- val edgeClosedMat = closeEdges(edgeMat)
32- val contours = detectContours(edgeClosedMat)
29+ val contours = strategy.detectContours(mat)
3330
3431 // Combine Rectangles approximated to other into one.
3532 val rectangles = contourToRectangles(contours).map { it.scaled(1 / scaleRatio) }
33+ val distanceTolerance = max(scaledBitmap.width, scaledBitmap.height) / 50f
3634 val reducedRectangles = rectangles.fold(emptyList<Rectangle >()) { result, rectangle ->
37- val approximatedRectangle = result.firstOrNull { it.isApproximated(rectangle, 8f ) }
35+ val approximatedRectangle = result.firstOrNull { it.isApproximated(rectangle, distanceTolerance ) }
3836 if (approximatedRectangle != null ) {
3937 result - approximatedRectangle + rectangle.average(approximatedRectangle)
4038 } else {
@@ -48,54 +46,6 @@ internal class RectangleDetectorImpl : RectangleDetector {
4846 )
4947 }
5048
51- private fun markEdgesWithCannyAlgorithm (mat : Mat ): Mat {
52- val result = Mat ()
53- Imgproc .blur(mat, result, org.opencv.core.Size (5.0 , 5.0 ))
54- Imgproc .Canny (mat, result, 250.0 , 100.0 , 3 , true )
55- return result
56- }
57-
58- private fun closeEdges (mat : Mat ): Mat {
59- val result = Mat ()
60- Imgproc .morphologyEx(
61- mat, result, Imgproc .MORPH_CLOSE ,
62- Imgproc .getStructuringElement(Imgproc .MORPH_ELLIPSE , org.opencv.core.Size (5.0 , 5.0 ))
63- )
64- return result
65- }
66-
67- private fun detectContours (mat : Mat ): List <MatOfPoint > {
68- val contours = arrayListOf<MatOfPoint >()
69- val hierarchy = Mat .zeros(org.opencv.core.Size (5.0 , 5.0 ), CvType .CV_8UC1 )
70- Imgproc .findContours(
71- mat,
72- contours,
73- hierarchy,
74- Imgproc .RETR_LIST ,
75- Imgproc .CHAIN_APPROX_NONE
76- )
77-
78- return contours.mapNotNull {
79- // Ignore extremely small size rectangles.
80- if (Imgproc .contourArea(it) < mat.size().area() / 100 ) {
81- return @mapNotNull null
82- }
83-
84- val pointMat = MatOfPoint2f (* it.toArray())
85- val approx = MatOfPoint2f ()
86- val approx2 = MatOfPoint ()
87-
88- val arcLength = Imgproc .arcLength(pointMat, true )
89- Imgproc .approxPolyDP(pointMat, approx, 0.03 * arcLength, true )
90- approx.convertTo(approx2, CvType .CV_32S )
91- if (approx2.size().area() == 4.0 ) {
92- approx2
93- } else {
94- null
95- }
96- }
97- }
98-
9949 private fun contourToRectangles (contour : List <MatOfPoint >): List <Rectangle > = contour.map {
10050 val points = it.toList().map { point ->
10151 Point (point.x.roundToInt(), point.y.roundToInt())
0 commit comments