244 lines
9.5 KiB
Python
244 lines
9.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
ONNX vs PaddlePaddle 상세 텍스트 결과 비교
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import time
|
|
import logging
|
|
from typing import Dict, List
|
|
|
|
# 모듈 경로 추가
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))
|
|
|
|
# 가짜 GPU 매니저 및 로거 클래스
|
|
class MockGPUManager:
|
|
def __init__(self, can_use_cuda=True):
|
|
self.can_use_cuda = can_use_cuda
|
|
|
|
class MockLogger:
|
|
def log(self, message: str, level=logging.INFO, exc_info=False):
|
|
pass # 조용한 로거
|
|
|
|
def compare_ocr_results():
|
|
"""ONNX와 PaddlePaddle OCR 결과 상세 비교"""
|
|
print("🔍 ONNX vs PaddlePaddle 텍스트 감지 결과 상세 비교")
|
|
print("=" * 70)
|
|
|
|
test_image = os.path.join(os.path.dirname(__file__), "1.jpg")
|
|
if not os.path.exists(test_image):
|
|
print(f"❌ 테스트 이미지를 찾을 수 없습니다: {test_image}")
|
|
return
|
|
|
|
logger = MockLogger()
|
|
gpu_manager = MockGPUManager(can_use_cuda=True)
|
|
|
|
# 1. ONNX CPU 결과 수집
|
|
print("\n🔧 ONNX CPU 결과 수집 중...")
|
|
try:
|
|
from onnx_ocr_module import ONNXOCRModule
|
|
|
|
ocr_onnx_cpu = ONNXOCRModule(
|
|
logger=logger,
|
|
gpu_manager=gpu_manager,
|
|
execution_provider='cpu'
|
|
)
|
|
|
|
start_time = time.time()
|
|
onnx_cpu_results = ocr_onnx_cpu.detect_text(test_image)
|
|
onnx_cpu_time = (time.time() - start_time) * 1000
|
|
|
|
print(f"✅ ONNX CPU: {len(onnx_cpu_results)}개 텍스트, {onnx_cpu_time:.1f}ms")
|
|
|
|
except Exception as e:
|
|
print(f"❌ ONNX CPU 실패: {e}")
|
|
onnx_cpu_results = []
|
|
onnx_cpu_time = 0
|
|
|
|
# 2. ONNX CUDA 결과 수집
|
|
print("\n🚀 ONNX CUDA 결과 수집 중...")
|
|
try:
|
|
ocr_onnx_cuda = ONNXOCRModule(
|
|
logger=logger,
|
|
gpu_manager=gpu_manager,
|
|
execution_provider='cuda'
|
|
)
|
|
|
|
start_time = time.time()
|
|
onnx_cuda_results = ocr_onnx_cuda.detect_text(test_image)
|
|
onnx_cuda_time = (time.time() - start_time) * 1000
|
|
|
|
print(f"✅ ONNX CUDA: {len(onnx_cuda_results)}개 텍스트, {onnx_cuda_time:.1f}ms")
|
|
|
|
except Exception as e:
|
|
print(f"❌ ONNX CUDA 실패: {e}")
|
|
onnx_cuda_results = []
|
|
onnx_cuda_time = 0
|
|
|
|
# 3. PaddlePaddle CPU 결과 수집
|
|
print("\n🐼 PaddlePaddle CPU 결과 수집 중...")
|
|
try:
|
|
from paddleocr import PaddleOCR
|
|
|
|
ocr_paddle_cpu = PaddleOCR(use_gpu=False, use_angle_cls=True, lang='ch', show_log=False)
|
|
|
|
start_time = time.time()
|
|
paddle_cpu_raw = ocr_paddle_cpu.ocr(test_image)
|
|
paddle_cpu_time = (time.time() - start_time) * 1000
|
|
|
|
# PaddleOCR 결과 파싱
|
|
paddle_cpu_results = []
|
|
if paddle_cpu_raw and paddle_cpu_raw[0]:
|
|
for i, line in enumerate(paddle_cpu_raw[0]):
|
|
if len(line) >= 2:
|
|
polygon = line[0]
|
|
text = line[1][0]
|
|
confidence = line[1][1]
|
|
|
|
# 바운딩 박스 계산
|
|
import numpy as np
|
|
import cv2
|
|
polygon_np = np.array(polygon, dtype=np.int32)
|
|
x, y, w, h = cv2.boundingRect(polygon_np)
|
|
|
|
paddle_cpu_results.append({
|
|
'text': text,
|
|
'confidence': confidence,
|
|
'polygon': polygon,
|
|
'bbox': (x, y, w, h),
|
|
'method': 'paddle'
|
|
})
|
|
|
|
print(f"✅ Paddle CPU: {len(paddle_cpu_results)}개 텍스트, {paddle_cpu_time:.1f}ms")
|
|
|
|
except Exception as e:
|
|
print(f"❌ PaddlePaddle CPU 실패: {e}")
|
|
paddle_cpu_results = []
|
|
paddle_cpu_time = 0
|
|
|
|
# 4. PaddlePaddle CUDA 결과 수집
|
|
print("\n🐼🚀 PaddlePaddle CUDA 결과 수집 중...")
|
|
try:
|
|
ocr_paddle_cuda = PaddleOCR(use_gpu=True, use_angle_cls=True, lang='ch', show_log=False)
|
|
|
|
start_time = time.time()
|
|
paddle_cuda_raw = ocr_paddle_cuda.ocr(test_image)
|
|
paddle_cuda_time = (time.time() - start_time) * 1000
|
|
|
|
# PaddleOCR 결과 파싱
|
|
paddle_cuda_results = []
|
|
if paddle_cuda_raw and paddle_cuda_raw[0]:
|
|
for i, line in enumerate(paddle_cuda_raw[0]):
|
|
if len(line) >= 2:
|
|
polygon = line[0]
|
|
text = line[1][0]
|
|
confidence = line[1][1]
|
|
|
|
# 바운딩 박스 계산
|
|
import numpy as np
|
|
import cv2
|
|
polygon_np = np.array(polygon, dtype=np.int32)
|
|
x, y, w, h = cv2.boundingRect(polygon_np)
|
|
|
|
paddle_cuda_results.append({
|
|
'text': text,
|
|
'confidence': confidence,
|
|
'polygon': polygon,
|
|
'bbox': (x, y, w, h),
|
|
'method': 'paddle'
|
|
})
|
|
|
|
print(f"✅ Paddle CUDA: {len(paddle_cuda_results)}개 텍스트, {paddle_cuda_time:.1f}ms")
|
|
|
|
except Exception as e:
|
|
print(f"❌ PaddlePaddle CUDA 실패: {e}")
|
|
paddle_cuda_results = []
|
|
paddle_cuda_time = 0
|
|
|
|
# 5. 결과 상세 비교
|
|
print("\n" + "="*70)
|
|
print("📊 텍스트 감지 결과 상세 비교")
|
|
print("="*70)
|
|
|
|
# 성능 비교
|
|
print(f"\n⚡ 성능 비교:")
|
|
print(f"{'모델':<20} {'시간(ms)':<12} {'텍스트 수':<10}")
|
|
print("-" * 42)
|
|
print(f"{'ONNX CPU':<20} {onnx_cpu_time:<12.1f} {len(onnx_cpu_results):<10}")
|
|
print(f"{'ONNX CUDA':<20} {onnx_cuda_time:<12.1f} {len(onnx_cuda_results):<10}")
|
|
print(f"{'Paddle CPU':<20} {paddle_cpu_time:<12.1f} {len(paddle_cpu_results):<10}")
|
|
print(f"{'Paddle CUDA':<20} {paddle_cuda_time:<12.1f} {len(paddle_cuda_results):<10}")
|
|
|
|
# 텍스트 내용 비교 (ONNX CUDA vs Paddle CUDA)
|
|
print(f"\n📝 텍스트 내용 상세 비교 (ONNX CUDA vs Paddle CUDA):")
|
|
print("-" * 70)
|
|
|
|
if onnx_cuda_results and paddle_cuda_results:
|
|
print(f"\n🔧 ONNX CUDA 감지 텍스트 ({len(onnx_cuda_results)}개):")
|
|
for i, result in enumerate(onnx_cuda_results, 1):
|
|
text = result['text']
|
|
conf = result['confidence']
|
|
bbox = result['bbox']
|
|
print(f" {i:2d}. '{text}' (신뢰도: {conf:.3f}, 위치: {bbox})")
|
|
|
|
print(f"\n🐼 Paddle CUDA 감지 텍스트 ({len(paddle_cuda_results)}개):")
|
|
for i, result in enumerate(paddle_cuda_results, 1):
|
|
text = result['text']
|
|
conf = result['confidence']
|
|
bbox = result['bbox']
|
|
print(f" {i:2d}. '{text}' (신뢰도: {conf:.3f}, 위치: {bbox})")
|
|
|
|
# 텍스트 세트 비교
|
|
onnx_texts = set(r['text'] for r in onnx_cuda_results if r['text'].strip())
|
|
paddle_texts = set(r['text'] for r in paddle_cuda_results if r['text'].strip())
|
|
|
|
# ONNX에만 있는 텍스트
|
|
onnx_only = onnx_texts - paddle_texts
|
|
if onnx_only:
|
|
print(f"\n🆕 ONNX에서만 발견된 텍스트 ({len(onnx_only)}개):")
|
|
for text in sorted(onnx_only):
|
|
# 해당 텍스트의 신뢰도와 위치 찾기
|
|
for result in onnx_cuda_results:
|
|
if result['text'] == text:
|
|
print(f" - '{text}' (신뢰도: {result['confidence']:.3f}, 위치: {result['bbox']})")
|
|
break
|
|
|
|
# Paddle에만 있는 텍스트
|
|
paddle_only = paddle_texts - onnx_texts
|
|
if paddle_only:
|
|
print(f"\n🆕 Paddle에서만 발견된 텍스트 ({len(paddle_only)}개):")
|
|
for text in sorted(paddle_only):
|
|
# 해당 텍스트의 신뢰도와 위치 찾기
|
|
for result in paddle_cuda_results:
|
|
if result['text'] == text:
|
|
print(f" - '{text}' (신뢰도: {result['confidence']:.3f}, 위치: {result['bbox']})")
|
|
break
|
|
|
|
# 공통 텍스트
|
|
common_texts = onnx_texts & paddle_texts
|
|
if common_texts:
|
|
print(f"\n🤝 공통으로 발견된 텍스트 ({len(common_texts)}개):")
|
|
for text in sorted(common_texts):
|
|
# 신뢰도 비교
|
|
onnx_conf = next((r['confidence'] for r in onnx_cuda_results if r['text'] == text), 0)
|
|
paddle_conf = next((r['confidence'] for r in paddle_cuda_results if r['text'] == text), 0)
|
|
|
|
conf_diff = onnx_conf - paddle_conf
|
|
conf_symbol = "🟢" if conf_diff > 0.1 else "🔴" if conf_diff < -0.1 else "🟡"
|
|
|
|
print(f" {conf_symbol} '{text}' | ONNX: {onnx_conf:.3f} vs Paddle: {paddle_conf:.3f} (차이: {conf_diff:+.3f})")
|
|
|
|
print("\n🎯 분석 결론:")
|
|
if len(onnx_cuda_results) > len(paddle_cuda_results):
|
|
diff = len(onnx_cuda_results) - len(paddle_cuda_results)
|
|
print(f"✅ ONNX가 {diff}개 더 많은 텍스트를 감지했습니다!")
|
|
elif len(paddle_cuda_results) > len(onnx_cuda_results):
|
|
diff = len(paddle_cuda_results) - len(onnx_cuda_results)
|
|
print(f"⚠️ Paddle이 {diff}개 더 많은 텍스트를 감지했습니다.")
|
|
else:
|
|
print("🟰 두 모델이 동일한 수의 텍스트를 감지했습니다.")
|
|
|
|
if __name__ == "__main__":
|
|
compare_ocr_results()
|