Yesianrohn commited on
Commit
1e6448c
·
verified ·
1 Parent(s): 8bef246

Update modeling_openocrv2_det.py

Browse files
Files changed (1) hide show
  1. modeling_openocrv2_det.py +73 -28
modeling_openocrv2_det.py CHANGED
@@ -416,36 +416,68 @@ def polygon_points(coefficients, basis, stride):
416
  locations = locations.repeat(1, basis.shape[1] // 2)
417
  return (points + locations) * stride
418
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
419
  def _suppress_contained(polygons, scores, contain=0.95, ratio=0.35):
420
- if len(polygons) < 2:
 
 
 
 
 
 
 
 
 
 
 
421
  return polygons, scores
422
- flat = polygons.reshape(len(polygons), -1, 2)
423
- small_xy = flat.min(dim=1).values
424
- big_xy = flat.max(dim=1).values
425
- areas = (big_xy - small_xy).clamp(min=0).prod(dim=1)
426
-
427
- keep = torch.ones(len(polygons), dtype=torch.bool, device=polygons.device)
428
- order = torch.argsort(areas, descending=True)
429
- for pos, i in enumerate(order.tolist()):
430
- if not keep[i]:
 
431
  continue
432
- for j in order[pos + 1:].tolist():
433
- if not keep[j]:
434
- continue
435
- ix0 = max(small_xy[i][0], small_xy[j][0]); iy0 = max(small_xy[i][1], small_xy[j][1])
436
- ix1 = min(big_xy[i][0], big_xy[j][0]); iy1 = min(big_xy[i][1], big_xy[j][1])
437
- if ix1 <= ix0 or iy1 <= iy0:
438
- continue
439
- inter = (ix1 - ix0) * (iy1 - iy0)
440
- smaller = areas[j]
441
- if smaller <= 0:
442
- continue
443
- if inter / smaller >= contain and smaller / areas[i] <= ratio:
444
- keep[j] = False
 
 
 
445
  return polygons[keep], scores[keep]
446
 
447
 
448
- @torch.no_grad()
449
  def decode_detection(predictions, basis, config, content_shape=None, scale=None):
450
  """Scores plus polygons to accepted boxes, mirroring the frozen decoder.
451
 
@@ -479,11 +511,24 @@ def decode_detection(predictions, basis, config, content_shape=None, scale=None)
479
  flat = polygons.reshape(len(polygons), -1, 2)
480
  boxes = torch.cat((flat.amin(dim=1), flat.amax(dim=1)), dim=1)
481
  keep = nms(boxes, scores, config["nms_threshold"])
482
- keep = nms(boxes, scores, config["nms_threshold"])
483
  polygons, scores = polygons[keep], scores[keep]
484
- polygons, scores = _suppress_contained(polygons, scores,
485
- config.get("contain_threshold", 0.95),
486
- config.get("contain_area_ratio", 0.35))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
  if scale is not None:
488
  polygons = polygons / torch.as_tensor(
489
  scale, dtype=polygons.dtype, device=polygons.device
 
416
  locations = locations.repeat(1, basis.shape[1] // 2)
417
  return (points + locations) * stride
418
 
419
+ @torch.no_grad()
420
+ def _drop_degenerate(polygons, content_shape, config):
421
+ """Mask out boxes that are too small or cover most of the page.
422
+
423
+ A 4-pixel box has no readable content, and a box spanning over a third of
424
+ the image is a layout region, not a text line.
425
+ """
426
+ flat = polygons.reshape(len(polygons), -1, 2)
427
+ wh = (flat.amax(dim=1) - flat.amin(dim=1)).clamp(min=0)
428
+ min_side = float(config.get("min_box_side", 4.0))
429
+ keep = (wh[:, 0] >= min_side) & (wh[:, 1] >= min_side)
430
+ fraction = float(config.get("max_box_area_fraction", 0.3))
431
+ if content_shape is not None and fraction < 1.0:
432
+ height, width = content_shape
433
+ keep = keep & ((wh[:, 0] * wh[:, 1]) <= fraction * float(height * width))
434
+ return keep
435
+
436
+
437
  def _suppress_contained(polygons, scores, contain=0.95, ratio=0.35):
438
+ """Drop boxes nested inside a larger box.
439
+
440
+ Measured on 3544 pages: 54% of images contain nested boxes and 40% of them
441
+ repeat text already returned by the enclosing line. Containment (not IoU)
442
+ is the right test -- a small box inside a large one has a low IoU, so an
443
+ IoU filter never fires.
444
+
445
+ The ratio guard keeps legitimate nesting: a heading inside a paragraph block
446
+ is usually more than a third of its area, so it survives.
447
+ """
448
+ n = len(polygons)
449
+ if n < 2:
450
  return polygons, scores
451
+ flat = polygons.reshape(n, -1, 2)
452
+ lo, hi = flat.amin(dim=1), flat.amax(dim=1)
453
+ areas = (hi - lo).clamp(min=0).prod(dim=1)
454
+
455
+ order = torch.argsort(areas, descending=True)
456
+ lo, hi, areas = lo[order], hi[order], areas[order]
457
+ alive = torch.ones(n, dtype=torch.bool, device=areas.device)
458
+
459
+ for pos in range(n - 1):
460
+ if not bool(alive[pos]):
461
  continue
462
+ candidate = alive[pos + 1:]
463
+ if not bool(candidate.any()):
464
+ continue
465
+ c_lo, c_hi, c_area = lo[pos + 1:], hi[pos + 1:], areas[pos + 1:]
466
+ ix0 = torch.maximum(lo[pos][0], c_lo[:, 0])
467
+ iy0 = torch.maximum(lo[pos][1], c_lo[:, 1])
468
+ ix1 = torch.minimum(hi[pos][0], c_hi[:, 0])
469
+ iy1 = torch.minimum(hi[pos][1], c_hi[:, 1])
470
+ inter = (ix1 - ix0).clamp(min=0) * (iy1 - iy0).clamp(min=0)
471
+ nested = (inter / c_area.clamp(min=1e-6) >= contain) & (
472
+ c_area / areas[pos].clamp(min=1e-6) <= ratio
473
+ )
474
+ alive[pos + 1:] = candidate & ~nested
475
+
476
+ keep = torch.zeros(n, dtype=torch.bool, device=areas.device)
477
+ keep[order] = alive
478
  return polygons[keep], scores[keep]
479
 
480
 
 
481
  def decode_detection(predictions, basis, config, content_shape=None, scale=None):
482
  """Scores plus polygons to accepted boxes, mirroring the frozen decoder.
483
 
 
511
  flat = polygons.reshape(len(polygons), -1, 2)
512
  boxes = torch.cat((flat.amin(dim=1), flat.amax(dim=1)), dim=1)
513
  keep = nms(boxes, scores, config["nms_threshold"])
 
514
  polygons, scores = polygons[keep], scores[keep]
515
+ # Added post-processing, all geometry-only so it runs before recognition.
516
+ keep = _drop_degenerate(polygons, content_shape, config)
517
+ polygons, scores = polygons[keep], scores[keep]
518
+ if polygons.numel():
519
+ polygons, scores = _suppress_contained(
520
+ polygons, scores,
521
+ float(config.get("contain_threshold", 0.95)),
522
+ float(config.get("contain_area_ratio", 0.35)),
523
+ )
524
+ if content_shape is not None and polygons.numel():
525
+ # Clamp to the content area, not the padded canvas: a polygon
526
+ # that runs into the padding would otherwise be cropped with
527
+ # replicated border pixels.
528
+ content_h, content_w = content_shape
529
+ view = polygons.reshape(len(polygons), -1, 2)
530
+ view[..., 0].clamp_(0, content_w - 1)
531
+ view[..., 1].clamp_(0, content_h - 1)
532
  if scale is not None:
533
  polygons = polygons / torch.as_tensor(
534
  scale, dtype=polygons.dtype, device=polygons.device