bugfixes
This commit is contained in:
parent
93b51978c5
commit
4484fb978d
BIN
backend/dist/nsfwapp-linux-amd64
vendored
BIN
backend/dist/nsfwapp-linux-amd64
vendored
Binary file not shown.
BIN
backend/dist/nsfwapp.exe
vendored
BIN
backend/dist/nsfwapp.exe
vendored
Binary file not shown.
BIN
backend/dist/nsfwapp_amd64.deb
vendored
BIN
backend/dist/nsfwapp_amd64.deb
vendored
Binary file not shown.
@ -4523,10 +4523,14 @@ export default function TrainingTab(props: {
|
||||
const poseFaceImagePanCenterRef = useRef<{ x: number; y: number } | null>(null)
|
||||
const poseFaceImagePanGestureRef = useRef<PoseFaceImagePanGesture | null>(null)
|
||||
const poseFaceImageDisplayCameraRef = useRef<PoseFaceImageCamera | null>(null)
|
||||
const poseFaceImageCameraRef = useRef<PoseFaceImageCamera | null>(null)
|
||||
const poseFaceImageCameraAnimationFrameRef = useRef<number | null>(null)
|
||||
const poseFaceImageZoomAnimationResolveRef = useRef<(() => void) | null>(null)
|
||||
const poseFaceImageZoomAppliedRef = useRef(false)
|
||||
const poseFaceImageZoomOutActiveRef = useRef(false)
|
||||
const correctionRef = useRef<CorrectionState>(correction)
|
||||
const hasManualCorrectionRef = useRef(hasManualCorrection)
|
||||
const saveFeedbackInFlightRef = useRef(false)
|
||||
const latestGestureBoxRef = useRef<TrainingBox | null>(null)
|
||||
const pendingPointerMoveRef = useRef<{ clientX: number; clientY: number } | null>(null)
|
||||
const pointerMoveRafRef = useRef<number | null>(null)
|
||||
@ -4634,8 +4638,14 @@ export default function TrainingTab(props: {
|
||||
cancelAnimationFrame(poseFaceImageCameraAnimationFrameRef.current)
|
||||
poseFaceImageCameraAnimationFrameRef.current = null
|
||||
}
|
||||
if (poseFaceImageZoomAnimationResolveRef.current !== null) {
|
||||
poseFaceImageZoomAnimationResolveRef.current()
|
||||
poseFaceImageZoomAnimationResolveRef.current = null
|
||||
}
|
||||
|
||||
poseFaceImageCameraRef.current = null
|
||||
poseFaceImageDisplayCameraRef.current = null
|
||||
poseFaceImageZoomAppliedRef.current = false
|
||||
poseFaceImageZoomOutActiveRef.current = false
|
||||
setPoseFaceImageDisplayCamera(null)
|
||||
setPoseFaceImageCameraAnimating(false)
|
||||
@ -4653,6 +4663,87 @@ export default function TrainingTab(props: {
|
||||
setPoseKeypointMapAnimating(false)
|
||||
}, [])
|
||||
|
||||
const zoomOutPoseFaceImageToFullImage = useCallback(() => {
|
||||
if (poseFaceImageZoomAnimationResolveRef.current !== null) {
|
||||
poseFaceImageZoomAnimationResolveRef.current()
|
||||
poseFaceImageZoomAnimationResolveRef.current = null
|
||||
}
|
||||
|
||||
if (poseFaceImageCameraAnimationFrameRef.current !== null) {
|
||||
cancelAnimationFrame(poseFaceImageCameraAnimationFrameRef.current)
|
||||
poseFaceImageCameraAnimationFrameRef.current = null
|
||||
}
|
||||
|
||||
const fromCamera =
|
||||
poseFaceImageDisplayCameraRef.current ??
|
||||
poseFaceImageCameraRef.current ??
|
||||
poseFaceImageFullCamera()
|
||||
const toCamera = poseFaceImageFullCamera()
|
||||
const shouldAnimate =
|
||||
poseFaceImageZoomAppliedRef.current ||
|
||||
poseFaceImageZoomOutActiveRef.current ||
|
||||
Math.abs(fromCamera.scale - toCamera.scale) > 0.001 ||
|
||||
Math.abs(fromCamera.translateX - toCamera.translateX) > 0.5 ||
|
||||
Math.abs(fromCamera.translateY - toCamera.translateY) > 0.5
|
||||
|
||||
switchPoseKeypointMapView('body')
|
||||
|
||||
if (!shouldAnimate) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
return new Promise<void>((resolve) => {
|
||||
let settled = false
|
||||
const settle = () => {
|
||||
if (settled) return
|
||||
settled = true
|
||||
if (poseFaceImageZoomAnimationResolveRef.current === settle) {
|
||||
poseFaceImageZoomAnimationResolveRef.current = null
|
||||
}
|
||||
resolve()
|
||||
}
|
||||
const finish = () => {
|
||||
poseFaceImageCameraAnimationFrameRef.current = null
|
||||
poseFaceImageDisplayCameraRef.current = null
|
||||
poseFaceImageZoomOutActiveRef.current = false
|
||||
poseFaceImageZoomAppliedRef.current = false
|
||||
setPoseFaceImageDisplayCamera(null)
|
||||
setPoseFaceImageCameraAnimating(false)
|
||||
setPoseFaceImageZoomOutActive(false)
|
||||
settle()
|
||||
}
|
||||
|
||||
poseFaceImagePanGestureRef.current = null
|
||||
poseFaceImagePanCenterRef.current = null
|
||||
setPoseFaceImagePanCenter(null)
|
||||
setPoseFaceImagePanning(false)
|
||||
poseFaceImageZoomAnimationResolveRef.current = settle
|
||||
poseFaceImageZoomOutActiveRef.current = true
|
||||
setPoseFaceImageZoomOutActive(true)
|
||||
setPoseFaceImageCameraAnimating(true)
|
||||
poseFaceImageDisplayCameraRef.current = fromCamera
|
||||
setPoseFaceImageDisplayCamera(fromCamera)
|
||||
|
||||
const startedAt = performance.now()
|
||||
const animateZoomOut = (now: number) => {
|
||||
const progress = Math.min(1, (now - startedAt) / POSE_FACE_IMAGE_ZOOM_DURATION_MS)
|
||||
const nextCamera = interpolatePoseFaceImageCamera(fromCamera, toCamera, progress)
|
||||
|
||||
poseFaceImageDisplayCameraRef.current = nextCamera
|
||||
setPoseFaceImageDisplayCamera(nextCamera)
|
||||
|
||||
if (progress < 1) {
|
||||
poseFaceImageCameraAnimationFrameRef.current = requestAnimationFrame(animateZoomOut)
|
||||
return
|
||||
}
|
||||
|
||||
finish()
|
||||
}
|
||||
|
||||
poseFaceImageCameraAnimationFrameRef.current = requestAnimationFrame(animateZoomOut)
|
||||
})
|
||||
}, [switchPoseKeypointMapView])
|
||||
|
||||
const labelsRef = useRef<TrainingLabels>(emptyLabels)
|
||||
|
||||
useEffect(() => {
|
||||
@ -4790,13 +4881,14 @@ export default function TrainingTab(props: {
|
||||
)
|
||||
const activePosePerson =
|
||||
activePosePersonIndex !== null ? posePersons[activePosePersonIndex] : undefined
|
||||
const activePosePersonVisible = Boolean(
|
||||
activePosePerson &&
|
||||
(hasVisiblePoseBox(activePosePerson) ||
|
||||
activePosePerson.keypoints?.some(isPoseKeypointVisible))
|
||||
const activePosePersonSelectable = Boolean(
|
||||
activePosePersonIndex !== null &&
|
||||
activePosePersonIndex >= 0 &&
|
||||
activePosePersonIndex < posePersons.length &&
|
||||
activePosePerson
|
||||
)
|
||||
const poseCorrectionPersonIndex =
|
||||
activePosePersonIndex !== null && activePosePersonVisible
|
||||
activePosePersonIndex !== null && activePosePersonSelectable
|
||||
? activePosePersonIndex
|
||||
: visiblePosePersonCount === 1
|
||||
? firstVisiblePosePersonIndex
|
||||
@ -7111,15 +7203,18 @@ export default function TrainingTab(props: {
|
||||
negative?: boolean
|
||||
}
|
||||
) => {
|
||||
if (!sample || trainingRunning) return
|
||||
if (!sample || trainingRunning || saveFeedbackInFlightRef.current) return
|
||||
|
||||
resetPoseUiToBoxes()
|
||||
setSavingOverlayText(editingFeedback ? 'Feedback wird aktualisiert…' : 'Feedback wird gespeichert…')
|
||||
setSaving(true)
|
||||
setError(null)
|
||||
setMessage(null)
|
||||
saveFeedbackInFlightRef.current = true
|
||||
|
||||
try {
|
||||
await zoomOutPoseFaceImageToFullImage()
|
||||
resetPoseUiToBoxes()
|
||||
setSavingOverlayText(editingFeedback ? 'Feedback wird aktualisiert…' : 'Feedback wird gespeichert…')
|
||||
setSaving(true)
|
||||
setError(null)
|
||||
setMessage(null)
|
||||
|
||||
const normalizedBoxes = (correction.boxes ?? [])
|
||||
.map(normalizeBox)
|
||||
.filter((box) => box.label && box.w > 0 && box.h > 0)
|
||||
@ -7262,6 +7357,7 @@ export default function TrainingTab(props: {
|
||||
|
||||
setError(`Feedback konnte nicht gespeichert werden. ${short}`)
|
||||
} finally {
|
||||
saveFeedbackInFlightRef.current = false
|
||||
setSaving(false)
|
||||
setSavingOverlayText('')
|
||||
}
|
||||
@ -7276,6 +7372,7 @@ export default function TrainingTab(props: {
|
||||
loadNextImportedQueuedSample,
|
||||
resetPoseUiToBoxes,
|
||||
trainingRunning,
|
||||
zoomOutPoseFaceImageToFullImage,
|
||||
]
|
||||
)
|
||||
|
||||
@ -8676,6 +8773,8 @@ export default function TrainingTab(props: {
|
||||
},
|
||||
}
|
||||
}, [imageBoxSize.height, imageBoxSize.width, imageLayerStyle, poseFaceImageEffectiveZoomRegion, poseFaceImageZoomActive])
|
||||
poseFaceImageCameraRef.current = poseFaceImageCamera
|
||||
|
||||
useEffect(() => {
|
||||
if (poseFaceImageZoomOutActiveRef.current) {
|
||||
return
|
||||
@ -8753,6 +8852,8 @@ export default function TrainingTab(props: {
|
||||
}
|
||||
}, [poseFaceImageRenderedCamera])
|
||||
const poseFaceImageZoomApplied = Boolean(poseFaceImageZoomStyle)
|
||||
poseFaceImageZoomAppliedRef.current = poseFaceImageZoomApplied
|
||||
|
||||
const setClampedPoseFaceImagePanCenter = useCallback((
|
||||
centerX: number,
|
||||
centerY: number,
|
||||
@ -8907,54 +9008,8 @@ export default function TrainingTab(props: {
|
||||
}, [setClampedPoseFaceImagePanCenter])
|
||||
|
||||
const zoomOutPoseFaceImageToBody = useCallback(() => {
|
||||
if (poseFaceImageCameraAnimationFrameRef.current !== null) {
|
||||
cancelAnimationFrame(poseFaceImageCameraAnimationFrameRef.current)
|
||||
poseFaceImageCameraAnimationFrameRef.current = null
|
||||
}
|
||||
|
||||
const fromCamera =
|
||||
poseFaceImageDisplayCameraRef.current ??
|
||||
poseFaceImageCamera ??
|
||||
poseFaceImageFullCamera()
|
||||
const toCamera = poseFaceImageFullCamera()
|
||||
const startedAt = performance.now()
|
||||
|
||||
poseFaceImagePanGestureRef.current = null
|
||||
poseFaceImagePanCenterRef.current = null
|
||||
setPoseFaceImagePanCenter(null)
|
||||
setPoseFaceImagePanning(false)
|
||||
poseFaceImageZoomOutActiveRef.current = true
|
||||
setPoseFaceImageZoomOutActive(true)
|
||||
setPoseFaceImageCameraAnimating(true)
|
||||
poseFaceImageDisplayCameraRef.current = fromCamera
|
||||
setPoseFaceImageDisplayCamera(fromCamera)
|
||||
|
||||
// Die rechte Map darf parallel zurueckfahren; die Bildkamera bleibt durch
|
||||
// den Override sichtbar, bis der Zoom-Out fertig ist.
|
||||
switchPoseKeypointMapView('body')
|
||||
|
||||
const animateZoomOut = (now: number) => {
|
||||
const progress = Math.min(1, (now - startedAt) / POSE_FACE_IMAGE_ZOOM_DURATION_MS)
|
||||
const nextCamera = interpolatePoseFaceImageCamera(fromCamera, toCamera, progress)
|
||||
|
||||
poseFaceImageDisplayCameraRef.current = nextCamera
|
||||
setPoseFaceImageDisplayCamera(nextCamera)
|
||||
|
||||
if (progress < 1) {
|
||||
poseFaceImageCameraAnimationFrameRef.current = requestAnimationFrame(animateZoomOut)
|
||||
return
|
||||
}
|
||||
|
||||
poseFaceImageCameraAnimationFrameRef.current = null
|
||||
poseFaceImageDisplayCameraRef.current = null
|
||||
poseFaceImageZoomOutActiveRef.current = false
|
||||
setPoseFaceImageDisplayCamera(null)
|
||||
setPoseFaceImageCameraAnimating(false)
|
||||
setPoseFaceImageZoomOutActive(false)
|
||||
}
|
||||
|
||||
poseFaceImageCameraAnimationFrameRef.current = requestAnimationFrame(animateZoomOut)
|
||||
}, [poseFaceImageCamera, switchPoseKeypointMapView])
|
||||
void zoomOutPoseFaceImageToFullImage()
|
||||
}, [zoomOutPoseFaceImageToFullImage])
|
||||
|
||||
const deletePosePerson = useCallback((personIndex: number) => {
|
||||
const shouldNavigateAfterDelete =
|
||||
@ -10426,7 +10481,7 @@ export default function TrainingTab(props: {
|
||||
.filter(isPoseKeypointVisible)
|
||||
.map((point) => poseKeypointId(point.name))
|
||||
)
|
||||
const disabled = uiLocked || frameBusy || trainingRunning || saving || !targetPerson
|
||||
const disabled = uiLocked || frameBusy || trainingRunning || saving || !poseTrainingAllowed
|
||||
const faceVisibleCount = POSE_FACE_KEYPOINT_SHAPES.filter((shape) =>
|
||||
visibleKeypointIds.has(shape.keypointName)
|
||||
).length
|
||||
@ -10459,10 +10514,29 @@ export default function TrainingTab(props: {
|
||||
const showMapParts = !poseKeypointMapAnimating
|
||||
|
||||
const selectPoseKeypoint = (keypointName: string) => {
|
||||
if (disabled || targetIndex === null) return
|
||||
if (disabled) return
|
||||
|
||||
let selectionPersonIndex = targetIndex
|
||||
|
||||
if (selectionPersonIndex === null || !targetPerson) {
|
||||
const persons = clonePosePersons(correctionRef.current.posePersons)
|
||||
selectionPersonIndex = persons.length
|
||||
const next: CorrectionState = {
|
||||
...correctionRef.current,
|
||||
posePersons: [...persons, createEmptyPosePerson()],
|
||||
}
|
||||
|
||||
markManualCorrection()
|
||||
correctionRef.current = next
|
||||
setCorrection(next)
|
||||
resetBoxDrawingMode()
|
||||
setShowPoseSkeleton(true)
|
||||
setActivePosePersonIndex(selectionPersonIndex)
|
||||
setMobilePanel('labels')
|
||||
}
|
||||
|
||||
const pending =
|
||||
pendingPoseKeypoint?.personIndex === targetIndex &&
|
||||
pendingPoseKeypoint?.personIndex === selectionPersonIndex &&
|
||||
pendingPoseKeypoint.keypointName === keypointName
|
||||
|
||||
if (pending) {
|
||||
@ -10472,10 +10546,10 @@ export default function TrainingTab(props: {
|
||||
}
|
||||
|
||||
setShowPoseSkeleton(true)
|
||||
setActivePosePersonIndex(targetIndex)
|
||||
setActivePosePersonIndex(selectionPersonIndex)
|
||||
setSelectedPoseKeypointAction(null)
|
||||
setPendingPoseKeypoint({
|
||||
personIndex: targetIndex,
|
||||
personIndex: selectionPersonIndex,
|
||||
keypointName,
|
||||
})
|
||||
}
|
||||
@ -10492,9 +10566,9 @@ export default function TrainingTab(props: {
|
||||
<div className="mt-0.5 text-[10px] text-gray-500 dark:text-gray-400">
|
||||
{targetPerson
|
||||
? `${targetPoseLabel}: Punkt wählen und im Bild setzen.`
|
||||
: visiblePosePersonCount > 1
|
||||
? 'Links erst eine Pose auswählen.'
|
||||
: 'Keine Pose vorhanden.'}
|
||||
: poseTrainingAllowed
|
||||
? 'Körperteil wählen, neue Pose wird angelegt.'
|
||||
: 'Für Unknown wird keine Pose trainiert.'}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -10530,7 +10604,7 @@ export default function TrainingTab(props: {
|
||||
height="1386"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
pointerEvents="none"
|
||||
className={targetPerson ? 'opacity-90' : 'opacity-35'}
|
||||
className={disabled ? 'opacity-35' : 'opacity-90'}
|
||||
/>
|
||||
|
||||
{showMapParts && poseKeypointMapView === 'head' ? (
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user