feat: add measured detection review loop
This commit is contained in:
@@ -405,6 +405,7 @@ export function useDetectionWorkflow({
|
||||
analysisRunId: string,
|
||||
referenceDatasetId: string,
|
||||
useCurrentFilters = true,
|
||||
iouThresholdOverride?: number,
|
||||
): Promise<DetectionQaResult | null> => {
|
||||
if (!analysisRunId) {
|
||||
setDetectionQaError('Select a detection run')
|
||||
@@ -422,7 +423,7 @@ export function useDetectionWorkflow({
|
||||
try {
|
||||
const result = await detectionApi.compareWithReference(analysisRunId, {
|
||||
reference_dataset_id: referenceDatasetId,
|
||||
iou_threshold: qaIouThreshold,
|
||||
iou_threshold: iouThresholdOverride ?? qaIouThreshold,
|
||||
class_name: useCurrentFilters ? detectionClassFilter || null : null,
|
||||
min_confidence: useCurrentFilters && detectionMinConfidenceFilter > 0 ? detectionMinConfidenceFilter : null,
|
||||
})
|
||||
|
||||
@@ -17,6 +17,8 @@ export type MapOrthophotoAnalysisStage =
|
||||
| 'complete'
|
||||
| 'failed'
|
||||
|
||||
export const MAP_BUILDING_QA_IOU_THRESHOLD = 0.25
|
||||
|
||||
interface MapOrthophotoAnalysisOptions {
|
||||
selectedProjectId: string | null
|
||||
selectedAreaId: string
|
||||
@@ -27,6 +29,7 @@ interface MapOrthophotoAnalysisOptions {
|
||||
compareDetectionRunWithReference: (
|
||||
analysisRunId: string,
|
||||
referenceDatasetId: string,
|
||||
iouThreshold: number,
|
||||
) => Promise<DetectionQaResult | null>
|
||||
onAnalysisReady: () => void
|
||||
}
|
||||
@@ -61,6 +64,12 @@ function formatOrthophotoError(caught: unknown): string {
|
||||
return formatError(caught, 'De kaartgestuurde beeldanalyse is mislukt')
|
||||
}
|
||||
|
||||
function formatQualityPercentage(value: number | null | undefined): string {
|
||||
return typeof value === 'number' && Number.isFinite(value)
|
||||
? `${(value * 100).toLocaleString('nl-BE', { maximumFractionDigits: 1 })}%`
|
||||
: 'n.v.t.'
|
||||
}
|
||||
|
||||
export function useMapOrthophotoAnalysis({
|
||||
selectedProjectId,
|
||||
selectedAreaId,
|
||||
@@ -75,12 +84,18 @@ export function useMapOrthophotoAnalysis({
|
||||
const [status, setStatus] = useState('')
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [lastResult, setLastResult] = useState<OrthophotoAcquisitionResult | null>(null)
|
||||
const [lastQuality, setLastQuality] = useState<DetectionQaResult | null>(null)
|
||||
const [lastDetectionCount, setLastDetectionCount] = useState<number | null>(null)
|
||||
const [lastAnalysisRunId, setLastAnalysisRunId] = useState<string | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
setStage('idle')
|
||||
setStatus('')
|
||||
setError(null)
|
||||
setLastResult(null)
|
||||
setLastQuality(null)
|
||||
setLastDetectionCount(null)
|
||||
setLastAnalysisRunId(null)
|
||||
}, [selectionBbox?.min_x, selectionBbox?.min_y, selectionBbox?.max_x, selectionBbox?.max_y])
|
||||
|
||||
const run = async (bbox: VectorSelectionBBox): Promise<boolean> => {
|
||||
@@ -91,6 +106,9 @@ export function useMapOrthophotoAnalysis({
|
||||
}
|
||||
setError(null)
|
||||
setLastResult(null)
|
||||
setLastQuality(null)
|
||||
setLastDetectionCount(null)
|
||||
setLastAnalysisRunId(null)
|
||||
setStage('acquiring')
|
||||
setStatus('1/3 Officieel luchtbeeld voor de rechthoek ophalen...')
|
||||
try {
|
||||
@@ -112,20 +130,27 @@ export function useMapOrthophotoAnalysis({
|
||||
if (!detection) {
|
||||
throw new Error('De beeldanalyse stopte. Open Beeldanalyse voor de technische oorzaak.')
|
||||
}
|
||||
setLastDetectionCount(detection.detection_count)
|
||||
setLastAnalysisRunId(detection.analysis_run_id)
|
||||
|
||||
const reference = findBuildingReference(datasets)
|
||||
if (reference) {
|
||||
setStage('validating')
|
||||
setStatus('3/3 Resultaat vergelijken met officiële GRB-gebouwen...')
|
||||
const quality = await compareDetectionRunWithReference(detection.analysis_run_id, reference.id)
|
||||
const quality = await compareDetectionRunWithReference(
|
||||
detection.analysis_run_id,
|
||||
reference.id,
|
||||
MAP_BUILDING_QA_IOU_THRESHOLD,
|
||||
)
|
||||
setLastQuality(quality)
|
||||
setStatus(
|
||||
quality
|
||||
? `Analyse klaar: ${detection.detection_count.toLocaleString('nl-BE')} gebouwen herkend en gecontroleerd.`
|
||||
: `Analyse klaar: ${detection.detection_count.toLocaleString('nl-BE')} gebouwen herkend; kwaliteitscontrole kon niet afronden.`,
|
||||
? `Analyse klaar: ${detection.detection_count.toLocaleString('nl-BE')} kandidaten, ${quality.matches.toLocaleString('nl-BE')} gekoppeld aan GRB. Precision ${formatQualityPercentage(quality.precision)}, recall ${formatQualityPercentage(quality.recall)}.`
|
||||
: `Analyse klaar: ${detection.detection_count.toLocaleString('nl-BE')} kandidaten; kwaliteitscontrole kon niet afronden.`,
|
||||
)
|
||||
} else {
|
||||
setStatus(
|
||||
`Analyse klaar: ${detection.detection_count.toLocaleString('nl-BE')} gebouwen herkend. De GRB-referentielaag ontbreekt voor automatische controle.`,
|
||||
`Analyse klaar: ${detection.detection_count.toLocaleString('nl-BE')} kandidaatvormen. De GRB-referentielaag ontbreekt voor automatische controle.`,
|
||||
)
|
||||
}
|
||||
setStage('complete')
|
||||
@@ -144,6 +169,9 @@ export function useMapOrthophotoAnalysis({
|
||||
status,
|
||||
error,
|
||||
lastResult,
|
||||
lastQuality,
|
||||
lastDetectionCount,
|
||||
lastAnalysisRunId,
|
||||
running: stage === 'acquiring' || stage === 'detecting' || stage === 'validating',
|
||||
run,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user