File size: 3,576 Bytes
430a6c7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import cv2
import numpy as np
import pytesseract
import requests
import pandas as pd
import gradio as gr
from io import BytesIO

# ──────────────────────────────────────────────────────────────
# 1. Utility: Detect rectangular contours (approximate book covers)
# ──────────────────────────────────────────────────────────────
def detect_book_regions(image: np.ndarray, min_area=10000, eps_coef=0.02):
    """
    Detect rectangular regions in an image that likely correspond to book covers.
    Returns a list of bounding boxes: (x, y, w, h).
    """
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (5, 5), 0)
    edges = cv2.Canny(blurred, 50, 150)

    # Dilate + erode to close gaps
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
    closed = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)

    contours, _ = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    boxes = []

    for cnt in contours:
        area = cv2.contourArea(cnt)
        if area < min_area:
            continue

        peri = cv2.arcLength(cnt, True)
        approx = cv2.approxPolyDP(cnt, eps_coef * peri, True)

        # Keep only quadrilaterals
        if len(approx) == 4:
            x, y, w, h = cv2.boundingRect(approx)
            ar = w / float(h)
            # Filter by typical book-cover aspect ratios
            if 0.4 < ar < 0.9 or 1.0 < ar < 1.6:
                boxes.append((x, y, w, h))

    # Sort left→right, top→bottom
    boxes = sorted(boxes, key=lambda b: (b[1], b[0]))
    return boxes

# ──────────────────────────────────────────────────────────────
# 2. OCR on a cropped region
# ──────────────────────────────────────────────────────────────
def ocr_on_region(image: np.ndarray, box: tuple):
    """
    Crop the image to the given box and run Tesseract OCR.
    Return the raw OCR text.
    """
    x, y, w, h = box
    cropped = image[y:y+h, x:x+w]
    gray_crop = cv2.cvtColor(cropped, cv2.COLOR_BGR2GRAY)
    _, thresh_crop = cv2.threshold(gray_crop, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    custom_config = r'--oem 3 --psm 6'
    text = pytesseract.image_to_string(thresh_crop, config=custom_config)
    return text.strip()

# ──────────────────────────────────────────────────────────────
# 3. Query OpenLibrary API
# ──────────────────────────────────────────────────────────────
def query_openlibrary(title_text: str, author_text: str = None):
    """
    Search OpenLibrary by title (and optional author). 
    Return a dict with title, author_name, publisher, first_publish_year, or None.
    """
    base_url = "https://openlibrary.org/search.json"
    params = {"title": title_text}
    if author_text:
        params["author"] = author_text

    try:
        resp = requests.get(base_url, params=params, timeout=5)