flickering issue
This commit is contained in:
@@ -422,6 +422,7 @@ export default function VideoPlayerSection({ data, videoId, videoFile, detection
|
|||||||
const loggedFrames = useRef<Set<number>>(new Set())
|
const loggedFrames = useRef<Set<number>>(new Set())
|
||||||
const cumulativeCountsMap = useRef<Map<number, Record<string, number>>>(new Map())
|
const cumulativeCountsMap = useRef<Map<number, Record<string, number>>>(new Map())
|
||||||
const sortedFrameIndices = useRef<number[]>([])
|
const sortedFrameIndices = useRef<number[]>([])
|
||||||
|
const detectedFrameSkip = useRef<number>(3) // Computed from data, fallback to 3
|
||||||
const MAX_LOGS = 50
|
const MAX_LOGS = 50
|
||||||
|
|
||||||
const isCombined = detectionType === "pot-sign-detection"
|
const isCombined = detectionType === "pot-sign-detection"
|
||||||
@@ -586,6 +587,18 @@ export default function VideoPlayerSection({ data, videoId, videoFile, detection
|
|||||||
map.set(frameId, { ...lastCounts })
|
map.set(frameId, { ...lastCounts })
|
||||||
})
|
})
|
||||||
sortedFrameIndices.current = indices
|
sortedFrameIndices.current = indices
|
||||||
|
|
||||||
|
// Compute the frame skip gap from the data (minimum gap between consecutive detection frames)
|
||||||
|
// This tells us how far apart processed frames are, so we only carry forward within that gap
|
||||||
|
if (indices.length >= 2) {
|
||||||
|
let minGap = Infinity
|
||||||
|
for (let i = 1; i < indices.length; i++) {
|
||||||
|
const gap = indices[i] - indices[i - 1]
|
||||||
|
if (gap > 0 && gap < minGap) minGap = gap
|
||||||
|
}
|
||||||
|
detectedFrameSkip.current = minGap === Infinity ? 3 : minGap
|
||||||
|
console.log(`[VideoPlayer] Detected frame skip gap: ${detectedFrameSkip.current}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cumulativeCountsMap.current = map
|
cumulativeCountsMap.current = map
|
||||||
@@ -629,6 +642,43 @@ export default function VideoPlayerSection({ data, videoId, videoFile, detection
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// Helper to get nearest detections for any frame (handles frame skipping)
|
||||||
|
// Uses binary search to find the closest processed frame <= current frame,
|
||||||
|
// but only carries forward within the frame-skip gap to avoid stale bounding boxes
|
||||||
|
const getNearestDetections = useCallback((frame: number): any[] | undefined => {
|
||||||
|
// First try exact match (fastest path)
|
||||||
|
const exact = frameDetectionMap.current.get(frame)
|
||||||
|
if (exact) return exact
|
||||||
|
|
||||||
|
// Binary search for the nearest processed frame <= current frame
|
||||||
|
const indices = sortedFrameIndices.current
|
||||||
|
if (indices.length === 0) return undefined
|
||||||
|
|
||||||
|
let low = 0, high = indices.length - 1
|
||||||
|
let targetIndex = -1
|
||||||
|
|
||||||
|
while (low <= high) {
|
||||||
|
const mid = Math.floor((low + high) / 2)
|
||||||
|
if (indices[mid] <= frame) {
|
||||||
|
targetIndex = indices[mid]
|
||||||
|
low = mid + 1
|
||||||
|
} else {
|
||||||
|
high = mid - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetIndex !== -1) {
|
||||||
|
// Only carry forward if we're within the frame-skip gap
|
||||||
|
// This prevents bounding boxes from persisting after the detection has ended
|
||||||
|
const gap = frame - targetIndex
|
||||||
|
if (gap <= detectedFrameSkip.current) {
|
||||||
|
return frameDetectionMap.current.get(targetIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}, [])
|
||||||
|
|
||||||
// Function to draw bounding boxes on canvas
|
// Function to draw bounding boxes on canvas
|
||||||
const drawBoundingBoxes = useCallback((detections: any[]) => {
|
const drawBoundingBoxes = useCallback((detections: any[]) => {
|
||||||
const canvas = canvasRef.current
|
const canvas = canvasRef.current
|
||||||
@@ -719,13 +769,13 @@ export default function VideoPlayerSection({ data, videoId, videoFile, detection
|
|||||||
canvas.width = rect.width
|
canvas.width = rect.width
|
||||||
canvas.height = rect.height
|
canvas.height = rect.height
|
||||||
|
|
||||||
// Redraw current frame's detections
|
// Redraw current frame's detections (using nearest frame for skipped frames)
|
||||||
const frame = Math.round(video.currentTime * data.video_info.fps)
|
const frame = Math.round(video.currentTime * data.video_info.fps)
|
||||||
const detections = frameDetectionMap.current.get(frame)
|
const detections = getNearestDetections(frame)
|
||||||
if (detections) {
|
if (detections) {
|
||||||
drawBoundingBoxes(detections)
|
drawBoundingBoxes(detections)
|
||||||
}
|
}
|
||||||
}, [data.video_info.fps, drawBoundingBoxes])
|
}, [data.video_info.fps, drawBoundingBoxes, getNearestDetections])
|
||||||
|
|
||||||
// Handle window resize
|
// Handle window resize
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -847,10 +897,11 @@ export default function VideoPlayerSection({ data, videoId, videoFile, detection
|
|||||||
lastProcessedFrame.current = frame
|
lastProcessedFrame.current = frame
|
||||||
setCurrentFrame(frame)
|
setCurrentFrame(frame)
|
||||||
|
|
||||||
const detections = frameDetectionMap.current.get(frame)
|
// Use nearest processed frame's detections to avoid flickering from frame skipping
|
||||||
|
const detections = getNearestDetections(frame)
|
||||||
setDetectionsCount(detections?.length || 0)
|
setDetectionsCount(detections?.length || 0)
|
||||||
|
|
||||||
// Draw bounding boxes for current frame
|
// Draw bounding boxes for current frame (carried forward from nearest processed frame)
|
||||||
drawBoundingBoxes(detections || [])
|
drawBoundingBoxes(detections || [])
|
||||||
|
|
||||||
// Update counts using sticky logic
|
// Update counts using sticky logic
|
||||||
@@ -860,7 +911,7 @@ export default function VideoPlayerSection({ data, videoId, videoFile, detection
|
|||||||
addDetectionLog(frame, detections)
|
addDetectionLog(frame, detections)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [data.video_info.fps, addDetectionLog, drawBoundingBoxes])
|
}, [data.video_info.fps, addDetectionLog, drawBoundingBoxes, getNearestDetections])
|
||||||
|
|
||||||
// Video playback monitoring
|
// Video playback monitoring
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user