File size: 4,262 Bytes
d51bea3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
"""
Debug script to visualize each preprocessing step for red play clock digits.
"""

from pathlib import Path

import cv2
import numpy as np


def main():
    # Load the red play clock region (frame 472849, which shows "5")
    region_path = Path("output/debug/red_play_clock/frame_472849_region.png")
    output_dir = Path("output/debug/red_preprocessing")
    output_dir.mkdir(parents=True, exist_ok=True)

    # Load the region
    region = cv2.imread(str(region_path))
    if region is None:
        print(f"Failed to load {region_path}")
        return

    print(f"Loaded region: {region.shape}")

    # Step 1: Split into color channels
    b, g, r = cv2.split(region)
    cv2.imwrite(str(output_dir / "01_red_channel.png"), r)
    cv2.imwrite(str(output_dir / "01_green_channel.png"), g)
    cv2.imwrite(str(output_dir / "01_blue_channel.png"), b)

    print(f"Red channel - min: {r.min()}, max: {r.max()}, mean: {r.mean():.1f}, std: {r.std():.1f}")
    print(f"Green channel - min: {g.min()}, max: {g.max()}, mean: {g.mean():.1f}")
    print(f"Blue channel - min: {b.min()}, max: {b.max()}, mean: {b.mean():.1f}")

    # Step 2: Use red channel as grayscale
    gray = r.copy()
    cv2.imwrite(str(output_dir / "02_gray_from_red.png"), gray)
    print(f"Gray (red channel) - shape: {gray.shape}")

    # Step 3: Scale up by 4x
    scale_factor = 4
    scaled = cv2.resize(gray, None, fx=scale_factor, fy=scale_factor, interpolation=cv2.INTER_LINEAR)
    cv2.imwrite(str(output_dir / "03_scaled.png"), scaled)
    print(f"Scaled - shape: {scaled.shape}, min: {scaled.min()}, max: {scaled.max()}, mean: {scaled.mean():.1f}")

    # Step 4: Otsu's thresholding
    threshold, binary_otsu = cv2.threshold(scaled, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    cv2.imwrite(str(output_dir / "04_otsu_binary.png"), binary_otsu)
    print(f"Otsu threshold: {threshold}")
    print(f"Binary (Otsu) - white pixels: {(binary_otsu == 255).sum()}, black pixels: {(binary_otsu == 0).sum()}")

    # Step 4b: Try different fixed thresholds
    for thresh_val in [30, 50, 70, 90]:
        _, binary_fixed = cv2.threshold(scaled, thresh_val, 255, cv2.THRESH_BINARY)
        cv2.imwrite(str(output_dir / f"04_fixed_thresh_{thresh_val}.png"), binary_fixed)
        white_pix = (binary_fixed == 255).sum()
        black_pix = (binary_fixed == 0).sum()
        print(f"Fixed threshold {thresh_val}: white={white_pix}, black={black_pix}")

    # Step 5: Check mean intensity and decide on inversion
    binary = binary_otsu.copy()
    mean_intensity = np.mean(binary)
    print(f"Mean intensity after Otsu: {mean_intensity:.1f}")
    if mean_intensity < 128:
        print("Mean < 128, inverting image")
        binary = cv2.bitwise_not(binary)
    cv2.imwrite(str(output_dir / "05_after_inversion_check.png"), binary)

    # Step 6: Morphological operations
    kernel = np.ones((2, 2), np.uint8)
    binary = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
    cv2.imwrite(str(output_dir / "06_after_morph_close.png"), binary)
    binary = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
    cv2.imwrite(str(output_dir / "06_after_morph_open.png"), binary)

    # Step 7: Add padding
    padding = 10
    binary = cv2.copyMakeBorder(binary, padding, padding, padding, padding, cv2.BORDER_CONSTANT, value=255)
    cv2.imwrite(str(output_dir / "07_final_with_padding.png"), binary)

    print(f"\nFinal image shape: {binary.shape}")
    print(f"Output saved to: {output_dir}")

    # Also compare with standard grayscale approach
    print("\n--- Comparing with standard grayscale ---")
    gray_standard = cv2.cvtColor(region, cv2.COLOR_BGR2GRAY)
    cv2.imwrite(str(output_dir / "compare_standard_gray.png"), gray_standard)
    print(f"Standard grayscale - min: {gray_standard.min()}, max: {gray_standard.max()}, mean: {gray_standard.mean():.1f}")

    scaled_standard = cv2.resize(gray_standard, None, fx=scale_factor, fy=scale_factor, interpolation=cv2.INTER_LINEAR)
    threshold_std, binary_standard = cv2.threshold(scaled_standard, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    cv2.imwrite(str(output_dir / "compare_standard_otsu.png"), binary_standard)
    print(f"Standard grayscale Otsu threshold: {threshold_std}")


if __name__ == "__main__":
    main()