File size: 907 Bytes
7a3a384
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
"""SAM 3 as the segmenter: lawn = union(lawn prompts) ∪ canopy; canopy = union(canopy
prompts). Returns the same `(lawn_mask, canopy_mask)` contract as
`segmentation.run_lawn_and_canopy`, so it drops straight into the decide-lawn block.

Canopy is folded into the lawn mask because LiDAR sees the ground under trees (same
rationale as the incumbent's class-1 ∪ class-4 union)."""

from __future__ import annotations

import numpy as np
from PIL import Image

from tuning.tools import sam3_common


def lawn_and_canopy(image: Image.Image, recipe) -> tuple[np.ndarray, np.ndarray]:
    canopy = sam3_common.concept_mask(
        image, recipe.sam3_canopy_prompts,
        recipe.sam3_score_threshold, recipe.sam3_mask_threshold)
    lawn = sam3_common.concept_mask(
        image, recipe.sam3_lawn_prompts,
        recipe.sam3_score_threshold, recipe.sam3_mask_threshold)
    return lawn | canopy, canopy