# ocr_eval_engine.py import jiwer from fuzzywuzzy import fuzz class OCREvaluator: """ 정답(GT) 텍스트와 하나 이상의 예측(Hypothesis) 텍스트를 비교하여 다양한 문자 오류율(CER) 지표를 계산하는 클래스. """ def __init__(self, ground_truth_text: str): """ 평가기 인스턴스를 초기화합니다. :param ground_truth_text: 비교의 기준이 되는 정답 텍스트. """ # 모든 텍스트는 유니코드(UTF-8)로 처리됩니다. self.ground_truth = ground_truth_text def evaluate(self, hypothesis_text: str) -> dict: """ 주어진 예측 텍스트에 대한 모든 평가 지표를 계산합니다. :param hypothesis_text: 평가할 OCR 예측 텍스트. :return: 평가 결과를 담은 딕셔너리. """ strict_results = self._calculate_strict_cer(self.ground_truth, hypothesis_text) flexible_cer = self._calculate_flexible_cer(self.ground_truth, hypothesis_text) results = { "strict_cer": strict_results["cer"], "substitutions": strict_results["S"], "deletions": strict_results["D"], "insertions": strict_results["I"], "hits": strict_results["H"], "flexible_cer": flexible_cer, } return results def _calculate_strict_cer(self, ref: str, hyp: str) -> dict: """ jiwer를 사용하여 엄격한 순서의 CER을 계산합니다. 이 메서드는 레벤슈타인 거리를 기반으로 S, D, I를 계산합니다. :param ref: 정답 텍스트. :param hyp: 예측 텍스트. :return: CER, S, D, I, H(정답) 개수를 포함하는 딕셔너리. """ if not ref: # 정답 텍스트가 비어있는 경우 return {"cer": 1.0 if hyp else 0.0, "S": 0, "D": 0, "I": len(hyp), "H": 0} # jiwer.process_characters는 상세한 오류 분석 결과를 제공합니다. output = jiwer.process_characters(ref, hyp) return { "cer": output.cer, "S": output.substitutions, "D": output.deletions, "I": output.insertions, "H": output.hits, } def _calculate_flexible_cer(self, ref: str, hyp: str) -> float: """ fuzzywuzzy의 token_sort_ratio를 사용하여 순서에 유연한 CER을 계산합니다. 이 메서드는 문자 순서를 무시하고 내용의 유사성을 평가합니다. :param ref: 정답 텍스트. :param hyp: 예측 텍스트. :return: 순서 유연 CER (0.0에서 1.0 사이의 값). """ # token_sort_ratio는 0-100 사이의 유사도 점수를 반환합니다. # 이를 0-1 사이의 오류율로 변환합니다. similarity_ratio = fuzz.token_sort_ratio(ref, hyp) error_rate = (100 - similarity_ratio) / 100.0 return error_rate