Update app.py
Browse files
app.py
CHANGED
|
@@ -135,7 +135,6 @@ def draw_mri(mri_result):
|
|
| 135 |
ax.axis('off')
|
| 136 |
return get_image_from_plot(fig)
|
| 137 |
|
| 138 |
-
# --- ฟังก์ชันวาดกราฟ Pulse Sequence ---
|
| 139 |
def draw_pulse_sequence(current_step, total_steps):
|
| 140 |
fig, axes = plt.subplots(4, 1, figsize=(5, 6), sharex=True, gridspec_kw={'height_ratios': [1, 1.5, 1, 1]})
|
| 141 |
t = np.linspace(0, 10, 1000)
|
|
@@ -150,7 +149,7 @@ def draw_pulse_sequence(current_step, total_steps):
|
|
| 150 |
ax.text(0, 0.5, 'RF', fontsize=14, fontweight='bold', va='center', ha='right', transform=ax.get_yaxis_transform())
|
| 151 |
ax.axis('off')
|
| 152 |
|
| 153 |
-
# 2. Gy
|
| 154 |
ax = axes[1]
|
| 155 |
gy_vals = np.linspace(1, -1, total_steps)
|
| 156 |
for i, gy_amp in enumerate(gy_vals):
|
|
@@ -163,7 +162,7 @@ def draw_pulse_sequence(current_step, total_steps):
|
|
| 163 |
ax.text(0, 0, 'Gy', fontsize=14, fontweight='bold', va='center', ha='right', transform=ax.get_yaxis_transform())
|
| 164 |
ax.axis('off')
|
| 165 |
|
| 166 |
-
# 3. Gx
|
| 167 |
ax = axes[2]
|
| 168 |
gx = np.zeros_like(t)
|
| 169 |
gx[(t > 2.5) & (t < 3.5)] = -0.5
|
|
@@ -184,54 +183,62 @@ def draw_pulse_sequence(current_step, total_steps):
|
|
| 184 |
plt.tight_layout()
|
| 185 |
return get_image_from_plot(fig)
|
| 186 |
|
| 187 |
-
# --- ฟังก์ชัน
|
| 188 |
def draw_kspace_filling(current_step, total_steps, mode_type, real_bg):
|
| 189 |
fig, ax = plt.subplots(figsize=(5, 6))
|
| 190 |
-
display_img = np.zeros((224, 224))
|
| 191 |
-
|
| 192 |
-
step_size = 224 / total_steps
|
| 193 |
|
| 194 |
if mode_type == "ข้อมูลจำลอง (Simulated)":
|
| 195 |
-
# สร้าง
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
|
|
|
|
|
|
| 214 |
|
| 215 |
-
ax.
|
|
|
|
|
|
|
| 216 |
else:
|
| 217 |
-
# โหมดข้อมูลจริง
|
|
|
|
|
|
|
|
|
|
| 218 |
if current_step >= total_steps - 1:
|
| 219 |
display_img = real_bg
|
| 220 |
else:
|
| 221 |
current_line_idx = int(current_step * step_size)
|
|
|
|
| 222 |
display_img[:current_line_idx + int(step_size), :] = real_bg[:current_line_idx + int(step_size), :]
|
| 223 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
|
| 225 |
-
ax.set_xlim(-112, 112)
|
| 226 |
-
ax.set_ylim(112, -112) # วาดจากบนลงล่าง (+ky -> -ky)
|
| 227 |
-
|
| 228 |
-
# วาดลูกศรชี้พิกัดที่กำลังวาด (ชี้เฉพาะบรรทัดนั้นๆ)
|
| 229 |
-
current_y_center = 112 - int(current_step * step_size + step_size / 2)
|
| 230 |
-
ax.annotate('', xy=(-70, current_y_center), xytext=(-110, current_y_center), arrowprops=dict(arrowstyle='->', color='red', lw=2))
|
| 231 |
-
|
| 232 |
-
ax.axhline(0, color='white', linewidth=0.5, linestyle='--')
|
| 233 |
-
ax.axvline(0, color='white', linewidth=0.5, linestyle='--')
|
| 234 |
-
ax.set_title("K-Space Filling", fontweight='bold')
|
| 235 |
ax.axis('off')
|
| 236 |
return get_image_from_plot(fig)
|
| 237 |
|
|
@@ -271,10 +278,10 @@ with col_main:
|
|
| 271 |
**การบันทึกข้อมูลลงใน K-space สามารถทำได้หลายรูปแบบ** โดยจะยกตัวอย่างให้การเก็บข้อมูลจะดำเนินไปทีละบรรทัด โดยสัญญาณจะเกิดขึ้นหลังจากกระตุ้นด้วย RF Pulse โดยมีลำดับดังนี้
|
| 272 |
|
| 273 |
1. กระบวนการเริ่มต้นขึ้นเมื่อสนามแม่เหล็กเกรเดียนท์ **Gx** และ **Gy** เริ่มทำงานพร้อมกันเพื่อสร้างพิกัดอ้างอิง
|
| 274 |
-
2. ระบบจะเริ่มบันทึกข้อมูลจุดแรกของเฟสในแถวที่ 1 โดยจะเริ่มต้นที่ค่าแอมปลิจูดของ **Gy ทางฝั่งบวกก่อน**
|
| 275 |
-
3. สัญญาณจะถูกบันทึกไล่ไปตามแกน Gx จนได้ข้อมูลครบถ้วนเต็ม 1 แถว
|
| 276 |
4. เมื่อจบแถวแรก ระบบจะเริ่มกระบวนการใหม่เพื่อบันทึกข้อมูลในเฟสแถวที่ 2, 3, 4 ต่อไปเรื่อยๆ
|
| 277 |
-
5. การวนรอบนี้จะดำเนินต่อไปพร้อมกับการเปลี่ยนค่า **Gy ให้ลดลงจนไปถึงค่าทางฝั่งลบ** เมื่อบันทึกครบทุกแถวตามจำนวนความละเอียดที่ตั้งไว้ จะถือว่าสิ้นสุดกระบวนการเก็บข้อมูล MRI แบบสองมิติลงบน K-space
|
| 278 |
""")
|
| 279 |
|
| 280 |
total_anim_steps = 15
|
|
@@ -316,6 +323,7 @@ with col_main:
|
|
| 316 |
with col_anim2:
|
| 317 |
st.image(draw_kspace_filling(st.session_state.fill_step, total_anim_steps, data_mode, kspace_bg_image), use_container_width=True)
|
| 318 |
|
|
|
|
| 319 |
st.markdown("---")
|
| 320 |
st.markdown("## 📍 1 จุดบน k-space")
|
| 321 |
|
|
|
|
| 135 |
ax.axis('off')
|
| 136 |
return get_image_from_plot(fig)
|
| 137 |
|
|
|
|
| 138 |
def draw_pulse_sequence(current_step, total_steps):
|
| 139 |
fig, axes = plt.subplots(4, 1, figsize=(5, 6), sharex=True, gridspec_kw={'height_ratios': [1, 1.5, 1, 1]})
|
| 140 |
t = np.linspace(0, 10, 1000)
|
|
|
|
| 149 |
ax.text(0, 0.5, 'RF', fontsize=14, fontweight='bold', va='center', ha='right', transform=ax.get_yaxis_transform())
|
| 150 |
ax.axis('off')
|
| 151 |
|
| 152 |
+
# 2. Gy (Phase Encoding)
|
| 153 |
ax = axes[1]
|
| 154 |
gy_vals = np.linspace(1, -1, total_steps)
|
| 155 |
for i, gy_amp in enumerate(gy_vals):
|
|
|
|
| 162 |
ax.text(0, 0, 'Gy', fontsize=14, fontweight='bold', va='center', ha='right', transform=ax.get_yaxis_transform())
|
| 163 |
ax.axis('off')
|
| 164 |
|
| 165 |
+
# 3. Gx (Frequency Encoding)
|
| 166 |
ax = axes[2]
|
| 167 |
gx = np.zeros_like(t)
|
| 168 |
gx[(t > 2.5) & (t < 3.5)] = -0.5
|
|
|
|
| 183 |
plt.tight_layout()
|
| 184 |
return get_image_from_plot(fig)
|
| 185 |
|
| 186 |
+
# --- ฟังก์ชันวาด Trajectory (เริ่มซ้ายบน วิ่งไปขวา) ---
|
| 187 |
def draw_kspace_filling(current_step, total_steps, mode_type, real_bg):
|
| 188 |
fig, ax = plt.subplots(figsize=(5, 6))
|
|
|
|
|
|
|
|
|
|
| 189 |
|
| 190 |
if mode_type == "ข้อมูลจำลอง (Simulated)":
|
| 191 |
+
# สร้างกราฟดำ
|
| 192 |
+
ax.set_facecolor('black')
|
| 193 |
+
|
| 194 |
+
# แกน kx, ky
|
| 195 |
+
ax.axhline(0, color='gray', lw=1, ls='--')
|
| 196 |
+
ax.axvline(0, color='gray', lw=1, ls='--')
|
| 197 |
+
|
| 198 |
+
# คำนวณพิกัด Y จากบนลงล่าง (+ky ไป -ky)
|
| 199 |
+
y_vals = np.linspace(90, -90, total_steps)
|
| 200 |
+
|
| 201 |
+
for i in range(current_step + 1):
|
| 202 |
+
y = y_vals[i]
|
| 203 |
+
# วาดเส้นลูกศรวิ่งจาก ซ้าย (-kx) ไป ขวา (+kx)
|
| 204 |
+
if i == current_step:
|
| 205 |
+
ax.annotate('', xy=(100, y), xytext=(-100, y), arrowprops=dict(arrowstyle='->', color='red', lw=3))
|
| 206 |
+
else:
|
| 207 |
+
ax.annotate('', xy=(100, y), xytext=(-100, y), arrowprops=dict(arrowstyle='->', color='white', lw=1.5))
|
| 208 |
+
|
| 209 |
+
# วาดเส้นประเฉียงๆ โยงจากจุดจบขวา ไปเริ่มซ้ายในบรรทัดถัดไป
|
| 210 |
+
for i in range(current_step):
|
| 211 |
+
ax.plot([100, -100], [y_vals[i], y_vals[i+1]], color='gray', ls=':', lw=1)
|
| 212 |
|
| 213 |
+
ax.set_xlim(-112, 112)
|
| 214 |
+
ax.set_ylim(-112, 112)
|
| 215 |
+
|
| 216 |
else:
|
| 217 |
+
# โหมดข้อมูลจริง (kspace.mat) เติมจากบนลงล่าง
|
| 218 |
+
display_img = np.zeros((224, 224))
|
| 219 |
+
step_size = 224 / total_steps
|
| 220 |
+
|
| 221 |
if current_step >= total_steps - 1:
|
| 222 |
display_img = real_bg
|
| 223 |
else:
|
| 224 |
current_line_idx = int(current_step * step_size)
|
| 225 |
+
# เติมข้อมูลจากแถวบน (index 0) ลงมา
|
| 226 |
display_img[:current_line_idx + int(step_size), :] = real_bg[:current_line_idx + int(step_size), :]
|
| 227 |
+
|
| 228 |
+
# origin='upper' ควบคุมให้ index 0 อยู่ด้านบนสุด (y=112)
|
| 229 |
+
ax.imshow(display_img, cmap='gray', extent=[-112, 112, -112, 112], origin='upper', vmin=0, vmax=1)
|
| 230 |
+
|
| 231 |
+
# ลูกศรชี้พิกัดที่กำลังทำงาน
|
| 232 |
+
current_y_center = 112 - int(current_step * step_size + step_size / 2)
|
| 233 |
+
ax.annotate('', xy=(112, current_y_center), xytext=(-112, current_y_center), arrowprops=dict(arrowstyle='->', color='red', lw=2))
|
| 234 |
+
|
| 235 |
+
ax.set_xlim(-112, 112)
|
| 236 |
+
ax.set_ylim(-112, 112)
|
| 237 |
+
|
| 238 |
+
ax.set_title("K-Space Trajectory", fontweight='bold', color='white' if mode_type=="ข้อมูลจำลอง (Simulated)" else 'black')
|
| 239 |
+
if mode_type == "ข้อมูลจำลอง (Simulated)":
|
| 240 |
+
fig.patch.set_facecolor('black')
|
| 241 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 242 |
ax.axis('off')
|
| 243 |
return get_image_from_plot(fig)
|
| 244 |
|
|
|
|
| 278 |
**การบันทึกข้อมูลลงใน K-space สามารถทำได้หลายรูปแบบ** โดยจะยกตัวอย่างให้การเก็บข้อมูลจะดำเนินไปทีละบรรทัด โดยสัญญาณจะเกิดขึ้นหลังจากกระตุ้นด้วย RF Pulse โดยมีลำดับดังนี้
|
| 279 |
|
| 280 |
1. กระบวนการเริ่มต้นขึ้นเมื่อสนามแม่เหล็กเกรเดียนท์ **Gx** และ **Gy** เริ่มทำงานพร้อมกันเพื่อสร้างพิกัดอ้างอิง
|
| 281 |
+
2. ระบบจะเริ่มบันทึกข้อมูลจุดแรกของเฟสในแถวที่ 1 โดยจะเริ่มต้นที่ค่าแอมปลิจูดของ **Gy ทางฝั่งบวกก่อน (พิกัดด้านบนของ K-Space)**
|
| 282 |
+
3. สัญญาณจะถูกบันทึกไล่ไปตามแกน **Gx (จากซ้าย -kx ไป ขวา +kx)** จนได้ข้อมูลครบถ้วนเต็ม 1 แถว
|
| 283 |
4. เมื่อจบแถวแรก ระบบจะเริ่มกระบวนการใหม่เพื่อบันทึกข้อมูลในเฟสแถวที่ 2, 3, 4 ต่อไปเรื่อยๆ
|
| 284 |
+
5. การวนรอบนี้จะดำเนินต่อไปพร้อมกับการเปลี่ยนค่า **Gy ให้ลดลงจนไปถึงค่าทางฝั่งลบ (พิกัดด้านล่าง)** เมื่อบันทึกครบทุกแถวตามจำนวนความละเอียดที่ตั้งไว้ จะถือว่าสิ้นสุดกระบวนการเก็บข้อมูล MRI แบบสองมิติลงบน K-space
|
| 285 |
""")
|
| 286 |
|
| 287 |
total_anim_steps = 15
|
|
|
|
| 323 |
with col_anim2:
|
| 324 |
st.image(draw_kspace_filling(st.session_state.fill_step, total_anim_steps, data_mode, kspace_bg_image), use_container_width=True)
|
| 325 |
|
| 326 |
+
|
| 327 |
st.markdown("---")
|
| 328 |
st.markdown("## 📍 1 จุดบน k-space")
|
| 329 |
|