videocr/models.py (view raw)
1from __future__ import annotations
2from typing import List
3from dataclasses import dataclass
4from fuzzywuzzy import fuzz
5
6
7CONF_THRESHOLD = 60
8# word predictions with lower confidence will be filtered out
9
10
11@dataclass
12class PredictedWord:
13 __slots__ = 'confidence', 'text'
14 confidence: int
15 text: str
16
17
18class PredictedFrame:
19 index: int # 0-based index of the frame
20 words: List[PredictedWord]
21 confidence: int # total confidence of all words
22 text: str
23
24 def __init__(self, index, pred_data: str):
25 self.index = index
26 self.words = []
27
28 block = 0 # keep track of line breaks
29
30 for l in pred_data.splitlines()[1:]:
31 word_data = l.split()
32 if len(word_data) < 12:
33 # no word is predicted
34 continue
35 _, _, block_num, *_, conf, text = word_data
36 block_num, conf = int(block_num), int(conf)
37
38 # handle line breaks
39 if block < block_num:
40 block = block_num
41 self.words.append(PredictedWord(0, '\n'))
42
43 if conf >= CONF_THRESHOLD:
44 self.words.append(PredictedWord(conf, text))
45
46 self.confidence = sum(word.confidence for word in self.words)
47 self.text = ''.join(word.text + ' ' for word in self.words).strip()
48
49 def is_similar_to(self, other: PredictedFrame, threshold=60) -> bool:
50 if len(self.text) == 0 or len(other.text) == 0:
51 return False
52 return fuzz.ratio(self.text, other.text) >= threshold
53
54
55class PredictedSubtitle:
56 frames: List[PredictedFrame]
57
58 def __init__(self, frames: List[PredictedFrame]):
59 self.frames = [f for f in frames if f.confidence > 0]
60
61 @property
62 def text(self) -> str:
63 if self.frames:
64 conf_max = max(f.confidence for f in self.frames)
65 return next(f.text for f in self.frames if f.confidence == conf_max)
66 return ''
67
68 @property
69 def index_start(self) -> int:
70 if self.frames:
71 return self.frames[0].index
72 return 0
73
74 @property
75 def index_end(self) -> int:
76 if self.frames:
77 return self.frames[-1].index
78 return 0