81 lines
3.2 KiB
Python
81 lines
3.2 KiB
Python
import cv2
|
|
import numpy as np
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
def test_lines(img_path, out_path):
|
|
img = cv2.imread(img_path)
|
|
if img is None:
|
|
print("Could not read image")
|
|
return
|
|
|
|
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
|
|
|
# 1. Use standard binary thresholding instead of adaptive to reduce noise from text
|
|
# Newspapers usually have very black lines on white background
|
|
_, thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
|
|
|
|
# We want lines that are at least 300px long (a typical column width)
|
|
line_length = 300
|
|
|
|
# 2. Detect horizontal lines (MUST be thin: e.g., height <= 5px)
|
|
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (line_length, 1))
|
|
horizontal_lines_raw = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
|
|
|
|
# 3. Detect vertical lines (MUST be thin: e.g., width <= 5px)
|
|
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, line_length))
|
|
vertical_lines_raw = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
|
|
|
|
# 4. Filter contours to ensure they are actually THIN lines, not thick blocks/images
|
|
h_contours_raw, _ = cv2.findContours(horizontal_lines_raw, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
|
v_contours_raw, _ = cv2.findContours(vertical_lines_raw, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
|
|
|
h_contours = []
|
|
for cnt in h_contours_raw:
|
|
x, y, w, h = cv2.boundingRect(cnt)
|
|
if h <= 15: # Line must not be thicker than 15px
|
|
h_contours.append(cnt)
|
|
|
|
v_contours = []
|
|
for cnt in v_contours_raw:
|
|
x, y, w, h = cv2.boundingRect(cnt)
|
|
if w <= 15: # Line must not be thicker than 15px
|
|
v_contours.append(cnt)
|
|
|
|
print(f"Horizontal separators found: {len(h_contours)} (filtered from {len(h_contours_raw)})")
|
|
print(f"Vertical separators found: {len(v_contours)} (filtered from {len(v_contours_raw)})")
|
|
|
|
# 5. Create clean masks from only the filtered thin lines
|
|
clean_h_mask = np.zeros_like(thresh)
|
|
cv2.drawContours(clean_h_mask, h_contours, -1, 255, thickness=cv2.FILLED)
|
|
|
|
clean_v_mask = np.zeros_like(thresh)
|
|
cv2.drawContours(clean_v_mask, v_contours, -1, 255, thickness=cv2.FILLED)
|
|
|
|
grid = cv2.add(clean_h_mask, clean_v_mask)
|
|
rect_contours, _ = cv2.findContours(grid, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
|
|
|
|
box_count = 0
|
|
debug_img = img.copy()
|
|
|
|
for cnt in rect_contours:
|
|
epsilon = 0.02 * cv2.arcLength(cnt, True)
|
|
approx = cv2.approxPolyDP(cnt, epsilon, True)
|
|
|
|
if len(approx) == 4:
|
|
x, y, w, h = cv2.boundingRect(approx)
|
|
if w > 300 and h > 200:
|
|
box_count += 1
|
|
cv2.rectangle(debug_img, (x, y), (x+w, y+h), (255, 0, 255), 8)
|
|
|
|
print(f"Rectangular boxes found: {box_count}")
|
|
|
|
cv2.drawContours(debug_img, h_contours, -1, (0, 0, 255), 3) # Red for horizontal
|
|
cv2.drawContours(debug_img, v_contours, -1, (255, 0, 0), 3) # Blue for vertical
|
|
|
|
cv2.imwrite(out_path, debug_img)
|
|
print(f"Saved debug image to {out_path}")
|
|
|
|
if __name__ == "__main__":
|
|
test_lines(sys.argv[1], sys.argv[2])
|