@@ -20,8 +20,8 @@ public static class QuadrilateralDetector
2020 private const double SizeWeight = 0.6 ;
2121 private const double RectangularityWeight = 0.4 ;
2222
23- // Duplicate detection threshold - quadrilaterals with corners closer than this are considered duplicates
24- private const double DuplicateDistanceThreshold = 5.0 ; // pixels
23+ // Duplicate detection: fraction of the image's short side used as the proximity diameter
24+ private const double DuplicateDiameterFraction = 0.02 ;
2525
2626 /// <summary>
2727 /// Represents a detected quadrilateral with its corner points
@@ -185,8 +185,8 @@ public static DetectionResult DetectQuadrilateralsWithDimensions(string imagePat
185185 }
186186 }
187187
188- // Remove duplicates before sorting
189- result . Quadrilaterals = FilterDuplicates ( result . Quadrilaterals ) ;
188+ // Remove duplicates before sorting (threshold is 2% of the short side)
189+ result . Quadrilaterals = FilterDuplicates ( result . Quadrilaterals , result . ImageWidth , result . ImageHeight ) ;
190190
191191 // Sort by confidence (highest first) and take top results
192192 result . Quadrilaterals = [ .. result . Quadrilaterals . OrderByDescending ( q => q . Confidence ) . Take ( maxResults ) ] ;
@@ -302,25 +302,36 @@ private static double CalculateAngle(System.Windows.Point p1, System.Windows.Poi
302302 }
303303
304304 /// <summary>
305- /// Filter out duplicate quadrilaterals that have very similar corner positions
305+ /// Filter out duplicate quadrilaterals that have very similar corner positions.
306+ /// Two quads are duplicates when every corresponding corner is within a circle
307+ /// whose diameter is 2% of the image's short side. Among duplicates the smallest
308+ /// quadrilateral (by area) is kept.
306309 /// </summary>
307- private static List < DetectedQuadrilateral > FilterDuplicates ( List < DetectedQuadrilateral > quadrilaterals )
310+ private static List < DetectedQuadrilateral > FilterDuplicates (
311+ List < DetectedQuadrilateral > quadrilaterals , double imageWidth , double imageHeight )
308312 {
313+ double shortSide = Math . Min ( imageWidth , imageHeight ) ;
314+ double threshold = DuplicateDiameterFraction * shortSide ;
315+
309316 List < DetectedQuadrilateral > filtered = [ ] ;
310317
311318 foreach ( DetectedQuadrilateral quad in quadrilaterals )
312319 {
313- bool isDuplicate = false ;
314- foreach ( DetectedQuadrilateral existing in filtered )
320+ bool merged = false ;
321+ for ( int i = 0 ; i < filtered . Count ; i ++ )
315322 {
316- if ( AreDuplicates ( quad , existing ) )
323+ if ( AreDuplicates ( quad , filtered [ i ] , threshold ) )
317324 {
318- isDuplicate = true ;
325+ // Keep the smaller quadrilateral
326+ if ( quad . Area < filtered [ i ] . Area )
327+ filtered [ i ] = quad ;
328+
329+ merged = true ;
319330 break ;
320331 }
321332 }
322333
323- if ( ! isDuplicate )
334+ if ( ! merged )
324335 {
325336 filtered . Add ( quad ) ;
326337 }
@@ -330,20 +341,16 @@ private static List<DetectedQuadrilateral> FilterDuplicates(List<DetectedQuadril
330341 }
331342
332343 /// <summary>
333- /// Check if two quadrilaterals are duplicates based on corner proximity
344+ /// Check if two quadrilaterals are duplicates: every corresponding corner
345+ /// must be within the given distance threshold.
334346 /// </summary>
335- private static bool AreDuplicates ( DetectedQuadrilateral quad1 , DetectedQuadrilateral quad2 )
347+ private static bool AreDuplicates (
348+ DetectedQuadrilateral quad1 , DetectedQuadrilateral quad2 , double threshold )
336349 {
337- // Calculate average distance between corresponding corners
338- double totalDistance =
339- Distance ( quad1 . TopLeft , quad2 . TopLeft ) +
340- Distance ( quad1 . TopRight , quad2 . TopRight ) +
341- Distance ( quad1 . BottomRight , quad2 . BottomRight ) +
342- Distance ( quad1 . BottomLeft , quad2 . BottomLeft ) ;
343-
344- double averageDistance = totalDistance / 4.0 ;
345-
346- return averageDistance < DuplicateDistanceThreshold ;
350+ return Distance ( quad1 . TopLeft , quad2 . TopLeft ) < threshold
351+ && Distance ( quad1 . TopRight , quad2 . TopRight ) < threshold
352+ && Distance ( quad1 . BottomRight , quad2 . BottomRight ) < threshold
353+ && Distance ( quad1 . BottomLeft , quad2 . BottomLeft ) < threshold ;
347354 }
348355
349356 /// <summary>
0 commit comments