ebhon commited on
Commit
bf07e30
·
verified ·
1 Parent(s): 5ff95a7

Upload 01_See_How_It_Works.py

Browse files
Files changed (1) hide show
  1. pages/01_See_How_It_Works.py +324 -0
pages/01_See_How_It_Works.py ADDED
@@ -0,0 +1,324 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import os
3
+ from PIL import Image
4
+ import torch
5
+ from manga_translator.translator import MangaTextDetector
6
+ import tempfile
7
+ import cv2
8
+ import io
9
+ import numpy as np
10
+ from PIL import ImageDraw, ImageFont
11
+
12
+ # Set page config for wider layout and title
13
+ st.set_page_config(
14
+ page_title="Process Details - Manga Translator",
15
+ page_icon="🔍",
16
+ layout="wide"
17
+ )
18
+
19
+ # Custom CSS to match main page exactly
20
+ st.markdown("""
21
+ <style>
22
+ /* Reset container styles */
23
+ .block-container {
24
+ padding: 2rem 1rem !important;
25
+ max-width: none;
26
+ }
27
+
28
+ /* Main content area */
29
+ .main .block-container {
30
+ padding-left: calc(250px + 1rem) !important;
31
+ }
32
+
33
+ /* Sidebar styling */
34
+ section[data-testid="stSidebar"] {
35
+ width: 250px !important;
36
+ background-color: rgb(240, 242, 246) !important;
37
+ position: fixed !important;
38
+ left: 0 !important;
39
+ top: 0 !important;
40
+ height: 100vh !important;
41
+ }
42
+
43
+ /* Header styling */
44
+ h1 {
45
+ font-weight: 700 !important;
46
+ color: rgb(49, 51, 63) !important;
47
+ margin-bottom: 0.5rem !important;
48
+ font-size: 2.25rem !important;
49
+ text-align: left !important;
50
+ }
51
+
52
+ /* Subheader styling */
53
+ .subheader {
54
+ color: rgb(49, 51, 63);
55
+ font-size: 1rem;
56
+ margin-bottom: 2rem;
57
+ }
58
+
59
+ /* Upload section styling */
60
+ .stUploadButton {
61
+ background-color: white !important;
62
+ border: 1px solid rgb(224, 224, 224) !important;
63
+ border-radius: 0.5rem !important;
64
+ padding: 1rem !important;
65
+ }
66
+
67
+ /* Button styling */
68
+ .stButton button {
69
+ background-color: rgb(255, 75, 75);
70
+ color: white;
71
+ border: none;
72
+ padding: 0.5rem 1rem;
73
+ border-radius: 0.25rem;
74
+ }
75
+
76
+ /* Process section styling */
77
+ .process-section {
78
+ margin-top: 2rem;
79
+ padding: 1.5rem;
80
+ background-color: white;
81
+ border-radius: 0.5rem;
82
+ }
83
+
84
+ /* Step headers */
85
+ .step-header {
86
+ font-size: 1.5rem;
87
+ color: rgb(49, 51, 63);
88
+ margin: 1.5rem 0 1rem 0;
89
+ padding-bottom: 0.5rem;
90
+ border-bottom: 1px solid rgb(224, 224, 224);
91
+ }
92
+
93
+ /* Hide default menu text */
94
+ .css-17lntkn {
95
+ display: none;
96
+ }
97
+ .css-pkbazv {
98
+ display: none;
99
+ }
100
+ </style>
101
+ """, unsafe_allow_html=True)
102
+
103
+ # Initialize session state for storing processed results
104
+ if 'processed_results' not in st.session_state:
105
+ st.session_state.processed_results = {}
106
+
107
+ # Create temp directory if needed
108
+ temp_dir = tempfile.mkdtemp()
109
+
110
+ # Header - now left-aligned like main page
111
+ st.title("See How It Works")
112
+ st.markdown('<div class="subheader">Explore the step-by-step translation process!</div>', unsafe_allow_html=True)
113
+
114
+ def get_font(size):
115
+ """Get font with proper error handling"""
116
+ try:
117
+ return ImageFont.truetype('font/CC Wild Words Roman.ttf', size)
118
+ except:
119
+ try:
120
+ # Fallback to Arial if available
121
+ return ImageFont.truetype('arial.ttf', size)
122
+ except:
123
+ return ImageFont.load_default()
124
+
125
+ def calculate_font_size(text, max_width, max_height):
126
+ """Calculate optimal font size based on text and box dimensions"""
127
+ # Base size calculations
128
+ min_size = 12
129
+ max_size = min(60, int(max_height * 0.8))
130
+
131
+ # Content-specific adjustments
132
+ if any(c in text for c in '!?!?'): # Emphasis characters
133
+ min_size = 16
134
+ max_size = min(max_size, int(max_height * 0.9))
135
+ elif text.isupper():
136
+ max_size = min(max_size, int(max_height * 0.7))
137
+ elif len(text.split()) <= 2:
138
+ min_size = 16
139
+
140
+ # Calculate based on text length and area
141
+ char_count = len(text)
142
+ area = max_width * max_height
143
+ chars_per_area = char_count / (area + 1)
144
+
145
+ # Adjust size based on density
146
+ size_factor = 1.0
147
+ if chars_per_area > 0.01:
148
+ size_factor = 0.8
149
+ elif chars_per_area < 0.005:
150
+ size_factor = 1.2
151
+
152
+ initial_size = int(min(max_width / (char_count * 0.6), max_height * 0.8) * size_factor)
153
+ return max(min_size, min(initial_size, max_size))
154
+
155
+ def process_detailed_image(uploaded_file):
156
+ """Process image and store detailed results in session state."""
157
+ if uploaded_file.name not in st.session_state.processed_results:
158
+ try:
159
+ detector = MangaTextDetector('best.pt')
160
+
161
+ # Save temporary file
162
+ temp_path = os.path.join(temp_dir, uploaded_file.name)
163
+ with open(temp_path, "wb") as f:
164
+ f.write(uploaded_file.getbuffer())
165
+
166
+ # Process image
167
+ image, detections, result_image, processed_regions, translated_image = detector.process_image(temp_path)
168
+
169
+ # Store all results in session state
170
+ st.session_state.processed_results[uploaded_file.name] = {
171
+ 'image': image,
172
+ 'detections': detections,
173
+ 'result_image': result_image,
174
+ 'processed_regions': processed_regions,
175
+ 'translated_image': translated_image
176
+ }
177
+
178
+ # Clean up temp file
179
+ try:
180
+ os.remove(temp_path)
181
+ except:
182
+ pass
183
+
184
+ return True
185
+ except Exception as e:
186
+ st.error(f"❌ Error: {str(e)}")
187
+ return False
188
+ return True
189
+
190
+ # File uploader with clean styling
191
+ uploaded_files = st.file_uploader(
192
+ "Choose manga pages",
193
+ type=['jpg', 'jpeg', 'png'],
194
+ accept_multiple_files=True,
195
+ help="Upload manga pages to see the detailed translation process"
196
+ )
197
+
198
+ if uploaded_files:
199
+ # Process images
200
+ with st.spinner("Processing your manga pages..."):
201
+ for uploaded_file in uploaded_files:
202
+ if process_detailed_image(uploaded_file):
203
+ results = st.session_state.processed_results[uploaded_file.name]
204
+
205
+ st.markdown('<div class="process-section">', unsafe_allow_html=True)
206
+ st.markdown(f"### 📝 Processing: {uploaded_file.name}")
207
+
208
+ # 1. Original Image
209
+ st.markdown('<div class="step-header">1️⃣ Original Image</div>', unsafe_allow_html=True)
210
+ st.image(
211
+ cv2.cvtColor(results['image'], cv2.COLOR_BGR2RGB),
212
+ caption="Original Image",
213
+ use_column_width=True
214
+ )
215
+
216
+ # 2. Text Detection
217
+ st.markdown('<div class="step-header">2️⃣ Text Detection</div>', unsafe_allow_html=True)
218
+ st.write("Detected text regions and speech bubbles are highlighted:")
219
+ st.image(
220
+ cv2.cvtColor(results['result_image'], cv2.COLOR_BGR2RGB),
221
+ caption="Detected Regions",
222
+ use_column_width=True
223
+ )
224
+
225
+ # 3. Detected Text Regions
226
+ st.markdown('<div class="step-header">3️⃣ Detected Text Regions</div>', unsafe_allow_html=True)
227
+ if results['processed_regions'] and results['processed_regions']['text_regions']:
228
+ for i, region in enumerate(results['processed_regions']['text_regions'], 1):
229
+ with st.expander(f"Region {i}"):
230
+ col1, col2 = st.columns(2)
231
+ with col1:
232
+ x1, y1, x2, y2 = region['coords']
233
+ region_img = results['image'][y1:y2, x1:x2]
234
+ st.image(
235
+ cv2.cvtColor(region_img, cv2.COLOR_BGR2RGB),
236
+ caption=f"Region {i}"
237
+ )
238
+
239
+ # Add region statistics
240
+ st.markdown(
241
+ f'<div class="region-stats">'
242
+ f'Region Size: {x2-x1}x{y2-y1} pixels<br>'
243
+ f'Type: {region["type"].capitalize()}<br>'
244
+ f'Text Length: {len(region["text"])} chars'
245
+ f'</div>',
246
+ unsafe_allow_html=True
247
+ )
248
+
249
+ with col2:
250
+ st.markdown("**Japanese Text:**")
251
+ st.code(region['text'])
252
+ if 'translation' in region:
253
+ st.markdown("**English Translation:**")
254
+ st.code(region['translation'])
255
+
256
+ # Show text preview with improved rendering
257
+ preview_height = 100
258
+ preview_width = 400
259
+ preview_img = np.ones((preview_height, preview_width, 3), dtype=np.uint8) * 255
260
+ preview_img = cv2.cvtColor(preview_img, cv2.COLOR_BGR2RGB)
261
+ pil_img = Image.fromarray(preview_img)
262
+ draw = ImageDraw.Draw(pil_img)
263
+
264
+ # Calculate font size based on text and preview dimensions
265
+ text = region['translation']
266
+ font_size = calculate_font_size(text, preview_width * 0.9, preview_height * 0.8)
267
+ font = get_font(font_size)
268
+
269
+ # Center text
270
+ bbox = draw.textbbox((0, 0), text, font=font)
271
+ text_width = bbox[2] - bbox[0]
272
+ text_height = bbox[3] - bbox[1]
273
+ x = (preview_width - text_width) // 2
274
+ y = (preview_height - text_height) // 2
275
+
276
+ # Draw with improved outline
277
+ outline_width = max(1, min(3, int(font_size / 20)))
278
+ for dx in range(-outline_width, outline_width + 1):
279
+ for dy in range(-outline_width, outline_width + 1):
280
+ if dx == 0 and dy == 0:
281
+ continue
282
+ draw.text((x + dx, y + dy), text,
283
+ font=font, fill=(255, 255, 255))
284
+
285
+ draw.text((x, y), text, font=font, fill=(0, 0, 0))
286
+ st.image(pil_img, caption="Text Preview", use_column_width=True)
287
+ else:
288
+ st.warning("No text regions detected in this image.")
289
+
290
+ # 4. Final Translation
291
+ st.markdown('<div class="step-header">4️⃣ Final Translation</div>', unsafe_allow_html=True)
292
+ if results['translated_image'] is not None:
293
+ st.image(
294
+ cv2.cvtColor(results['translated_image'], cv2.COLOR_BGR2RGB),
295
+ caption="Final Translated Image",
296
+ use_column_width=True
297
+ )
298
+
299
+ # Download button with improved styling
300
+ st.markdown('<div class="download-btn">', unsafe_allow_html=True)
301
+ translated_bytes = cv2.imencode('.png', results['translated_image'])[1].tobytes()
302
+ st.download_button(
303
+ label="⬇️ Download Translated Image",
304
+ data=translated_bytes,
305
+ file_name=f"translated_{uploaded_file.name}",
306
+ mime="image/png"
307
+ )
308
+ st.markdown('</div>', unsafe_allow_html=True)
309
+ else:
310
+ st.warning("Translation could not be completed.")
311
+
312
+ st.markdown('</div>', unsafe_allow_html=True)
313
+ st.markdown("---")
314
+
315
+ else:
316
+ st.info("👆 Upload a manga page to see the detailed translation process!")
317
+
318
+ st.subheader("What You'll See")
319
+ st.write("""
320
+ 1. **Original Image**: Your uploaded manga page
321
+ 2. **Text Detection**: View detected text regions and bubbles
322
+ 3. **Detected Text**: See each text region with its translation
323
+ 4. **Final Translation**: The complete translated image
324
+ """)