Nicha1234 commited on
Commit
ebb3617
·
verified ·
1 Parent(s): b8fb806

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -51
app.py CHANGED
@@ -5,8 +5,6 @@ import zipfile
5
  import os
6
  import io
7
  from PIL import Image
8
-
9
- # บังคับให้ Matplotlib ทำงานแบบ Background เพื่อแก้ปัญหาภาพสั่น
10
  import matplotlib
11
  matplotlib.use('Agg')
12
  import matplotlib.pyplot as plt
@@ -36,7 +34,6 @@ st.markdown("""
36
  color: #1565C0;
37
  margin-top: 20px;
38
  }
39
- /* ปรับแต่งปุ่มให้ดูสวยงาม */
40
  div.stButton > button:first-child {
41
  background-color: #f0f2f6;
42
  color: #0D47A1;
@@ -82,7 +79,6 @@ def format_kspace_display(k_data):
82
 
83
  kspace_bg_image = format_kspace_display(kspace_raw)
84
 
85
- # --- ฟังก์ชันแปลงรูปภาพ (ลดการสั่น) ---
86
  def get_image_from_plot(fig):
87
  buf = io.BytesIO()
88
  plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.1, dpi=100)
@@ -139,72 +135,87 @@ def draw_mri(mri_result):
139
  ax.axis('off')
140
  return get_image_from_plot(fig)
141
 
142
- # --- ฟังก์ชันวาดระบบเติม K-Space ทีละบรรทัด (Interactive 3) ---
143
- def draw_gy_sequence(current_step, total_steps):
144
- # กราฟแสดง Phase Encoding (Gy) ด้านซ้าย
145
- fig, ax = plt.subplots(figsize=(3, 4))
146
 
147
- # วาดแกน
148
- ax.axhline(0, color='black', lw=1.5)
149
- ax.axvline(0, color='black', lw=1.5)
 
 
 
150
 
151
- y_vals = np.linspace(1, -1, total_steps)
 
 
 
 
 
 
 
 
152
 
153
- for i, y in enumerate(y_vals):
154
- # ไฮไลต์บรรทัดที่กำลังทำงานให้เป็นสีแดงและหนาขึ้น
 
 
 
 
155
  if i == current_step:
156
- ax.plot([0.1, 0.9], [y, y], color='red', lw=4)
157
  elif i < current_step:
158
- ax.plot([0.1, 0.9], [y, y], color='gray', lw=2, alpha=0.5)
159
  else:
160
- ax.plot([0.1, 0.9], [y, y], color='blue', lw=2)
161
-
162
- ax.set_xlim(-0.1, 1.1)
163
- ax.set_ylim(-1.2, 1.2)
164
- ax.set_title("Gy (Phase Encoding)", fontweight='bold')
 
 
 
 
165
  ax.axis('off')
 
 
166
  return get_image_from_plot(fig)
167
 
168
  def draw_kspace_filling(current_step, total_steps, mode_type, real_bg):
169
- # กราฟแสดง K-Space ที่ค่อยๆ ถูกเติม
170
- fig, ax = plt.subplots(figsize=(4, 4))
171
-
172
- # สร้างภาพเปล่าสีดำ
173
  display_img = np.zeros((224, 224))
174
-
175
- # คำนวณขอบเขตบรรทัดที่จะเติม
176
  lines_per_step = 224 // total_steps
177
  current_line_idx = current_step * lines_per_step
178
 
179
  if mode_type == "ข้อมูลจำลอง (Simulated)":
180
- # สร้างภาพเส้นจำลองสีเหลืองแนวนอน
181
  Y, X = np.ogrid[:224, :224]
182
- # จำลองสัญญาณให้ตรงกลางสว่าง ขอบมืด
183
  intensity = np.exp(-((Y - 112)**2) / (2 * 50**2))
184
  for i in range(current_line_idx + lines_per_step):
185
  display_img[i, :] = intensity[i, 0] * 255
186
-
187
  ax.imshow(display_img, cmap='inferno', extent=[-112, 112, -112, 112], vmin=0, vmax=255)
188
  else:
189
- # ใช้ข้อมูล kspace.mat จริง
190
  if current_step >= total_steps - 1:
191
  display_img = real_bg
192
  else:
193
  display_img[:current_line_idx + lines_per_step, :] = real_bg[:current_line_idx + lines_per_step, :]
194
-
195
  ax.imshow(display_img, cmap='gray', extent=[-112, 112, -112, 112], vmin=0, vmax=1)
196
 
197
  ax.set_xlim(-112, 112)
198
- ax.set_ylim(112, -112) # Invert Y axis ให้เติมจากบนลงล่างตามกราฟ Gy
 
 
 
 
 
199
  ax.axhline(0, color='white', linewidth=0.5, linestyle='--')
200
  ax.axvline(0, color='white', linewidth=0.5, linestyle='--')
201
  ax.set_title("K-Space Filling", fontweight='bold')
202
  ax.axis('off')
203
  return get_image_from_plot(fig)
204
 
205
-
206
  # ==========================================================
207
- # --- 3. ส่วนแสดงผลเว็บ (ใช้ Container บีบขอบซ้าย-ขวา) ---
208
  # ==========================================================
209
 
210
  _, col_main, _ = st.columns([1, 6, 1])
@@ -230,16 +241,21 @@ with col_main:
230
  st.image("Screenshot 2026-05-07 205051.png", use_container_width=True)
231
  elif os.path.exists("Screenshot 2026-05-07 205051.jpg"):
232
  st.image("Screenshot 2026-05-07 205051.jpg", use_container_width=True)
233
- else:
234
- st.info("กรุณาอัปโหลดรูปภาพ Screenshot 2026-05-07 205051 (เป็น .png หรือ .jpg ก็ได้)")
235
 
236
  # ---------------------------------------------------------
237
- # NEW INTERACTIVE: การเติม K-Space ทีละบรรทัด (Line-by-Line Filling)
238
  # ---------------------------------------------------------
239
- st.markdown("### 🎛จำลองการเติมข้อมูล K-Space ตามรอบของ Phase Encoding (Gy)")
240
- st.markdown("สังเกตการทำงานของเกรเดียนท์ Gy ด้านซ้าย ว่าในแต่ละรอบการกระตุ้น (TR) จะดึงข้อมูลมาเติมใน K-Space ทีละบรรทัดอย่างไร")
241
-
242
- # State Management สำหรับการควบคุมแอนิเมชัน
 
 
 
 
 
 
 
243
  total_anim_steps = 15
244
  if 'fill_step' not in st.session_state:
245
  st.session_state.fill_step = 0
@@ -259,11 +275,11 @@ with col_main:
259
  st.session_state.fill_step = 0
260
 
261
  # แถบควบค���มบน
262
- _, col_ctrl1, col_ctrl2, _ = st.columns([1, 2, 2, 1])
263
  with col_ctrl1:
264
- data_mode = st.radio("เลือกรูปแบบข้อมูลแสดงผล:", ["ข้อมูลจำลอง (Simulated)", "ข้อมูลจริง (kspace.mat)"])
265
  with col_ctrl2:
266
- st.write("ควบคุมการเติมบรรทัด:")
267
  c1, c2, c3, c4 = st.columns(4)
268
  c1.button("⏮ Reset", on_click=reset_anim)
269
  c2.button("◀ ก่อนหน้า", on_click=step_backward)
@@ -272,12 +288,14 @@ with col_main:
272
 
273
  st.progress((st.session_state.fill_step + 1) / total_anim_steps)
274
 
275
- # สดงผลรูปภาพ
276
- _, col_anim1, col_anim2, _ = st.columns([1.5, 2, 3, 1.5])
277
- with col_anim1:
278
- st.image(draw_gy_sequence(st.session_state.fill_step, total_anim_steps), use_container_width=True)
279
- with col_anim2:
280
- st.image(draw_kspace_filling(st.session_state.fill_step, total_anim_steps, data_mode, kspace_bg_image), use_container_width=True)
 
 
281
 
282
 
283
  st.markdown("---")
 
5
  import os
6
  import io
7
  from PIL import Image
 
 
8
  import matplotlib
9
  matplotlib.use('Agg')
10
  import matplotlib.pyplot as plt
 
34
  color: #1565C0;
35
  margin-top: 20px;
36
  }
 
37
  div.stButton > button:first-child {
38
  background-color: #f0f2f6;
39
  color: #0D47A1;
 
79
 
80
  kspace_bg_image = format_kspace_display(kspace_raw)
81
 
 
82
  def get_image_from_plot(fig):
83
  buf = io.BytesIO()
84
  plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.1, dpi=100)
 
135
  ax.axis('off')
136
  return get_image_from_plot(fig)
137
 
138
+ # --- ฟังก์ชันวาดาฟ Pulse Sequence (RF, Gx, Gy, Echo) ---
139
+ def draw_pulse_sequence(current_step, total_steps):
140
+ fig, axes = plt.subplots(4, 1, figsize=(5, 6), gridspec_kw={'height_ratios': [1, 1, 1.5, 1]})
141
+ t = np.linspace(0, 10, 500)
142
 
143
+ # 1. RF
144
+ ax = axes[0]
145
+ rf = np.sinc(t - 2) * (t > 0) * (t < 4)
146
+ ax.plot(t, rf, color='black', lw=2)
147
+ ax.text(0, 0.5, 'RF', fontsize=14, fontweight='bold', va='center', ha='right', transform=ax.get_yaxis_transform())
148
+ ax.axis('off')
149
 
150
+ # 2. Gx (Frequency Encoding)
151
+ ax = axes[1]
152
+ gx = np.zeros_like(t)
153
+ gx[(t > 4.5) & (t < 5.5)] = -1 # Dephase
154
+ gx[(t > 6) & (t < 9)] = 1 # Readout
155
+ ax.plot(t, gx, color='black', lw=2)
156
+ ax.fill_between(t, gx, 0, alpha=0.3, color='gray')
157
+ ax.text(0, 0, 'Gx', fontsize=14, fontweight='bold', va='center', ha='right', transform=ax.get_yaxis_transform())
158
+ ax.axis('off')
159
 
160
+ # 3. Gy (Phase Encoding)
161
+ ax = axes[2]
162
+ gy_vals = np.linspace(1, -1, total_steps)
163
+ for i, gy_amp in enumerate(gy_vals):
164
+ gy = np.zeros_like(t)
165
+ gy[(t > 4.5) & (t < 5.5)] = gy_amp
166
  if i == current_step:
167
+ ax.plot(t, gy, color='red', lw=3, zorder=10) # ไฮไลต์เส้นปัจจุบัน
168
  elif i < current_step:
169
+ ax.plot(t, gy, color='gray', lw=1, alpha=0.5)
170
  else:
171
+ ax.plot(t, gy, color='blue', lw=1, alpha=0.3)
172
+ ax.text(0, 0, 'Gy', fontsize=14, fontweight='bold', va='center', ha='right', transform=ax.get_yaxis_transform())
173
+ ax.axis('off')
174
+
175
+ # 4. Echo
176
+ ax = axes[3]
177
+ echo = np.sinc(t - 7.5) * (t > 6) * (t < 9)
178
+ ax.plot(t, echo, color='black', lw=2)
179
+ ax.text(0, 0.5, 'Echo', fontsize=14, fontweight='bold', va='center', ha='right', transform=ax.get_yaxis_transform())
180
  ax.axis('off')
181
+
182
+ plt.tight_layout()
183
  return get_image_from_plot(fig)
184
 
185
  def draw_kspace_filling(current_step, total_steps, mode_type, real_bg):
186
+ fig, ax = plt.subplots(figsize=(5, 6))
 
 
 
187
  display_img = np.zeros((224, 224))
 
 
188
  lines_per_step = 224 // total_steps
189
  current_line_idx = current_step * lines_per_step
190
 
191
  if mode_type == "ข้อมูลจำลอง (Simulated)":
 
192
  Y, X = np.ogrid[:224, :224]
 
193
  intensity = np.exp(-((Y - 112)**2) / (2 * 50**2))
194
  for i in range(current_line_idx + lines_per_step):
195
  display_img[i, :] = intensity[i, 0] * 255
 
196
  ax.imshow(display_img, cmap='inferno', extent=[-112, 112, -112, 112], vmin=0, vmax=255)
197
  else:
 
198
  if current_step >= total_steps - 1:
199
  display_img = real_bg
200
  else:
201
  display_img[:current_line_idx + lines_per_step, :] = real_bg[:current_line_idx + lines_per_step, :]
 
202
  ax.imshow(display_img, cmap='gray', extent=[-112, 112, -112, 112], vmin=0, vmax=1)
203
 
204
  ax.set_xlim(-112, 112)
205
+ ax.set_ylim(112, -112) # วาดจากบนลงล่าง
206
+
207
+ # วาดลูกศรชี้ว่ากำลังเติมบรรทัดไหน
208
+ y_pos = 112 - (current_line_idx + lines_per_step//2)
209
+ ax.annotate('', xy=(0, y_pos), xytext=(-100, y_pos), arrowprops=dict(arrowstyle='->', color='red', lw=3))
210
+
211
  ax.axhline(0, color='white', linewidth=0.5, linestyle='--')
212
  ax.axvline(0, color='white', linewidth=0.5, linestyle='--')
213
  ax.set_title("K-Space Filling", fontweight='bold')
214
  ax.axis('off')
215
  return get_image_from_plot(fig)
216
 
 
217
  # ==========================================================
218
+ # --- 3. ส่วนแสดงผลเว็บ ---
219
  # ==========================================================
220
 
221
  _, col_main, _ = st.columns([1, 6, 1])
 
241
  st.image("Screenshot 2026-05-07 205051.png", use_container_width=True)
242
  elif os.path.exists("Screenshot 2026-05-07 205051.jpg"):
243
  st.image("Screenshot 2026-05-07 205051.jpg", use_container_width=True)
 
 
244
 
245
  # ---------------------------------------------------------
246
+ # NEW: K-Space Trajectories (การบันทึกข้อมูล)
247
  # ---------------------------------------------------------
248
+ st.markdown("## 🛤️ K-Space Trajectories")
249
+ st.markdown("""
250
+ **การบันทึกข้อมูลลงใน K-space สามารถทำได้หลายรูปแบบ** โดยจะยกตัวอย่างให้การเก็บข้อมูลจะดำเนินไปทีละบรรทัด โดยสัญญาณจะเกิดขึ้นหลังจากกระตุ้นด้วย RF Pulse โดยมีลำดับดังนี้
251
+
252
+ 1. กระบวนการเริ่มต้นขึ้นเมื่อสนามแม่เหล็กเกรเดียนท์ **Gx** และ **Gy** เริ่มทำงานพร้อมกันเพื่อสร้างพิกัดอ้างอิง
253
+ 2. ระบบจะเริ่มบันทึกข้อมูลจุดแรกของเฟสในแถวที่ 1 โดยจะเริ่มต้นที่ค่าแอมปลิจูดของ **Gy ทางฝั่งบวกก่อน**
254
+ 3. สัญญาณจะถูกบันทึกไล่ไปตามแกน Gx จนได้ข้อมูลครบถ้วนเต็ม 1 แถว
255
+ 4. เมื่อจบแถวแรก ระบบจะเริ่มกระบวนการใหม่เพื่อบันทึกข้อมูลในเฟสแถวที่ 2, 3, 4 ต่อไปเรื่อยๆ
256
+ 5. การวนรอบนี้จะดำเนินต่อไปพร้อมกับการเปลี่ยนค่า **Gy ให้ลดลงจนไปถึงค่าทางฝั่งลบ** เมื่อบันทึกครบทุกแถวตามจำนวนความละเอียดที่ตั้งไว้ จะถือว่าสิ้นสุดกระบวนการเก็บข้อมูล MRI แบบสองมิติลงบน K-space
257
+ """)
258
+
259
  total_anim_steps = 15
260
  if 'fill_step' not in st.session_state:
261
  st.session_state.fill_step = 0
 
275
  st.session_state.fill_step = 0
276
 
277
  # แถบควบค���มบน
278
+ _, col_ctrl1, col_ctrl2, _ = st.columns([0.5, 2.5, 2.5, 0.5])
279
  with col_ctrl1:
280
+ data_mode = st.radio("เลือกรูปแบบ K-Space:", ["ข้อมูลจำลอง (Simulated)", "ข้อมูลจริง (kspace.mat)"])
281
  with col_ctrl2:
282
+ st.write("ควบคุมการเติมบรรทัด (Gy):")
283
  c1, c2, c3, c4 = st.columns(4)
284
  c1.button("⏮ Reset", on_click=reset_anim)
285
  c2.button("◀ ก่อนหน้า", on_click=step_backward)
 
288
 
289
  st.progress((st.session_state.fill_step + 1) / total_anim_steps)
290
 
291
+ # ใช้ Placeholder เพื่อลดการั่นกระตุกตอนวาดรูปใหม่
292
+ anim_placeholder = st.empty()
293
+ with anim_placeholder.container():
294
+ col_anim1, col_anim2 = st.columns([1, 1])
295
+ with col_anim1:
296
+ st.image(draw_pulse_sequence(st.session_state.fill_step, total_anim_steps), use_container_width=True)
297
+ with col_anim2:
298
+ st.image(draw_kspace_filling(st.session_state.fill_step, total_anim_steps, data_mode, kspace_bg_image), use_container_width=True)
299
 
300
 
301
  st.markdown("---")