203 lines
5.9 KiB
Go
203 lines
5.9 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
|
|
"gocv.io/x/gocv"
|
|
)
|
|
|
|
// Global DEBUG flag
|
|
var DEBUG = false
|
|
|
|
func main() {
|
|
// Parse command line args
|
|
if len(os.Args) > 1 && os.Args[1] == "/debug" {
|
|
DEBUG = true
|
|
fmt.Println("DEBUG mode enabled\n")
|
|
}
|
|
|
|
// Hardcode RTSP URL
|
|
streamURL := "rtsp://tapohass:!!Helder06@192.168.2.183:554/stream1"
|
|
|
|
fmt.Println("Rotation Detection System")
|
|
fmt.Println("========================")
|
|
fmt.Println("Processing frames...\n")
|
|
|
|
// Open RTSP stream
|
|
stream, err := gocv.OpenVideoCapture(streamURL)
|
|
if err != nil {
|
|
log.Fatalf("Failed to open stream: %v", err)
|
|
}
|
|
defer stream.Close()
|
|
|
|
// Initialize detection state
|
|
rotation := 9999.0 // Sentinel value for "not detected"
|
|
width := 0 // 0 means "not detected"
|
|
|
|
// Frame processing counters
|
|
framesSkipped := 0
|
|
framesProcessed := 0
|
|
detectionAttempts := 0
|
|
totalFramesRead := 0
|
|
SKIP_COUNT := 7 // Process every 8th frame
|
|
MAX_DETECTION_ATTEMPTS := 100 // Give up after 100 attempts
|
|
RE_DETECT_AFTER := 0 // Re-detect after N frames (0 = disabled)
|
|
|
|
// Main processing loop
|
|
frame := gocv.NewMat()
|
|
defer frame.Close()
|
|
|
|
for {
|
|
// Acquire a frame
|
|
if ok := stream.Read(&frame); !ok || frame.Empty() {
|
|
log.Fatal("Failed to read frame from stream")
|
|
}
|
|
totalFramesRead++
|
|
|
|
// Preprocess frame to binary
|
|
binary := PreprocessFrame(frame)
|
|
|
|
// If rotation is 9999 or width is 0, detect bands/width/rotation
|
|
if rotation == 9999 || width == 0 {
|
|
detectionAttempts++
|
|
|
|
// Give up if too many attempts
|
|
if detectionAttempts > MAX_DETECTION_ATTEMPTS {
|
|
fmt.Printf("❌ Detection failed after %d attempts. Exiting.\n", MAX_DETECTION_ATTEMPTS)
|
|
break
|
|
}
|
|
|
|
result := DetectRotationAndWidth(binary)
|
|
if result.Success {
|
|
rotation = result.Rotation
|
|
width = result.Width
|
|
fmt.Printf("✓ DETECTION SUCCESSFUL (frame %d, attempt #%d): Width=%dpx, Rotation=%.3f°\n\n",
|
|
totalFramesRead, detectionAttempts, width, rotation)
|
|
detectionAttempts = 0 // Reset counter
|
|
} else {
|
|
// Show detection attempts with frame info
|
|
if detectionAttempts <= 5 {
|
|
if DEBUG {
|
|
fmt.Printf("Frame %d: Detection attempt #%d failed\n", totalFramesRead, detectionAttempts)
|
|
}
|
|
} else {
|
|
fmt.Printf("⚠ Frame %d: Detection attempt #%d failed - retrying...\n", totalFramesRead, detectionAttempts)
|
|
}
|
|
// Clean up and continue to next frame
|
|
binary.Close()
|
|
|
|
// Skip a few frames to ensure display has changed
|
|
for skip := 0; skip < 3; skip++ {
|
|
if ok := stream.Read(&frame); !ok {
|
|
break
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
|
|
// If rotation != 9999 and width != 0 and we've skipped enough frames
|
|
if rotation != 9999 && width != 0 && framesSkipped >= SKIP_COUNT {
|
|
framesProcessed++
|
|
|
|
// Rotate the image to correct orientation
|
|
rotated := RotateImage(binary, rotation)
|
|
defer rotated.Close()
|
|
|
|
// Calculate scale factor based on detected width
|
|
scaleFactor := 860.0 / float64(width)
|
|
|
|
// Scale to 860px width using the scale factor
|
|
scaled := ScaleByFactor(rotated, scaleFactor)
|
|
defer scaled.Close()
|
|
|
|
fmt.Printf("Frame #%d processed: Rotated %.3f°, Scaled from %dpx to 860px (factor: %.3f)\n",
|
|
framesProcessed, rotation, width, scaleFactor)
|
|
|
|
// Re-detect bands on the scaled image
|
|
// Scale the 80px minimum height by the same factor
|
|
scaledMinHeight := int(80.0 * scaleFactor)
|
|
bands := DetectBands(scaled, scaledMinHeight)
|
|
|
|
if DEBUG {
|
|
fmt.Printf(" Using scaled minimum height: %dpx (80px * %.3f)\n", scaledMinHeight, scaleFactor)
|
|
fmt.Printf(" Found %d bands on scaled image:\n", len(bands))
|
|
for i, band := range bands {
|
|
fmt.Printf(" Band #%d: Y range [%d-%d], Height: %dpx\n",
|
|
i+1, band.minY, band.maxY, band.maxY-band.minY)
|
|
}
|
|
}
|
|
|
|
// We should have exactly 2 bands: graph and digits
|
|
if len(bands) == 2 {
|
|
// First band should be graph (taller), second should be digits
|
|
graphBand := bands[0]
|
|
digitBand := bands[1]
|
|
|
|
// Verify graph band is taller
|
|
graphHeight := graphBand.maxY - graphBand.minY
|
|
digitHeight := digitBand.maxY - digitBand.minY
|
|
|
|
if graphHeight < digitHeight {
|
|
// Swap if needed
|
|
graphBand, digitBand = digitBand, graphBand
|
|
}
|
|
|
|
fmt.Printf(" ✓ Graph band: Y [%d-%d], Height: %dpx\n",
|
|
graphBand.minY, graphBand.maxY, graphBand.maxY-graphBand.minY)
|
|
fmt.Printf(" ✓ Digit band: Y [%d-%d], Height: %dpx\n",
|
|
digitBand.minY, digitBand.maxY, digitBand.maxY-digitBand.minY)
|
|
|
|
// Extract just the digit band region for OCR
|
|
digitRegion := ExtractBandRegion(scaled, digitBand)
|
|
defer digitRegion.Close()
|
|
|
|
// Save visualization if in DEBUG mode
|
|
if DEBUG && framesProcessed <= 5 {
|
|
// Simple visualization with just 2 bands
|
|
VisualizeSimpleBands(scaled, graphBand, digitBand,
|
|
fmt.Sprintf("debug_frame_%03d_bands.png", framesProcessed))
|
|
|
|
// Save just the digit region
|
|
digitFilename := fmt.Sprintf("debug_frame_%03d_digits.png", framesProcessed)
|
|
gocv.IMWrite(digitFilename, digitRegion)
|
|
fmt.Printf("DEBUG: Saved digit region to %s\n", digitFilename)
|
|
}
|
|
|
|
// TODO: Run OCR on digitRegion here
|
|
|
|
} else {
|
|
fmt.Printf(" ⚠ Expected 2 bands, found %d bands (>%dpx height)\n", len(bands), scaledMinHeight)
|
|
}
|
|
|
|
// Save debug images if in DEBUG mode
|
|
if DEBUG && framesProcessed <= 5 {
|
|
filename := fmt.Sprintf("debug_frame_%03d_scaled.png", framesProcessed)
|
|
gocv.IMWrite(filename, scaled)
|
|
fmt.Printf("DEBUG: Saved %s\n", filename)
|
|
}
|
|
|
|
// TODO: Add OCR processing on 'scaled' image here in later phase
|
|
|
|
framesSkipped = 0
|
|
|
|
// Optional: Force re-detection after N frames to adapt to changes
|
|
if RE_DETECT_AFTER > 0 && framesProcessed >= RE_DETECT_AFTER {
|
|
fmt.Printf("\n🔄 Re-detecting after %d frames...\n", RE_DETECT_AFTER)
|
|
rotation = 9999
|
|
width = 0
|
|
framesProcessed = 0
|
|
}
|
|
} else {
|
|
framesSkipped++
|
|
}
|
|
|
|
// Clean up
|
|
binary.Close()
|
|
}
|
|
|
|
fmt.Println("\nProgram terminated.")
|
|
}
|