188 lines
No EOL
7.2 KiB
Python
188 lines
No EOL
7.2 KiB
Python
#!/usr/bin/env python3
|
|
import cv2
|
|
import numpy as np
|
|
from pathlib import Path
|
|
import os
|
|
|
|
def analyze_horizontal_panels(image_path: str, debug=True):
|
|
"""Analyze horizontal panel structure and test splitting parameters"""
|
|
print(f"Analyzing {Path(image_path).name}")
|
|
|
|
# Load image
|
|
img = cv2.imread(image_path)
|
|
height, width = img.shape[:2]
|
|
print(f"Image dimensions: {width}x{height}")
|
|
|
|
# Convert to grayscale
|
|
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
|
|
|
# Method 1: Simple equal division
|
|
print("\n=== Method 1: Equal Division ===")
|
|
equal_panels = []
|
|
for num_panels in [8, 10, 12]:
|
|
panel_width = width // num_panels
|
|
panels = []
|
|
for i in range(num_panels):
|
|
x1 = i * panel_width
|
|
x2 = (i + 1) * panel_width if i < num_panels - 1 else width
|
|
panels.append((x1, 0, x2, height))
|
|
equal_panels.append((num_panels, panels))
|
|
print(f" {num_panels} panels: widths = {[x2-x1 for x1, y1, x2, y2 in panels]}")
|
|
|
|
# Method 2: Edge-based detection
|
|
print("\n=== Method 2: Edge Detection ===")
|
|
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
|
|
|
|
# Create vertical line detection kernel
|
|
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, height // 4))
|
|
vertical_lines = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, vertical_kernel)
|
|
|
|
# Get vertical projection
|
|
vertical_projection = np.sum(vertical_lines, axis=0)
|
|
|
|
# Find peaks for different thresholds
|
|
for threshold_factor in [0.3, 0.4, 0.5, 0.6, 0.7]:
|
|
threshold = np.max(vertical_projection) * threshold_factor
|
|
separators = []
|
|
|
|
for x in range(width):
|
|
if vertical_projection[x] > threshold:
|
|
# Ensure minimum distance between separators
|
|
if not separators or x - separators[-1] > 30:
|
|
separators.append(x)
|
|
|
|
# Create panels from separators
|
|
x_boundaries = [0] + separators + [width]
|
|
x_boundaries = sorted(list(set(x_boundaries)))
|
|
|
|
panels = []
|
|
for i in range(len(x_boundaries) - 1):
|
|
x1, x2 = x_boundaries[i], x_boundaries[i + 1]
|
|
if x2 - x1 > 50: # Minimum panel width
|
|
panels.append((x1, 0, x2, height))
|
|
|
|
print(f" Threshold {threshold_factor}: {len(panels)} panels, widths = {[x2-x1 for x1, y1, x2, y2 in panels]}")
|
|
|
|
# Method 3: Adaptive histogram analysis
|
|
print("\n=== Method 3: Histogram Analysis ===")
|
|
|
|
# Calculate horizontal histogram (sum of pixel intensities)
|
|
horizontal_hist = np.sum(gray, axis=0)
|
|
|
|
# Find local minima (potential separators)
|
|
from scipy.signal import find_peaks
|
|
|
|
# Invert histogram to find valleys (separators)
|
|
inverted_hist = np.max(horizontal_hist) - horizontal_hist
|
|
|
|
# Find peaks in inverted histogram (valleys in original)
|
|
for min_distance in [50, 80, 100, 120]:
|
|
peaks, _ = find_peaks(inverted_hist, distance=min_distance, height=np.max(inverted_hist) * 0.1)
|
|
|
|
# Create panels
|
|
x_boundaries = [0] + list(peaks) + [width]
|
|
x_boundaries = sorted(list(set(x_boundaries)))
|
|
|
|
panels = []
|
|
for i in range(len(x_boundaries) - 1):
|
|
x1, x2 = x_boundaries[i], x_boundaries[i + 1]
|
|
if x2 - x1 > 50:
|
|
panels.append((x1, 0, x2, height))
|
|
|
|
print(f" Min distance {min_distance}: {len(panels)} panels, widths = {[x2-x1 for x1, y1, x2, y2 in panels]}")
|
|
|
|
if debug:
|
|
# Save debug images
|
|
debug_dir = Path("debug_splitting")
|
|
debug_dir.mkdir(exist_ok=True)
|
|
|
|
# Save edge detection result
|
|
cv2.imwrite(str(debug_dir / f"{Path(image_path).stem}_edges.jpg"), edges)
|
|
cv2.imwrite(str(debug_dir / f"{Path(image_path).stem}_vertical_lines.jpg"), vertical_lines)
|
|
|
|
# Save histogram visualization
|
|
import matplotlib.pyplot as plt
|
|
plt.figure(figsize=(15, 5))
|
|
plt.plot(horizontal_hist)
|
|
plt.title("Horizontal Histogram")
|
|
plt.savefig(debug_dir / f"{Path(image_path).stem}_histogram.png")
|
|
plt.close()
|
|
|
|
# Save inverted histogram with peaks
|
|
plt.figure(figsize=(15, 5))
|
|
plt.plot(inverted_hist)
|
|
peaks, _ = find_peaks(inverted_hist, distance=100, height=np.max(inverted_hist) * 0.1)
|
|
plt.scatter(peaks, inverted_hist[peaks], color='red', zorder=5)
|
|
plt.title("Inverted Histogram with Detected Peaks")
|
|
plt.savefig(debug_dir / f"{Path(image_path).stem}_peaks.png")
|
|
plt.close()
|
|
|
|
print(f"\nDebug images saved to {debug_dir}/")
|
|
|
|
return equal_panels
|
|
|
|
def test_best_method(image_path: str, expected_panels: int):
|
|
"""Test the best splitting method for accurate panel detection"""
|
|
print(f"\n=== Testing Best Method for {expected_panels} expected panels ===")
|
|
|
|
img = cv2.imread(image_path)
|
|
height, width = img.shape[:2]
|
|
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
|
|
|
# Combination approach: Use histogram analysis with refinement
|
|
horizontal_hist = np.sum(gray, axis=0)
|
|
inverted_hist = np.max(horizontal_hist) - horizontal_hist
|
|
|
|
# Smooth the inverted histogram to reduce noise
|
|
from scipy.ndimage import gaussian_filter1d
|
|
smoothed_hist = gaussian_filter1d(inverted_hist, sigma=10)
|
|
|
|
# Find peaks with optimized parameters
|
|
from scipy.signal import find_peaks
|
|
min_distance = width // (expected_panels * 1.5) # Adaptive distance based on expected panels
|
|
peaks, properties = find_peaks(smoothed_hist,
|
|
distance=min_distance,
|
|
height=np.max(smoothed_hist) * 0.15,
|
|
prominence=np.max(smoothed_hist) * 0.1)
|
|
|
|
print(f"Found {len(peaks)} separator peaks with min_distance={min_distance}")
|
|
|
|
# Create panels
|
|
x_boundaries = [0] + list(peaks) + [width]
|
|
x_boundaries = sorted(list(set(x_boundaries)))
|
|
|
|
panels = []
|
|
for i in range(len(x_boundaries) - 1):
|
|
x1, x2 = x_boundaries[i], x_boundaries[i + 1]
|
|
if x2 - x1 > 50: # Minimum reasonable panel width
|
|
panels.append((x1, 0, x2, height))
|
|
|
|
print(f"Generated {len(panels)} panels:")
|
|
for i, (x1, y1, x2, y2) in enumerate(panels):
|
|
print(f" Panel {i+1}: x={x1}-{x2} (width={x2-x1})")
|
|
|
|
# Save crops for visual verification
|
|
crops_dir = Path("test_crops")
|
|
crops_dir.mkdir(exist_ok=True)
|
|
|
|
for i, (x1, y1, x2, y2) in enumerate(panels):
|
|
crop = img[y1:y2, x1:x2]
|
|
crop_path = crops_dir / f"{Path(image_path).stem}_panel_{i+1:02d}.jpg"
|
|
cv2.imwrite(str(crop_path), crop)
|
|
|
|
print(f"\nCrops saved to {crops_dir}/ - Check these to verify panel accuracy!")
|
|
|
|
return panels
|
|
|
|
if __name__ == "__main__":
|
|
# Test on the multi-panel layout
|
|
test_image = "/Users/michael.clervi/Documents/projects/master_adapt_detect/layouts/6786500.jpg"
|
|
|
|
if os.path.exists(test_image):
|
|
print("Analyzing horizontal panel structure...")
|
|
analyze_horizontal_panels(test_image, debug=True)
|
|
|
|
print("\n" + "="*60)
|
|
test_best_method(test_image, expected_panels=10)
|
|
else:
|
|
print(f"Test image not found: {test_image}") |