refactor: Crop nach Deskew/Dewarp verschieben + content-basierter Buchscan-Crop
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 26s
CI / test-go-edu-search (push) Successful in 27s
CI / test-python-klausur (push) Failing after 1m56s
CI / test-python-agent-core (push) Successful in 16s
CI / test-nodejs-website (push) Successful in 17s

Pipeline-Reihenfolge neu: Orientierung → Begradigung → Entzerrung → Zuschneiden → Spalten...
Crop arbeitet jetzt auf dem bereits geraden Bild, was bessere Ergebnisse liefert.

page_crop.py komplett ersetzt: Adaptive Threshold + 4-Kanten-Erkennung
(Buchruecken-Schatten links, Ink-Projektion fuer alle Raender) statt
Otsu + groesste Kontur.

Backend: Step-Nummern, Input-Bilder, Reprocess-Kaskade angepasst.
Frontend: PIPELINE_STEPS umgeordnet, Switch-Cases, Vorher-Bilder aktualisiert.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-09 08:52:11 +01:00
parent eb45bb4879
commit 156a818246
7 changed files with 295 additions and 173 deletions

View File

@@ -71,8 +71,8 @@ export default function OcrPipelinePage() {
// Determine which step to jump to based on current_step
const dbStep = data.current_step || 1
// Steps: 1=deskew, 2=dewarp, 3=columns, ...
// UI steps are 0-indexed: 0=deskew, 1=dewarp, 2=columns, ...
// DB steps: 1=start, 2=orientation, 3=deskew, 4=dewarp, 5=crop, 6=columns, ...
// UI steps are 0-indexed: 0=orientation, 1=deskew, 2=dewarp, 3=crop, 4=columns, ...
const uiStep = Math.max(0, dbStep - 1)
const skipSteps = savedDocType?.skip_steps || []
@@ -205,8 +205,8 @@ export default function OcrPipelinePage() {
handleNext()
}
const handleDewarpNext = async () => {
// Auto-detect document type after dewarp, then advance
const handleCropNext = async () => {
// Auto-detect document type after crop (last image-processing step), then advance
if (sessionId) {
try {
const res = await fetch(
@@ -273,9 +273,9 @@ export default function OcrPipelinePage() {
const stepNames: Record<number, string> = {
1: 'Orientierung',
2: 'Zuschneiden',
3: 'Begradigung',
4: 'Entzerrung',
2: 'Begradigung',
3: 'Entzerrung',
4: 'Zuschneiden',
5: 'Spalten',
6: 'Zeilen',
7: 'Woerter',
@@ -312,11 +312,11 @@ export default function OcrPipelinePage() {
case 0:
return <StepOrientation sessionId={sessionId} onNext={handleOrientationComplete} />
case 1:
return <StepCrop sessionId={sessionId} onNext={handleNext} />
case 2:
return <StepDeskew sessionId={sessionId} onNext={handleNext} />
case 2:
return <StepDewarp sessionId={sessionId} onNext={handleNext} />
case 3:
return <StepDewarp sessionId={sessionId} onNext={handleDewarpNext} />
return <StepCrop sessionId={sessionId} onNext={handleCropNext} />
case 4:
return <StepColumnDetection sessionId={sessionId} onNext={handleNext} />
case 5:

View File

@@ -310,9 +310,9 @@ export const IMAGE_STYLES: { value: ImageStyle; label: string }[] = [
export const PIPELINE_STEPS: PipelineStep[] = [
{ id: 'orientation', name: 'Orientierung', icon: '🔄', status: 'pending' },
{ id: 'crop', name: 'Zuschneiden', icon: '✂️', status: 'pending' },
{ id: 'deskew', name: 'Begradigung', icon: '📐', status: 'pending' },
{ id: 'dewarp', name: 'Entzerrung', icon: '🔧', status: 'pending' },
{ id: 'crop', name: 'Zuschneiden', icon: '✂️', status: 'pending' },
{ id: 'columns', name: 'Spalten', icon: '📊', status: 'pending' },
{ id: 'rows', name: 'Zeilen', icon: '📏', status: 'pending' },
{ id: 'words', name: 'Woerter', icon: '🔤', status: 'pending' },

View File

@@ -78,7 +78,7 @@ export function StepCrop({ sessionId, onNext }: StepCropProps) {
return <div className="text-sm text-gray-400">Keine Session ausgewaehlt.</div>
}
const orientedUrl = `${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sessionId}/image/oriented`
const dewarpedUrl = `${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sessionId}/image/dewarped`
const croppedUrl = cropResult
? `${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sessionId}/image/cropped`
: null
@@ -95,12 +95,12 @@ export function StepCrop({ sessionId, onNext }: StepCropProps) {
{/* Image comparison */}
<ImageCompareView
originalUrl={orientedUrl}
originalUrl={dewarpedUrl}
deskewedUrl={croppedUrl}
showGrid={false}
showBinarized={false}
binarizedUrl={null}
leftLabel="Orientiert"
leftLabel="Entzerrt"
rightLabel="Zugeschnitten"
/>

View File

@@ -37,8 +37,8 @@ export function StepDeskew({ sessionId, onNext }: StepDeskewProps) {
filename: data.filename,
image_width: data.image_width,
image_height: data.image_height,
// Use cropped image as "before" view
original_image_url: `${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sessionId}/image/cropped`,
// Use oriented image as "before" view (deskew runs right after orientation)
original_image_url: `${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sessionId}/image/oriented`,
}
setSession(sessionInfo)
@@ -155,7 +155,7 @@ export function StepDeskew({ sessionId, onNext }: StepDeskewProps) {
showGrid={showGrid}
showBinarized={showBinarized}
binarizedUrl={deskewResult?.binarized_image_url ?? null}
leftLabel="Zugeschnitten"
leftLabel="Orientiert"
rightLabel="Begradigt"
/>
)}