Wahso commited on
Commit
01c8adf
·
verified ·
1 Parent(s): be0c010

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +173 -0
app.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import pytesseract
3
+ import numpy as np
4
+ from dataclasses import dataclass
5
+ from typing import List
6
+
7
+ # -----------------------------
8
+ # CONFIGURATION
9
+ # -----------------------------
10
+
11
+ OCR_LANG_MAP = {
12
+ "english": "eng",
13
+ "japanese": "jpn",
14
+ "korean": "kor",
15
+ "chinese_simplified": "chi_sim",
16
+ "chinese_traditional": "chi_tra",
17
+ "thai": "tha"
18
+ }
19
+
20
+ FRAME_SAMPLE_RATE = 1 # OCR every N frames (1 = every frame)
21
+ TEXT_STABILITY_FRAMES = 3 # frames needed to confirm subtitle change
22
+
23
+ # -----------------------------
24
+ # DATA STRUCTURES
25
+ # -----------------------------
26
+
27
+ @dataclass
28
+ class SubtitleLine:
29
+ text: str
30
+ start_time: float
31
+ end_time: float
32
+ status: str # entered | active | exited
33
+
34
+
35
+ # -----------------------------
36
+ # UTILITY FUNCTIONS
37
+ # -----------------------------
38
+
39
+ def sec_to_srt_time(seconds: float) -> str:
40
+ ms = int((seconds % 1) * 1000)
41
+ s = int(seconds) % 60
42
+ m = (int(seconds) // 60) % 60
43
+ h = int(seconds) // 3600
44
+ return f"{h:02}:{m:02}:{s:02},{ms:03}"
45
+
46
+
47
+ def clean_text(text: str) -> str:
48
+ return text.strip().replace("\n", " ")
49
+
50
+
51
+ # -----------------------------
52
+ # OCR ENGINE
53
+ # -----------------------------
54
+
55
+ def ocr_image(image, lang_code):
56
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
57
+ gray = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)[1]
58
+
59
+ config = "--psm 6"
60
+ text = pytesseract.image_to_string(gray, lang=lang_code, config=config)
61
+ return clean_text(text)
62
+
63
+
64
+ # -----------------------------
65
+ # MAIN VIDEO OCR FUNCTION
66
+ # -----------------------------
67
+
68
+ def extract_subtitles(
69
+ video_path: str,
70
+ x: int, y: int, w: int, h: int,
71
+ start_time: float,
72
+ end_time: float,
73
+ language: str
74
+ ) -> List[SubtitleLine]:
75
+
76
+ cap = cv2.VideoCapture(video_path)
77
+ fps = cap.get(cv2.CAP_PROP_FPS)
78
+
79
+ start_frame = int(start_time * fps)
80
+ end_frame = int(end_time * fps)
81
+
82
+ cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)
83
+
84
+ lang_code = OCR_LANG_MAP[language]
85
+
86
+ subtitles = []
87
+ last_text = ""
88
+ stable_count = 0
89
+ active_sub = None
90
+
91
+ frame_idx = start_frame
92
+
93
+ while cap.isOpened() and frame_idx <= end_frame:
94
+ ret, frame = cap.read()
95
+ if not ret:
96
+ break
97
+
98
+ if frame_idx % FRAME_SAMPLE_RATE != 0:
99
+ frame_idx += 1
100
+ continue
101
+
102
+ crop = frame[y:y+h, x:x+w]
103
+ text = ocr_image(crop, lang_code)
104
+
105
+ current_time = frame_idx / fps
106
+
107
+ if text and text != last_text:
108
+ stable_count += 1
109
+ else:
110
+ stable_count = 0
111
+
112
+ if stable_count >= TEXT_STABILITY_FRAMES:
113
+ # Exit previous subtitle
114
+ if active_sub:
115
+ active_sub.end_time = current_time
116
+ active_sub.status = "exited"
117
+ subtitles.append(active_sub)
118
+
119
+ # Enter new subtitle
120
+ active_sub = SubtitleLine(
121
+ text=text,
122
+ start_time=current_time,
123
+ end_time=current_time,
124
+ status="entered"
125
+ )
126
+ last_text = text
127
+ stable_count = 0
128
+
129
+ if active_sub:
130
+ active_sub.status = "active"
131
+ active_sub.end_time = current_time
132
+
133
+ frame_idx += 1
134
+
135
+ # Close last subtitle
136
+ if active_sub:
137
+ active_sub.status = "exited"
138
+ subtitles.append(active_sub)
139
+
140
+ cap.release()
141
+ return subtitles
142
+
143
+
144
+ # -----------------------------
145
+ # EXPORT SRT
146
+ # -----------------------------
147
+
148
+ def export_srt(subtitles: List[SubtitleLine], output_path: str):
149
+ with open(output_path, "w", encoding="utf-8") as f:
150
+ for i, sub in enumerate(subtitles, 1):
151
+ f.write(f"{i}\n")
152
+ f.write(
153
+ f"{sec_to_srt_time(sub.start_time)} --> "
154
+ f"{sec_to_srt_time(sub.end_time)}\n"
155
+ )
156
+ f.write(f"{sub.text}\n\n")
157
+
158
+
159
+ # -----------------------------
160
+ # EXAMPLE USAGE
161
+ # -----------------------------
162
+
163
+ if __name__ == "__main__":
164
+ subs = extract_subtitles(
165
+ video_path="input.mp4",
166
+ x=200, y=400, w=800, h=150, # subtitle box
167
+ start_time=10.0,
168
+ end_time=120.0,
169
+ language="chinese_simplified"
170
+ )
171
+
172
+ export_srt(subs, "output.srt")
173
+ print("✅ Subtitle extraction completed.")