# Field-photo-only classification

`classify_from_photos()` answers a field-realistic question: given only a photograph of a soil profile and a GPS fix, what is this soil? No augered samples, no laboratory sheet – just what a phone camera and a coordinate can provide. It is a screening tool, not a replacement for a described and sampled profile, and the result is graded accordingly.

# The pipeline

    profile photo  --VLM-->  Munsell colour per horizon
    field sheet    --VLM-->  site metadata (optional)
    GPS fix        --SoilGrids-->  depth-resolved clay / sand / silt / pH / OC / CEC
                             |
                             v
                  assembled PedonRecord
                             |
                             v
            WRB 2022  +  SiBCS 5  +  USDA ST 13

Three things never happen here: the taxonomic key is never delegated to the model; quantitative non-colour attributes are never read off a photograph (that is a hard prompt-level rule); and a SoilGrids prior never silently displaces a measured value – the `PedonRecord` authority order forbids it.

# A minimal run

    library(soilKey)

    res <- classify_from_photos(
      images   = list(profile = "perfil.jpg", fieldsheet = "ficha.jpg"),
      lat      = -22.74,
      lon      = -43.68,
      country  = "BR",
      provider = ellmer::chat_anthropic()   # any ellmer chat object
    )

    res$wrb$name            # e.g. "Rhodic Ferralsol (Clayic, ...)"
    res$wrb$evidence_grade  # "D" -- VLM-extracted; or "C" with a prior
    res$summary             # one row per system

`images` can also be a plain character vector of profile photos when there is no field sheet:

    res <- classify_from_photos("perfil.jpg", lat = -22.74, lon = -43.68,
                                provider = ellmer::chat_anthropic())

# The `provider` argument is required

There is deliberately no default provider. Passing a real classification back from canned data by accident would be worse than an error, so you must supply either a live ellmer chat object or a `MockVLMProvider` for testing:

    # Testing / offline: a mock provider returning a canned, schema-valid response
    mock <- MockVLMProvider$new(responses = list(my_canned_munsell_json))
    classify_from_photos("perfil.jpg", lat = -22.7, lon = -43.6, provider = mock)

# The SoilGrids depth prior

A Munsell colour alone rarely keys past the data-poor catch-all (Regosols / Neossolos / Entisols). `classify_from_photos()` therefore back-fills the missing horizon attributes from a SoilGrids depth prior, on by default. `apply_soilgrids_depth_prior()` does the work and can be called on its own:

    p <- make_cambisol_canonical()
    p$horizons$clay_pct <- NA_real_

    # Live: fetch the six SoilGrids 2.0 depth slices via the ISRIC REST API.
    apply_soilgrids_depth_prior(p)

    # Offline / reproducible: pass the six-slice profiles directly.
    apply_soilgrids_depth_prior(
      p,
      depth_profiles = list(clay_pct = c(18, 20, 24, 28, 30, 30)))

For each horizon the value is interpolated at the mid-depth from the 0-5 / 5-15 / 15-30 / 30-60 / 60-100 / 100-200 cm slices and recorded with `source = "inferred_prior"`. Skip it with `soilgrids = FALSE` if you only want the Munsell-driven result.

# Reading the evidence grade

Because every value came from a photograph or a prior, the classification’s evidence grade is low by construction – `D` where a VLM-extracted attribute was used, `C` where only a SoilGrids prior contributed. For a cell-by-cell view use `compute_per_attribute_evidence_grade()`:

    grades <- compute_per_attribute_evidence_grade(res$pedon)
    grades            # data.table(horizon_idx, attribute, grade)

The five-grade scale is: A measured, B spectra-predicted, C prior-inferred, D VLM-extracted, E user-assumed. A photo-only classification will never report grade A or B – and that is the point: the grade tells the user exactly how much trust the result has earned.

# When to use it

`classify_from_photos()` is built for reconnaissance: a quick, georeferenced, multi-system first guess from a field visit, to be confirmed later by description and sampling. The handful of horizons it can see, the colour it can estimate, and the regional prior it can fetch are genuinely informative – but the evidence grade is the honest headline, and it is never an A.