Created
September 26, 2025 07:48
-
-
Save slowmove/69ee602f34eafc1087cdcbd38cebbbac to your computer and use it in GitHub Desktop.
detect_and_crop_letterbox_enhanced
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Check if input file is provided | |
| if [ $# -lt 1 ]; then | |
| echo "Usage: $0 input_video [output_video] [time_position]" | |
| echo " time_position: Optional time to extract frame (default: 00:00:01)" | |
| exit 1 | |
| fi | |
| INPUT_VIDEO="$1" | |
| OUTPUT_VIDEO="${2:-${INPUT_VIDEO%.*}_cropped.${INPUT_VIDEO##*.}}" | |
| TIME_POSITION="${3:-00:00:01}" | |
| # Create a temporary directory | |
| TEMP_DIR=$(mktemp -d) | |
| FRAME_PATH="$TEMP_DIR/frame.png" | |
| echo "Extracting frame at $TIME_POSITION mark..." | |
| ffmpeg -y -ss "$TIME_POSITION" -i "$INPUT_VIDEO" -vframes 1 -q:v 2 "$FRAME_PATH" | |
| # Get video dimensions | |
| VIDEO_INFO=$(ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 "$INPUT_VIDEO") | |
| VIDEO_WIDTH=$(echo $VIDEO_INFO | cut -d'x' -f1) | |
| VIDEO_HEIGHT=$(echo $VIDEO_INFO | cut -d'x' -f2) | |
| echo "Video dimensions: ${VIDEO_WIDTH}x${VIDEO_HEIGHT}" | |
| # Detect black bars using ffmpeg's cropdetect filter with adjusted parameters | |
| echo "Detecting letterbox dimensions..." | |
| # Use more sensitive detection parameters | |
| CROP_INFO=$(ffmpeg -i "$FRAME_PATH" -vf "cropdetect=limit=24:round=2:reset=0" -f null - 2>&1 | grep -o "crop=[0-9:]*" | tail -1) | |
| if [ -z "$CROP_INFO" ]; then | |
| echo "Could not detect crop dimensions automatically. Trying with more aggressive settings..." | |
| # Try with even more aggressive settings | |
| CROP_INFO=$(ffmpeg -i "$FRAME_PATH" -vf "cropdetect=limit=16:round=2:reset=0" -f null - 2>&1 | grep -o "crop=[0-9:]*" | tail -1) | |
| if [ -z "$CROP_INFO" ]; then | |
| echo "Still could not detect crop dimensions. Let's try manual detection..." | |
| # Save a debug image with grid for manual inspection | |
| DEBUG_FRAME="$TEMP_DIR/debug_frame.png" | |
| ffmpeg -i "$FRAME_PATH" -vf "drawgrid=width=32:height=32:thickness=1:[email protected]" "$DEBUG_FRAME" | |
| echo "Debug frame saved to: $DEBUG_FRAME" | |
| open "$DEBUG_FRAME" | |
| # Extract top and bottom black bar heights using ImageMagick if available | |
| if command -v convert &> /dev/null; then | |
| echo "Using ImageMagick for detection..." | |
| # Create temporary files for analysis | |
| TOP_SCAN="$TEMP_DIR/top_scan.txt" | |
| BOTTOM_SCAN="$TEMP_DIR/bottom_scan.txt" | |
| # Scan top and bottom edges for black pixels | |
| convert "$FRAME_PATH" -crop "${VIDEO_WIDTH}x20+0+0" -colorspace RGB -format "%[fx:mean]" info: > "$TOP_SCAN" | |
| convert "$FRAME_PATH" -crop "${VIDEO_WIDTH}x20+0+$((VIDEO_HEIGHT-20))" -colorspace RGB -format "%[fx:mean]" info: > "$BOTTOM_SCAN" | |
| TOP_VALUE=$(cat "$TOP_SCAN") | |
| BOTTOM_VALUE=$(cat "$BOTTOM_SCAN") | |
| echo "Top brightness: $TOP_VALUE, Bottom brightness: $BOTTOM_VALUE" | |
| # If brightness is below threshold, consider it a black bar | |
| THRESHOLD=0.05 | |
| TOP_CROP=0 | |
| BOTTOM_CROP=0 | |
| if (( $(echo "$TOP_VALUE < $THRESHOLD" | bc -l) )); then | |
| # Estimate top black bar height | |
| for ((y=1; y<VIDEO_HEIGHT/3; y+=5)); do | |
| BRIGHTNESS=$(convert "$FRAME_PATH" -crop "${VIDEO_WIDTH}x1+0+$y" -colorspace RGB -format "%[fx:mean]" info:) | |
| if (( $(echo "$BRIGHTNESS > $THRESHOLD" | bc -l) )); then | |
| TOP_CROP=$y | |
| break | |
| fi | |
| done | |
| fi | |
| if (( $(echo "$BOTTOM_VALUE < $THRESHOLD" | bc -l) )); then | |
| # Estimate bottom black bar height | |
| for ((y=VIDEO_HEIGHT-1; y>VIDEO_HEIGHT*2/3; y-=5)); do | |
| BRIGHTNESS=$(convert "$FRAME_PATH" -crop "${VIDEO_WIDTH}x1+0+$y" -colorspace RGB -format "%[fx:mean]" info:) | |
| if (( $(echo "$BRIGHTNESS > $THRESHOLD" | bc -l) )); then | |
| BOTTOM_CROP=$((VIDEO_HEIGHT-y-1)) | |
| break | |
| fi | |
| done | |
| fi | |
| if [ $TOP_CROP -gt 0 ] || [ $BOTTOM_CROP -gt 0 ]; then | |
| NEW_HEIGHT=$((VIDEO_HEIGHT-TOP_CROP-BOTTOM_CROP)) | |
| CROP_INFO="crop=${VIDEO_WIDTH}:${NEW_HEIGHT}:0:${TOP_CROP}" | |
| echo "Manually detected crop: $CROP_INFO" | |
| else | |
| echo "No significant letterboxing detected." | |
| exit 1 | |
| fi | |
| else | |
| echo "ImageMagick not found. Cannot perform manual detection." | |
| exit 1 | |
| fi | |
| fi | |
| fi | |
| echo "Detected crop settings: $CROP_INFO" | |
| # Extract crop dimensions | |
| CROP_WIDTH=$(echo $CROP_INFO | sed -E 's/crop=([0-9]+):.*/\1/') | |
| CROP_HEIGHT=$(echo $CROP_INFO | sed -E 's/crop=[0-9]+:([0-9]+):.*/\1/') | |
| CROP_X=$(echo $CROP_INFO | sed -E 's/crop=[0-9]+:[0-9]+:([0-9]+):.*/\1/') | |
| CROP_Y=$(echo $CROP_INFO | sed -E 's/crop=[0-9]+:[0-9]+:[0-9]+:([0-9]+).*/\1/') | |
| echo "Crop dimensions: ${CROP_WIDTH}x${CROP_HEIGHT} at position (${CROP_X},${CROP_Y})" | |
| # Verify the crop makes sense (not cropping too much) | |
| MIN_PERCENT=50 | |
| if (( $(echo "$CROP_WIDTH * 100 / $VIDEO_WIDTH < $MIN_PERCENT" | bc -l) )) || \ | |
| (( $(echo "$CROP_HEIGHT * 100 / $VIDEO_HEIGHT < $MIN_PERCENT" | bc -l) )); then | |
| echo "Warning: Crop dimensions seem extreme (removing more than ${MIN_PERCENT}% of the frame)." | |
| echo "Original: ${VIDEO_WIDTH}x${VIDEO_HEIGHT}, Crop: ${CROP_WIDTH}x${CROP_HEIGHT}" | |
| read -p "Continue anyway? (y/n): " CONFIRM | |
| if [[ $CONFIRM != "y" ]]; then | |
| echo "Aborted by user." | |
| exit 1 | |
| fi | |
| fi | |
| # Apply the crop to the entire video | |
| echo "Applying crop to entire video..." | |
| ffmpeg -i "$INPUT_VIDEO" -vf "$CROP_INFO" -c:v libx264 -crf 18 -preset medium -c:a copy "$OUTPUT_VIDEO" | |
| # Clean up | |
| rm -rf "$TEMP_DIR" | |
| echo "Processing complete. Output saved to: $OUTPUT_VIDEO" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment