Skip to content

ADFA-3290 | Implement smart boundary detection for dynamic margins#1171

Open
jatezzz wants to merge 2 commits intostagefrom
feat/ADFA-3290-smart-boundary-detection-experimental
Open

ADFA-3290 | Implement smart boundary detection for dynamic margins#1171
jatezzz wants to merge 2 commits intostagefrom
feat/ADFA-3290-smart-boundary-detection-experimental

Conversation

@jatezzz
Copy link
Copy Markdown
Collaborator

@jatezzz jatezzz commented Apr 9, 2026

Description

This PR replaces the hardcoded margin boundaries (0.2f and 0.8f) with a smart algorithm that calculates their optimal positions dynamically. It introduces the SmartBoundaryDetector and a new calculateVerticalProjection utility in BitmapUtils to analyze image content and snap guidelines to the best available vertical gaps.

Details

  • Extracted pixel analysis logic into BitmapUtils.calculateVerticalProjection.
  • Created SmartBoundaryDetector to find gap midpoints using the projection data.
  • Updated ComputerVisionViewModel.loadImageFromUri to apply the dynamically calculated left and right percentage bounds instead of resetting to default hardcoded values.
document_5098099422705747202.mp4

Ticket

ADFA-3290

Observation

The edge detection approach in calculateVerticalProjection uses a simplified, highly performant Sobel-like technique by directly calculating pixel variations on the red channel, avoiding heavy matrix operations on the main thread.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 9, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 87f9beaf-7333-4bea-830d-91c6f8bff35e

📥 Commits

Reviewing files that changed from the base of the PR and between c689644 and cb36d75.

📒 Files selected for processing (3)
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/viewmodel/ComputerVisionViewModel.kt
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/BitmapUtils.kt
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/SmartBoundaryDetector.kt
🚧 Files skipped from review as they are similar to previous changes (3)
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/BitmapUtils.kt
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/viewmodel/ComputerVisionViewModel.kt
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/SmartBoundaryDetector.kt

📝 Walkthrough
  • Features

    • Dynamic margin calculation: replaces hardcoded left/right guide boundaries (0.2f / 0.8f) with content-driven boundaries computed from each image.
    • Vertical-projection edge detection: adds BitmapUtils.calculateVerticalProjection(bitmap) which builds a per-column edge activity profile using a simplified, high-performance red-channel difference detector.
    • Smart gap detection: adds SmartBoundaryDetector.detectSmartBoundaries(bitmap, edgeIgnorePercent) to locate left/right content boundaries by finding widest low-activity gaps in the projection with primary and fallback threshold passes.
    • Off-main-thread processing: image decode/rotation and guide computation run inside withContext(Dispatchers.Default) when loading images.
  • Code changes

    • ComputerVisionViewModel.loadImageFromUri(): applies computed left/right percentage bounds from SmartBoundaryDetector instead of resetting to fixed defaults.
    • BitmapUtils.kt: new calculateVerticalProjection(bitmap: Bitmap) and EDGE_DETECTION_THRESHOLD = 30.
    • SmartBoundaryDetector.kt: new singleton implementing gap-based boundary detection with configurable edge-ignore percent and multi-tier fallback logic.
  • Risks / Best-practice violations

    • Memory usage: calculateVerticalProjection allocates full bitmap pixel arrays (IntArray width*height) and intermediate FloatArray copies (e.g., during normalization), which can create large temporary allocations (notable for 4K images) and pressure low-memory devices.
    • No tests: no unit tests observed for projection or SmartBoundaryDetector logic; threshold behavior, fallback paths, and edge cases are not validated.
    • Hardcoded thresholds and fallbacks: EDGE_DETECTION_THRESHOLD (30), primary/fallback activity thresholds and fixed fallback bounds (e.g., ~0.15/0.85) are hardcoded and not parameterized per image/document type.
    • Algorithm robustness: simplified red-channel-only edge detection may miss edges in multi-channel content; minimum gap-width and threshold choices may fail on atypical layouts or noisy images.
    • Performance transparency: no benchmarks or measured accuracy/performance data provided; cancellation handling while computing projections is not documented (synchronous computation inside coroutines).
    • Error handling & logging: projection returns empty arrays for invalid dimensions silently; limited input validation and no explicit exception handling for corrupted or extreme-aspect bitmaps.
    • Documentation: lack of KDoc/comments explaining rationale, threshold semantics, and fallback behavior reduces maintainability and makes tuning harder.
  • Recommendations (concise)

    • Add unit tests covering typical/edge-case images and threshold behavior.
    • Make key thresholds/configs (edge threshold, activity thresholds, fallback percentages, min gap width) configurable or tunable via parameters.
    • Avoid full-pixel IntArray allocations for very large images (downsample before analysis) and document memory/CPU trade-offs; add basic benchmarking.
    • Add cancellation/cooperative checks during heavy computation and improve logging for failure modes.

