#13 use webp instead of jpeg/png
This commit is contained in:
177
ocr_server.py
177
ocr_server.py
@@ -26,116 +26,84 @@ def get_dir_name():
|
||||
|
||||
def create_debug_directory(dir_name):
|
||||
"""Erstellt ein eindeutiges Verzeichnis für Debug-Bilder"""
|
||||
base_dir = 'debug_images'
|
||||
timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
unique_id = str(uuid.uuid4())[:8]
|
||||
base_dir = 'images'
|
||||
full_path = os.path.join(base_dir, dir_name)
|
||||
|
||||
# Erstelle Hauptverzeichnis falls nicht vorhanden
|
||||
if not os.path.exists(base_dir):
|
||||
os.makedirs(base_dir)
|
||||
|
||||
# Erstelle spezifisches Verzeichnis für diesen Durchlauf
|
||||
os.makedirs(full_path)
|
||||
|
||||
return full_path
|
||||
|
||||
def preprocess_image(image, debug_dir):
|
||||
"""
|
||||
Verarbeitet das Bild und speichert Zwischenergebnisse im angegebenen Verzeichnis,
|
||||
einschließlich einer komprimierten JPG-Version und eines Thumbnails.
|
||||
"""
|
||||
"""Bildverarbeitung mit optionalen Optimierungen"""
|
||||
try:
|
||||
# Umwandlung in Graustufen
|
||||
# Graustufenkonvertierung
|
||||
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
|
||||
# Anwendung von CLAHE zur Kontrastverbesserung
|
||||
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
|
||||
|
||||
# Kontrastverbesserung mit CLAHE
|
||||
clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8)) # Erhöhter Clip-Limit
|
||||
enhanced = clahe.apply(gray)
|
||||
# Rauschunterdrückung
|
||||
denoised = cv2.fastNlMeansDenoising(enhanced)
|
||||
# Optional: Binärschwellenwert (auskommentiert)
|
||||
# _, binary = cv2.threshold(denoised, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
|
||||
|
||||
# Rauschunterdrückung mit optimierten Parametern
|
||||
denoised = cv2.fastNlMeansDenoising(
|
||||
enhanced,
|
||||
h=15, # Stärkere Rauschreduzierung
|
||||
templateWindowSize=7,
|
||||
searchWindowSize=21
|
||||
)
|
||||
|
||||
# Speichern der Zwischenergebnisse im spezifischen Verzeichnis
|
||||
cv2.imwrite(os.path.join(debug_dir, 'gray.png'), gray)
|
||||
cv2.imwrite(os.path.join(debug_dir, 'enhanced.png'), enhanced)
|
||||
cv2.imwrite(os.path.join(debug_dir, 'denoised.png'), denoised)
|
||||
# cv2.imwrite(os.path.join(debug_dir, 'binary.png'), binary)
|
||||
# Debug-Bilder speichern
|
||||
# cv2.imwrite(os.path.join(debug_dir, 'gray.png'), gray)
|
||||
# cv2.imwrite(os.path.join(debug_dir, 'enhanced.png'), enhanced)
|
||||
# cv2.imwrite(os.path.join(debug_dir, 'denoised.png'), denoised)
|
||||
|
||||
# Speichern der komprimierten JPG-Version des Originalbildes
|
||||
compressed_jpg_path = os.path.join(debug_dir, 'original_compressed.jpg')
|
||||
original_bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
|
||||
cv2.imwrite(compressed_jpg_path, original_bgr, [int(cv2.IMWRITE_JPEG_QUALITY), 80]) # Qualität auf 80 setzen
|
||||
logger.info(f"Komprimiertes Original JPG gespeichert: {compressed_jpg_path}")
|
||||
# Thumbnail als WebP
|
||||
denoised_rgb = cv2.cvtColor(denoised, cv2.COLOR_GRAY2RGB)
|
||||
thumbnail = Image.fromarray(denoised_rgb)
|
||||
thumbnail.thumbnail((256, 256))
|
||||
thumbnail_path = os.path.join(debug_dir, 'thumbnail.webp')
|
||||
thumbnail.save(thumbnail_path, 'WEBP', quality=85)
|
||||
|
||||
# Erstellen und Speichern des Thumbnails
|
||||
thumbnail_path = os.path.join(debug_dir, 'thumbnail.jpg')
|
||||
image_pil = Image.fromarray(denoised)
|
||||
image_pil.thumbnail((128, 128)) # Thumbnail-Größe auf 128x128 Pixel setzen
|
||||
image_pil.save(thumbnail_path, 'JPEG')
|
||||
logger.info(f"Thumbnail gespeichert: {thumbnail_path}")
|
||||
|
||||
logger.info(f"Debug images saved in: {debug_dir}")
|
||||
return denoised
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Preprocessing error: {str(e)}")
|
||||
raise
|
||||
|
||||
|
||||
@app.route('/api/ocr', methods=['POST'])
|
||||
def ocr_endpoint():
|
||||
debug_dir = None
|
||||
try:
|
||||
# Erstelle eindeutiges Debug-Verzeichnis für diesen Request
|
||||
# Verzeichnis erstellen
|
||||
dir_name = get_dir_name()
|
||||
debug_dir = create_debug_directory(dir_name)
|
||||
logger.info(f"Created debug directory: {debug_dir}")
|
||||
|
||||
if not request.is_json:
|
||||
return jsonify({'error': 'Content-Type must be application/json'}), 400
|
||||
|
||||
data = request.get_json()
|
||||
if not data or 'image' not in data:
|
||||
return jsonify({'error': 'No image provided'}), 400
|
||||
|
||||
image_b64 = data['image']
|
||||
|
||||
# Base64 Dekodierung
|
||||
try:
|
||||
image_data = base64.b64decode(image_b64)
|
||||
except Exception as decode_err:
|
||||
logger.error(f"Base64 decode error: {str(decode_err)}")
|
||||
return jsonify({'error': 'Base64 decode error'}), 400
|
||||
|
||||
# Bildverarbeitung
|
||||
try:
|
||||
image = Image.open(BytesIO(image_data)).convert('RGB')
|
||||
image = np.array(image)
|
||||
logger.info(f"Image loaded successfully. Shape: {image.shape}")
|
||||
|
||||
# Originalbild speichern
|
||||
cv2.imwrite(os.path.join(debug_dir, 'original.png'),
|
||||
cv2.cvtColor(image, cv2.COLOR_RGB2BGR))
|
||||
except Exception as img_err:
|
||||
logger.error(f"Image processing error: {str(img_err)}")
|
||||
return jsonify({'error': 'Invalid image data'}), 400
|
||||
data = request.get_json()
|
||||
image_data = base64.b64decode(data['image'])
|
||||
|
||||
# Originalbild als WebP speichern
|
||||
original_image = Image.open(BytesIO(image_data)).convert('RGB')
|
||||
webp_path = os.path.join(debug_dir, 'original.webp')
|
||||
original_image.save(webp_path, 'WEBP', quality=50)
|
||||
|
||||
# Bildvorverarbeitung
|
||||
processed_image = preprocess_image(image, debug_dir)
|
||||
logger.info("Preprocessing completed")
|
||||
# WebP-Bild für Verarbeitung laden
|
||||
with open(webp_path, 'rb') as f:
|
||||
webp_image = Image.open(BytesIO(f.read())).convert('RGB')
|
||||
|
||||
# Vorverarbeitung
|
||||
processed_image = preprocess_image(np.array(webp_image), debug_dir)
|
||||
|
||||
# PaddleOCR Konfiguration
|
||||
# OCR mit optimierter Konfiguration
|
||||
ocr = PaddleOCR(
|
||||
use_angle_cls=True,
|
||||
lang='en',
|
||||
det_db_thresh=0.3,
|
||||
det_db_box_thresh=0.3,
|
||||
det_db_unclip_ratio=2.0,
|
||||
rec_char_type='en',
|
||||
det_limit_side_len=960,
|
||||
det_limit_type='max',
|
||||
det_model_dir='en_PP-OCRv3_det',
|
||||
rec_model_dir='en_PP-OCRv3_rec',
|
||||
det_limit_side_len=processed_image.shape[0] * 2,
|
||||
use_dilation=True,
|
||||
det_db_score_mode='fast',
|
||||
show_log=True
|
||||
det_db_score_mode='fast'
|
||||
)
|
||||
|
||||
# OCR durchführen
|
||||
@@ -206,59 +174,12 @@ def ocr_endpoint():
|
||||
}), 500
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Unexpected error: {str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
logger.error(f"Fehler: {str(e)}")
|
||||
return jsonify({
|
||||
'error': 'Internal server error',
|
||||
'debug_dir': debug_dir if 'debug_dir' in locals() else None
|
||||
'error': 'Verarbeitungsfehler',
|
||||
'details': str(e),
|
||||
'debug_dir': dir_name if debug_dir else None
|
||||
}), 500
|
||||
|
||||
@app.route('/api/debug_image/<name>/<filename>', methods=['GET'])
|
||||
def get_debug_image(name, filename):
|
||||
"""
|
||||
Gibt das angeforderte Bild unter 'debug_images/[name]/[filename]' direkt zurück.
|
||||
"""
|
||||
try:
|
||||
# Sicherheitsmaßnahme: Nur erlaubte Zeichen im Verzeichnisnamen
|
||||
if not all(c.isalnum() or c in ('_', '-') for c in name):
|
||||
logger.warning(f"Ungültiger Verzeichnisname angefordert: {name}")
|
||||
return jsonify({'error': 'Invalid directory name'}), 400
|
||||
|
||||
# Sicherheitsmaßnahme: Nur erlaubte Zeichen im Dateinamen
|
||||
if not all(c.isalnum() or c in ('_', '-', '.',) for c in filename):
|
||||
logger.warning(f"Ungültiger Dateiname angefordert: {filename}")
|
||||
return jsonify({'error': 'Invalid file name'}), 400
|
||||
|
||||
# Vollständigen Pfad zum Bild erstellen
|
||||
image_path = os.path.join('debug_images', name, filename)
|
||||
|
||||
# Überprüfen, ob die Datei existiert
|
||||
if not os.path.isfile(image_path):
|
||||
logger.warning(f"Bild nicht gefunden: {image_path}")
|
||||
return jsonify({'error': 'Image not found'}), 404
|
||||
|
||||
# Bestimmen des MIME-Typs basierend auf der Dateiendung
|
||||
mime_type = 'image/png' # Standard-MIME-Typ
|
||||
if filename.lower().endswith('.jpg') or filename.lower().endswith('.jpeg'):
|
||||
mime_type = 'image/jpeg'
|
||||
elif filename.lower().endswith('.gif'):
|
||||
mime_type = 'image/gif'
|
||||
elif filename.lower().endswith('.bmp'):
|
||||
mime_type = 'image/bmp'
|
||||
elif filename.lower().endswith('.tiff') or filename.lower().endswith('.tif'):
|
||||
mime_type = 'image/tiff'
|
||||
|
||||
return send_file(
|
||||
image_path,
|
||||
mimetype=mime_type,
|
||||
as_attachment=False
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Abrufen des Bildes '{name}/{filename}': {str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
return jsonify({'error': 'Failed to retrieve image'}), 500
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=5000, debug=False)
|
||||
Reference in New Issue
Block a user