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.
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.
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 systemimages can also be a plain character vector of profile
photos when there is no field sheet:
provider argument is requiredThere 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:
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.
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.
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.