File size: 3,943 Bytes
2021e9a
1fe8e1c
 
 
 
 
 
2021e9a
1fe8e1c
 
 
2021e9a
1fe8e1c
93ee1d7
 
 
 
 
 
 
 
 
 
 
db8fe18
 
93ee1d7
 
 
 
 
 
db8fe18
1fe8e1c
93ee1d7
 
 
 
1fe8e1c
 
 
 
 
 
 
 
 
 
 
f5c8077
1fe8e1c
 
 
2021e9a
 
1fe8e1c
2021e9a
1fe8e1c
 
2021e9a
1fe8e1c
2021e9a
1fe8e1c
 
 
 
 
f5c8077
 
1fe8e1c
 
 
 
 
 
 
 
 
 
 
 
f5c8077
1fe8e1c
 
2021e9a
1fe8e1c
2021e9a
1fe8e1c
2021e9a
 
1fe8e1c
 
 
2021e9a
1fe8e1c
 
 
2021e9a
1fe8e1c
2021e9a
1fe8e1c
 
 
2021e9a
1fe8e1c
2021e9a
1fe8e1c
 
2021e9a
1fe8e1c
2021e9a
1fe8e1c
2021e9a
 
 
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
from fastapi import FastAPI, File, UploadFile, HTTPException
from PIL import Image
import pytesseract
import numpy as np
import cv2
import subprocess
import os
import io

pytesseract.pytesseract.tesseract_cmd = '/usr/bin/tesseract'

app = FastAPI()

def set_dpi(image: Image.Image, target_dpi=300):
    """Set the image DPI to the target value while preserving aspect ratio."""
    current_dpi = image.info.get('dpi', (72, 72))[0]
    
    if current_dpi == target_dpi:
        return image
    
    # Calculate scale factor to achieve target DPI
    scale_factor = target_dpi / current_dpi
    
    # Resize image
    width, height = image.size
    new_size = (int(width * scale_factor), int(height * scale_factor))
    resized_image = image.resize(new_size, Image.Resampling.LANCZOS)
    
    # Set DPI metadata
    resized_image.info['dpi'] = (target_dpi, target_dpi)
    
    return resized_image

def preprocess_dual(image: Image.Image):
    """Set DPI to 300, convert to grayscale, and produce normal and inverted versions."""
    # Set DPI to 300
    image_300dpi = set_dpi(image, target_dpi=300)
    img = np.array(image_300dpi)
    if img.ndim == 3:
        gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    else:
        gray = img
    inverted = cv2.bitwise_not(gray)
    return gray, inverted

def contains_croatian_chars(text):
    cro_chars = set("čćđžšČĆĐŽŠ")
    return any(c in text for c in cro_chars)

def run_ocr(image_np, lang='hrv', config='--oem 3 --psm 6'):
    """Run Tesseract OCR on a grayscale image"""
    return pytesseract.image_to_string(image_np, config=config, lang=lang)

@app.post('/ocr')
async def ocr(file: UploadFile = File(...)):
    if not file:
        raise HTTPException(status_code=400, detail={'error': 'No image uploaded'})

    try:
        image = Image.open(io.BytesIO(await file.read())).convert('RGB')
    except Exception as e:
        raise HTTPException(status_code=400, detail={'error': f'Invalid image file: {str(e)}'})

    gray, inverted = preprocess_dual(image)

    try:
        # Croatian OCR
        text_hrv_normal = run_ocr(gray, lang='hrv')
        text_hrv_inverted = run_ocr(inverted, lang='hrv')
        text_hrv = text_hrv_inverted if len(text_hrv_inverted.strip()) > len(text_hrv_normal.strip()) else text_hrv_normal

        if contains_croatian_chars(text_hrv):
            final_text = text_hrv
        else:
            # Fallback to English OCR
            text_eng_normal = run_ocr(gray, lang='eng')
            text_eng_inverted = run_ocr(inverted, lang='eng')
            text_eng = text_eng_inverted if len(text_eng_inverted.strip()) > len(text_eng_normal.strip()) else text_eng_normal
            final_text = text_eng if len(text_eng.strip()) > len(text_hrv.strip()) else text_hrv

        final_text = final_text.replace('£', 'E')
        final_text = final_text.replace('€', 'E')

    except Exception as e:
        raise HTTPException(status_code=500, detail={'error': f'OCR failed: {str(e)}'})

    return {'text': final_text}

@app.get('/debug')
async def debug_tesseract():
    try:
        result = subprocess.run(['tesseract', '--version'], capture_output=True, text=True, check=True)
        path = os.environ.get('PATH', 'PATH not set')
        return {
            'tesseract_version': result.stdout.strip(),
            'tesseract_path': pytesseract.pytesseract.tesseract_cmd,
            'current_path': path
        }
    except subprocess.CalledProcessError as e:
        return {
            'error': str(e),
            'stderr': e.stderr,
            'path': os.environ.get('PATH', 'PATH not set')
        }, 500
    except FileNotFoundError:
        return {
            'error': 'Tesseract executable not found',
            'path': os.environ.get('PATH', 'PATH not set')
        }, 500
    except Exception as e:
        return {'error': str(e)}, 500

@app.get('/')
async def root():
    return {"message": "Hello from FastAPI"}