feat: add map-driven orthophoto analysis
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-15 02:01:03 +02:00
parent 845c4696e7
commit daccd3869a
29 changed files with 1300 additions and 26 deletions
+56 -25
View File
@@ -229,12 +229,18 @@ export function useDetectionWorkflow({
}
}
const executeDetection = async (projectId: string, datasetId: string, manifestPath: string | null) => {
const executeDetection = async (
projectId: string,
datasetId: string,
manifestPath: string | null,
modelId = selectedDetectionModelId,
modelAssetId = selectedModelAssetId,
) => {
const result = await detectionApi.run({
project_id: projectId,
dataset_id: datasetId,
model_id: selectedDetectionModelId,
model_asset_id: selectedModelAssetId || null,
model_id: modelId,
model_asset_id: modelAssetId || null,
confidence_threshold: detectionConfidenceThreshold,
tile_manifest_path: manifestPath,
parameters_json: {},
@@ -303,24 +309,31 @@ export function useDetectionWorkflow({
}
}
const prepareAndRunDetection = async (): Promise<boolean> => {
const prepareAndRunDetection = async (
datasetIdOverride?: string,
modelIdOverride?: string,
): Promise<DetectionRunResponse | null> => {
if (!selectedProjectId) {
setDetectionRunError('De regionale werkruimte is nog niet geladen')
return false
return null
}
const datasetId = selectedDetectionDatasetId || rasterDatasets[0]?.id
const datasetId = datasetIdOverride || selectedDetectionDatasetId || rasterDatasets[0]?.id
if (!datasetId) {
setDetectionRunError('Kies of voeg eerst een gegeorefereerd luchtbeeld toe')
return false
return null
}
const selectedModel = detectionModels.find((model) => model.model_id === selectedDetectionModelId)
if (!selectedModel?.configured || selectedDetectionModelId === 'manual-fixture-detector') {
const effectiveModelId = modelIdOverride || selectedDetectionModelId
const effectiveModelAssetId = effectiveModelId === 'yolo-configured'
? modelAssets.find((asset) => asset.active)?.model_asset_id ?? selectedModelAssetId
: selectedModelAssetId
const selectedModel = detectionModels.find((model) => model.model_id === effectiveModelId)
if (!selectedModel?.configured || effectiveModelId === 'manual-fixture-detector') {
setDetectionRunError(selectedModel?.limitation_message ?? 'Het gekozen analysemodel is niet beschikbaar')
return false
return null
}
if (selectedDetectionModelId === 'yolo-configured' && modelAssets.length > 0 && !selectedModelAssetId) {
if (effectiveModelId === 'yolo-configured' && modelAssets.length > 0 && !effectiveModelAssetId) {
setDetectionRunError('Kies eerst een lokaal modelbestand')
return false
return null
}
setDetectionRunError(null)
@@ -355,7 +368,7 @@ export function useDetectionWorkflow({
setDetectionWorkflowStage('validating')
const preflight = await detectionApi.getYoloPreflight({
tile_manifest_path: manifestPath,
model_asset_id: selectedModelAssetId || null,
model_asset_id: effectiveModelAssetId || null,
})
setYoloPreflight(preflight)
setYoloPreflightError(null)
@@ -370,46 +383,63 @@ export function useDetectionWorkflow({
}
setDetectionWorkflowStage('detecting')
await executeDetection(selectedProjectId, datasetId, manifestPath)
const result = await executeDetection(
selectedProjectId,
datasetId,
manifestPath,
effectiveModelId,
effectiveModelAssetId,
)
setDetectionWorkflowStage('complete')
return true
return result
} catch (error) {
setDetectionRunError(formatError(error, 'De beeldanalyse is mislukt'))
setDetectionWorkflowStage('failed')
return false
return null
} finally {
setRunningDetection(false)
}
}
const runDetectionQa = async () => {
if (!selectedDetectionRunId) {
const compareDetectionRunWithReference = async (
analysisRunId: string,
referenceDatasetId: string,
useCurrentFilters = true,
): Promise<DetectionQaResult | null> => {
if (!analysisRunId) {
setDetectionQaError('Select a detection run')
return
return null
}
if (!detectionReferenceDatasetId) {
if (!referenceDatasetId) {
setDetectionQaError('Select a reference dataset')
return
return null
}
setSelectedDetectionRunId(analysisRunId)
setDetectionReferenceDatasetId(referenceDatasetId)
setDetectionQaError(null)
setDetectionQaResult(null)
setRunningDetectionQa(true)
try {
const result = await detectionApi.compareWithReference(selectedDetectionRunId, {
reference_dataset_id: detectionReferenceDatasetId,
const result = await detectionApi.compareWithReference(analysisRunId, {
reference_dataset_id: referenceDatasetId,
iou_threshold: qaIouThreshold,
class_name: detectionClassFilter || null,
min_confidence: detectionMinConfidenceFilter > 0 ? detectionMinConfidenceFilter : null,
class_name: useCurrentFilters ? detectionClassFilter || null : null,
min_confidence: useCurrentFilters && detectionMinConfidenceFilter > 0 ? detectionMinConfidenceFilter : null,
})
setDetectionQaResult(result)
await loadQualityChecks(selectedProjectId)
return result
} catch (error) {
setDetectionQaError(formatError(error, 'Detection QA failed'))
return null
} finally {
setRunningDetectionQa(false)
}
}
const runDetectionQa = async (): Promise<DetectionQaResult | null> =>
compareDetectionRunWithReference(selectedDetectionRunId, detectionReferenceDatasetId)
const runDetectionCalibration = async () => {
if (!selectedProjectId) {
setDetectionCalibrationError('Select a project before calibration')
@@ -560,6 +590,7 @@ export function useDetectionWorkflow({
runDetection,
uploadDetectionRaster,
prepareAndRunDetection,
compareDetectionRunWithReference,
runDetectionQa,
runDetectionCalibration,
applyDetectionOperatorProfile,