Walkthrough

Image analysis moved off the main thread and now computes smart left/right guides by adding a vertical projection utility and a SmartBoundaryDetector; the ViewModel uses the detector on the rotated bitmap and converts detected pixel bounds into guide percentages, replacing fixed default guides.

Changes

Cohort / File(s) Summary
Bitmap utilities
cv-image-to-xml/src/main/java/.../utils/BitmapUtils.kt
Added calculateVerticalProjection(bitmap: Bitmap): FloatArray and an EDGE_DETECTION_THRESHOLD constant to compute per-x edge activity from red-channel differences.
Smart boundary detection
cv-image-to-xml/src/main/java/.../utils/SmartBoundaryDetector.kt
Added SmartBoundaryDetector with detectSmartBoundaries(bitmap, edgeIgnorePercent) that analyzes vertical projections, searches for gap midpoints per side with thresholds and fallbacks, and returns pixel-based left/right bounds.
ViewModel integration
cv-image-to-xml/src/main/java/.../ui/viewmodel/ComputerVisionViewModel.kt
Decoding/rotation and guide computation moved into withContext(Dispatchers.Default); calls detector on rotated bitmap, converts returned pixel bounds to percentages for leftGuidePct/rightGuidePct, and simplifies null/decode failure handling.

Sequence Diagram

sequenceDiagram
    actor User
    participant ViewModel as ComputerVisionViewModel
    participant Default as Dispatchers.Default
    participant Detector as SmartBoundaryDetector
    participant Utils as BitmapUtils
    participant Bitmap as Bitmap

    User->>ViewModel: selectImage()
    ViewModel->>Default: withContext(Dispatchers.Default) - decode & rotate
    Default->>Bitmap: decode / apply rotation
    Bitmap-->>Default: rotatedBitmap
    Default->>Detector: detectSmartBoundaries(rotatedBitmap)
    Detector->>Utils: calculateVerticalProjection(rotatedBitmap)
    Utils->>Bitmap: readPixels()
    Bitmap-->>Utils: pixel data
    Utils->>Utils: compute vertical edge projection
    Utils-->>Detector: FloatArray projection
    Detector->>Detector: analyze left/right zones, find gap midpoints
    Detector-->>Default: Pair(leftPixel, rightPixel)
    Default->>ViewModel: convert to percentages & update guides
    ViewModel->>ViewModel: emit UI state
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested reviewers

  • itsaky-adfa
  • Daniel-ADFA

Poem

🐰
I sniff the pixels, hop and peep,
I count the edges, while others sleep.
I find the gaps, left and right,
Guide the crop with gentle light.
Hooray — smart bounds, snug and neat!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: implementing smart boundary detection to replace hardcoded margin values with dynamic calculations.
Description check ✅ Passed The description is directly related to the changeset, detailing the introduction of SmartBoundaryDetector and calculateVerticalProjection utility, and their integration into ComputerVisionViewModel.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ADFA-3290-smart-boundary-detection-experimental

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/SmartBoundaryDetector.kt (1)

11-11: Minor type inconsistency.

MIN_GAP_WIDTH_PERCENT is declared as Double (0.02) while other percentage constants are Float (e.g., 0.05f). Consider using 0.02f for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/SmartBoundaryDetector.kt`
at line 11, MIN_GAP_WIDTH_PERCENT is declared with a Double literal (0.02) while
other percentage constants use Float; change the literal to 0.02f so
MIN_GAP_WIDTH_PERCENT is a Float consistent with the other constants in
SmartBoundaryDetector.kt (update the constant declaration for
MIN_GAP_WIDTH_PERCENT to use the f-suffix).
cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/viewmodel/ComputerVisionViewModel.kt (1)

116-120: Consider validating that leftPct < rightPct and values are in valid range.

While SmartBoundaryDetector is designed to return sensible bounds, there's no explicit validation that leftPct < rightPct or that values fall within [0, 1]. The downstream GuidelinesView.updateGuidelines() (per the relevant code snippet) has no bounds checks either.

For robustness, consider adding a sanity check:

🛡️ Proposed validation
                     val widthFloat = rotatedBitmap.width.toFloat()
-                    val leftPct = leftBoundPx / widthFloat
-                    val rightPct = rightBoundPx / widthFloat
+                    val rawLeftPct = (leftBoundPx / widthFloat).coerceIn(0f, 1f)
+                    val rawRightPct = (rightBoundPx / widthFloat).coerceIn(0f, 1f)
+                    val leftPct = minOf(rawLeftPct, rawRightPct)
+                    val rightPct = maxOf(rawLeftPct, rawRightPct)
 
                     Triple(rotatedBitmap, leftPct, rightPct)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/viewmodel/ComputerVisionViewModel.kt`
