技能备份 - 2026-04-15 (40个技能)
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
PaddleOCR wrapper - High accuracy Chinese OCR engine
|
||||
|
||||
Compatible with PaddleOCR 3.4.0+ API (predict() method returns list)
|
||||
Based on Emma's testing: result[0][0][1][0] for text, result[0][0][1][1] for confidence
|
||||
"""
|
||||
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
|
||||
class PaddleOCR:
|
||||
"""PaddleOCR processor for high-accuracy text extraction"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
verbose: bool = False,
|
||||
lang: str = 'ch',
|
||||
use_angle_cls: bool = True
|
||||
):
|
||||
"""Initialize PaddleOCR - lang and use_angle_cls parameters"""
|
||||
self.verbose = verbose
|
||||
self.lang = lang
|
||||
self.use_angle_cls = use_angle_cls
|
||||
self._init_ocr()
|
||||
|
||||
def _init_ocr(self) -> None:
|
||||
"""Initialize PaddleOCR model"""
|
||||
from paddleocr import PaddleOCR
|
||||
|
||||
self.ocr = PaddleOCR(lang=self.lang, use_angle_cls=self.use_angle_cls)
|
||||
|
||||
def extract(self, image_path: str) -> Dict:
|
||||
"""
|
||||
Extract text from image using PaddleOCR.
|
||||
|
||||
Args:
|
||||
image_path: Path to input image
|
||||
|
||||
Returns:
|
||||
Dict with text, confidence, results, processing time
|
||||
"""
|
||||
if self.verbose:
|
||||
print(f"[PaddleOCR] Processing: {image_path}")
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
try:
|
||||
# Run OCR - using predict() for PaddleOCR 3.4.0+
|
||||
result = self.ocr.predict(image_path)
|
||||
|
||||
processing_time = time.time() - start_time
|
||||
|
||||
# Parse results - legacy format: [[box], [text, confidence]]
|
||||
parsed = self._parse_results(result)
|
||||
parsed['processing_time_ms'] = round(processing_time * 1000, 2)
|
||||
|
||||
return parsed
|
||||
|
||||
except Exception as e:
|
||||
processing_time = time.time() - start_time
|
||||
return {
|
||||
'text': '',
|
||||
'confidence': 0.0,
|
||||
'error': str(e),
|
||||
'results': [],
|
||||
'processing_time_ms': round(processing_time * 1000, 2)
|
||||
}
|
||||
|
||||
def _parse_results(self, results) -> Dict:
|
||||
"""
|
||||
Parse PaddleOCR 3.4.0+ output format.
|
||||
|
||||
PaddleOCR 3.4.0+ predict() returns dict with:
|
||||
- rec_texts: list of detected text strings
|
||||
- rec_scores: list of confidence scores
|
||||
- dt_polys: list of text polygon coordinates
|
||||
|
||||
Returns:
|
||||
Dict with text, confidence, results, line_count
|
||||
"""
|
||||
if not results or not results[0]:
|
||||
return {
|
||||
'text': '',
|
||||
'confidence': 0.0,
|
||||
'results': [],
|
||||
'error': 'No text detected'
|
||||
}
|
||||
|
||||
# New format: result[0] is a dict with 'rec_texts' and 'rec_scores'
|
||||
result_dict = results[0]
|
||||
|
||||
if isinstance(result_dict, dict):
|
||||
texts = result_dict.get('rec_texts', [])
|
||||
scores = result_dict.get('rec_scores', [])
|
||||
|
||||
if not texts:
|
||||
return {
|
||||
'text': '',
|
||||
'confidence': 0.0,
|
||||
'results': [],
|
||||
'error': 'No text detected'
|
||||
}
|
||||
|
||||
# Combine all text (PaddleOCR already splits by lines)
|
||||
full_text = '\n'.join(texts)
|
||||
|
||||
# Calculate average confidence
|
||||
avg_confidence = sum(scores) / len(scores) if scores else 0.0
|
||||
|
||||
# Build detailed results
|
||||
detailed_results = []
|
||||
for i, (text, score) in enumerate(zip(texts, scores)):
|
||||
# Get bbox if available (dt_polys is list of arrays)
|
||||
dt_polys = result_dict.get('dt_polys', [])
|
||||
bbox = None
|
||||
if i < len(dt_polys):
|
||||
try:
|
||||
poly = dt_polys[i]
|
||||
if hasattr(poly, 'tolist'):
|
||||
bbox = poly.tolist()
|
||||
else:
|
||||
bbox = poly
|
||||
except:
|
||||
bbox = None
|
||||
|
||||
detailed_results.append({
|
||||
'text': text,
|
||||
'confidence': round(score, 4),
|
||||
'bbox': bbox
|
||||
})
|
||||
|
||||
return {
|
||||
'text': full_text.strip(),
|
||||
'confidence': round(avg_confidence, 4),
|
||||
'results': detailed_results,
|
||||
'line_count': len(texts)
|
||||
}
|
||||
else:
|
||||
# Fallback: handle legacy format if still used
|
||||
return self._parse_results_legacy(results)
|
||||
|
||||
def _parse_results_legacy(self, results) -> Dict:
|
||||
"""
|
||||
Legacy parser for backward compatibility.
|
||||
Old format: [[bbox], [text, confidence]]
|
||||
"""
|
||||
if not results or not results[0]:
|
||||
return {
|
||||
'text': '',
|
||||
'confidence': 0.0,
|
||||
'results': [],
|
||||
'error': 'No text detected'
|
||||
}
|
||||
|
||||
text_lines = []
|
||||
all_confidences = []
|
||||
|
||||
for line in results:
|
||||
if len(line) < 2:
|
||||
continue
|
||||
|
||||
box = line[0]
|
||||
|
||||
if isinstance(line[1], (list, tuple)) and len(line[1]) >= 2:
|
||||
text, confidence = line[1][0], line[1][1]
|
||||
else:
|
||||
text, confidence = str(line[1]), 0.0
|
||||
|
||||
text_lines.append(text)
|
||||
all_confidences.append(confidence)
|
||||
|
||||
full_text = '\n'.join(text_lines)
|
||||
avg_confidence = sum(all_confidences) / len(all_confidences) if all_confidences else 0.0
|
||||
|
||||
detailed_results = []
|
||||
for line in results:
|
||||
if len(line) >= 2:
|
||||
box = line[0]
|
||||
if isinstance(line[1], (list, tuple)) and len(line[1]) >= 2:
|
||||
text, confidence = line[1][0], line[1][1]
|
||||
else:
|
||||
text, confidence = str(line[1]), 0.0
|
||||
|
||||
detailed_results.append({
|
||||
'text': text,
|
||||
'confidence': confidence,
|
||||
'bbox': box
|
||||
})
|
||||
|
||||
return {
|
||||
'text': full_text.strip(),
|
||||
'confidence': round(avg_confidence, 4),
|
||||
'results': detailed_results,
|
||||
'line_count': len(detailed_results)
|
||||
}
|
||||
|
||||
def batch_extract(self, image_paths: List[str]) -> List[Dict]:
|
||||
"""Process multiple images"""
|
||||
return [self.extract(path) for path in image_paths]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='PaddleOCR wrapper')
|
||||
parser.add_argument('image', help='Image file to process')
|
||||
parser.add_argument('--lang', default='ch', help='Language code (ch, en, etc.)')
|
||||
parser.add_argument('--verbose', '-v', action='store_true')
|
||||
args = parser.parse_args()
|
||||
|
||||
processor = PaddleOCR(verbose=args.verbose, lang=args.lang)
|
||||
result = processor.extract(args.image)
|
||||
|
||||
print(f"\nText:\n{result['text']}")
|
||||
print(f"\nConfidence: {result['confidence']:.4f}")
|
||||
print(f"Lines detected: {result.get('line_count', 0)}")
|
||||
print(f"Time: {result.get('processing_time_ms', 0):.2f}ms")
|
||||
Reference in New Issue
Block a user