around lines 116 - 120, Validate and sanitize the bounds returned by
SmartBoundaryDetector.detectSmartBoundaries before calling
GuidelinesView.updateGuidelines: compute leftPct/rightPct from rotatedBitmap as
shown, then ensure they are within [0.0, 1.0] (clamp) and that leftPct <
rightPct (swap or adjust if not), and log a warning when you modify values; pass
the sanitized leftPct/rightPct to GuidelinesView.updateGuidelines to guarantee
valid input.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/SmartBoundaryDetector.kt`:
- Around line 75-92: The loop in SmartBoundaryDetector misses leading gaps
because currentGapStart is only set on transitions from active to inactive; to
fix, initialize gap detection for leading inactive samples before iterating
(e.g., if signal is not empty and signal[0] <= threshold set currentGapStart =
0) or add a check inside the loop to set currentGapStart when index == 0 and
!isActive; keep the existing gap-closing logic (currentGapStart, maxGapLength,
maxGapMidpoint) unchanged so leading gaps are measured and recorded
consistently.
- Around line 25-36: Guard against invalid ranges before calling
projection.copyOfRange: check that ignoredEdgePixels < leftZoneEnd before
building leftSignal and that rightZoneStart < rightZoneEnd before building
rightSignal; if a range would be empty or invalid (e.g., due to small image or
large edgeIgnorePercent/LEFT_ZONE_END_PERCENT/RIGHT_ZONE_START_PERCENT), either
adjust the start/end to valid bounds or skip creating the signal and handle the
fallback (call findBestGapMidpoint with an empty/normalized signal or return
nulls) so projection.copyOfRange cannot throw; update the logic around
ignoredEdgePixels, leftZoneEnd, rightZoneStart, rightZoneEnd, leftSignal,
rightSignal and subsequent findBestGapMidpoint/leftBound/rightBound handling to
safely handle these edge cases.

---

Nitpick comments:
In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/viewmodel/ComputerVisionViewModel.kt`:
- Around line 116-120: Validate and sanitize the bounds returned by
SmartBoundaryDetector.detectSmartBoundaries before calling
GuidelinesView.updateGuidelines: compute leftPct/rightPct from rotatedBitmap as
shown, then ensure they are within [0.0, 1.0] (clamp) and that leftPct <
rightPct (swap or adjust if not), and log a warning when you modify values; pass
the sanitized leftPct/rightPct to GuidelinesView.updateGuidelines to guarantee
valid input.

In
`@cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/SmartBoundaryDetector.kt`:
- Line 11: MIN_GAP_WIDTH_PERCENT is declared with a Double literal (0.02) while
other percentage constants use Float; change the literal to 0.02f so
MIN_GAP_WIDTH_PERCENT is a Float consistent with the other constants in
SmartBoundaryDetector.kt (update the constant declaration for
MIN_GAP_WIDTH_PERCENT to use the f-suffix).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b6c44ef6-e502-44d4-9810-d8bdf0693a3f

📥 Commits

Reviewing files that changed from the base of the PR and between 0975600 and c689644.

📒 Files selected for processing (3)
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/ui/viewmodel/ComputerVisionViewModel.kt
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/BitmapUtils.kt
  • cv-image-to-xml/src/main/java/org/appdevforall/codeonthego/computervision/utils/SmartBoundaryDetector.kt

jatezzz added 2 commits April 10, 2026 09:00
Replaces hardcoded bounds with a vertical projection edge-detection algorithm.
@jatezzz jatezzz force-pushed the feat/ADFA-3290-smart-boundary-detection-experimental branch from c689644 to cb36d75 Compare April 10, 2026 14:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants