Update app.py
Browse files
app.py
CHANGED
|
@@ -72,20 +72,18 @@ def load_kspace_data():
|
|
| 72 |
|
| 73 |
kspace_raw = load_kspace_data()
|
| 74 |
|
| 75 |
-
# ปรับแก้ความสว่างภาพ K-Space ใหม่ (ใช้ Gamma Correction เพื่อให้เห็นวงกลมชัดแบบออริจินอล)
|
| 76 |
def format_kspace_display(k_data):
|
| 77 |
k_mag = np.abs(k_data)
|
| 78 |
-
|
|
|
|
| 79 |
return np.zeros_like(k_mag, dtype=np.float32)
|
| 80 |
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
# 2. Normalize ให้อยู่ในช่วง 0-1
|
| 84 |
-
log_norm = (log_k - np.min(log_k)) / (np.max(log_k) - np.min(log_k))
|
| 85 |
-
# 3. Gamma Correction (0.3) งัดส่วนที่มืดให้สว่างพุ่งขึ้นมา
|
| 86 |
-
gamma = 0.3
|
| 87 |
-
log_boosted = np.power(log_norm, gamma)
|
| 88 |
|
|
|
|
|
|
|
|
|
|
| 89 |
return log_boosted
|
| 90 |
|
| 91 |
kspace_bg_image = format_kspace_display(kspace_raw)
|
|
@@ -97,31 +95,31 @@ def get_image_from_plot(fig):
|
|
| 97 |
buf.seek(0)
|
| 98 |
return Image.open(buf)
|
| 99 |
|
| 100 |
-
# สร้างภาพ
|
| 101 |
def draw_kspace_diagram():
|
| 102 |
fig, ax = plt.subplots(figsize=(6, 6))
|
| 103 |
|
| 104 |
-
#
|
| 105 |
x = np.linspace(-112, 112, 224)
|
| 106 |
y = np.linspace(112, -112, 224)
|
| 107 |
X, Y = np.meshgrid(x, y)
|
| 108 |
|
| 109 |
-
freq_x =
|
| 110 |
-
freq_y =
|
| 111 |
wave = np.cos(2 * np.pi * (freq_x * X + freq_y * Y))
|
| 112 |
|
| 113 |
-
# แสดงรูปคลื่นในกรอบ
|
| 114 |
-
ax.imshow(wave, cmap='gray', extent=[-1, 1, -1, 1])
|
| 115 |
|
| 116 |
-
# ตีกรอบสี่เหลี่ยมรอบ
|
| 117 |
-
rect = plt.Rectangle((-1, -1), 2, 2, fill=False, edgecolor='black', lw=2)
|
| 118 |
ax.add_patch(rect)
|
| 119 |
|
| 120 |
-
# วาดแกน
|
| 121 |
ax.annotate('', xy=(1, -1.2), xytext=(-1, -1.2), arrowprops=dict(arrowstyle='<|-|>', color='black', lw=3))
|
| 122 |
ax.text(0, -1.3, 'kx (Frequency)', ha='center', va='top', fontsize=18, fontweight='bold')
|
| 123 |
|
| 124 |
-
# วาดแกน
|
| 125 |
ax.annotate('', xy=(-1.2, 1), xytext=(-1.2, -1), arrowprops=dict(arrowstyle='<|-|>', color='black', lw=3))
|
| 126 |
ax.text(-1.3, 0, 'ky (Phase)', ha='right', va='center', rotation=90, fontsize=18, fontweight='bold')
|
| 127 |
|
|
@@ -134,7 +132,6 @@ def draw_kspace_diagram():
|
|
| 134 |
|
| 135 |
def draw_kspace_point(kx, ky, bg_image):
|
| 136 |
fig, ax = plt.subplots(figsize=(4, 4))
|
| 137 |
-
# แสดงภาพ K-space สว่างจ้า
|
| 138 |
ax.imshow(bg_image, cmap='gray', extent=[-112, 112, -112, 112], vmin=0, vmax=1)
|
| 139 |
ax.plot(kx, ky, 'ro', markersize=6)
|
| 140 |
ax.annotate('', xy=(kx, ky), xytext=(0, 0), arrowprops=dict(arrowstyle='->', color='yellow', lw=2))
|
|
@@ -171,7 +168,6 @@ def apply_filter(k_data, mode, radius):
|
|
| 171 |
|
| 172 |
def draw_filtered_kspace(filtered_k):
|
| 173 |
fig, ax = plt.subplots(figsize=(4, 4))
|
| 174 |
-
# ภาพ Filtered ก็จะสว่าง เห็นวงกลม Filter สีดำชัดเจน
|
| 175 |
ax.imshow(format_kspace_display(filtered_k), cmap='gray', vmin=0, vmax=1)
|
| 176 |
ax.axis('off')
|
| 177 |
return get_image_from_plot(fig)
|
|
@@ -280,7 +276,7 @@ with col_main:
|
|
| 280 |
ข้อมูลใน k-space มักจะถูกนำมาแสดงผลในรูปแบบตารางสี่เหลี่ยม (Grid) โดยมีแกนหลักคือ **kx (แนวนอน - Frequency)** และ **ky (แนวตั้ง - Phase)** จุดสำคัญคือ **แกน kx และ ky เหล่านี้ ไม่ได้���อกตำแหน่งพิกัดในภาพอวัยวะ** แต่มันคือแกนที่บอกถึงลักษณะของ **"ความถี่เชิงพื้นที่"** ที่เป็นคลื่น (Sinusoidal wave) ด้วยเหตุนี้ **จุดแต่ละจุดบน K-space จึงไม่ได้จับคู่แบบ 1 ต่อ 1 กับพิกเซลบนภาพ MRI** (เช่น จุดมุมซ้ายบนของ K-space ไม่ได้สร้างภาพมุมซ้ายบนของอวัยวะ)
|
| 281 |
""")
|
| 282 |
|
| 283 |
-
_, col_img_center, _ = st.columns([
|
| 284 |
with col_img_center:
|
| 285 |
st.image(draw_kspace_diagram(), use_container_width=True)
|
| 286 |
|
|
@@ -418,10 +414,11 @@ with col_main:
|
|
| 418 |
|
| 419 |
_, col_fslide, _ = st.columns([1.5, 5, 1.5])
|
| 420 |
with col_fslide:
|
|
|
|
| 421 |
if mode == "Low frequency":
|
| 422 |
-
radius = st.slider("ปรับระดับความถี่ที่ยอมให้ผ่าน (รัศมีจากตรงกลาง)", 1,
|
| 423 |
else:
|
| 424 |
-
radius = st.slider("ปรับระดับการตัดข้อมูลส่วนกลาง (รัศมีจากตรงกลาง)", 0,
|
| 425 |
|
| 426 |
filtered_k, mri_result = apply_filter(kspace_raw, mode, radius)
|
| 427 |
|
|
|
|
| 72 |
|
| 73 |
kspace_raw = load_kspace_data()
|
| 74 |
|
|
|
|
| 75 |
def format_kspace_display(k_data):
|
| 76 |
k_mag = np.abs(k_data)
|
| 77 |
+
max_val = np.max(k_mag)
|
| 78 |
+
if max_val == 0:
|
| 79 |
return np.zeros_like(k_mag, dtype=np.float32)
|
| 80 |
|
| 81 |
+
c = 255.0 / np.log(1 + max_val)
|
| 82 |
+
log_img = c * np.log(1 + k_mag)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
|
| 84 |
+
# ใช้ Gamma correction เสริมความสว่างให้เห็นวงกลมฟิลเตอร์ชัดเจน
|
| 85 |
+
log_norm = (log_img - np.min(log_img)) / (np.max(log_img) - np.min(log_img) + 1e-8)
|
| 86 |
+
log_boosted = np.power(log_norm, 0.3)
|
| 87 |
return log_boosted
|
| 88 |
|
| 89 |
kspace_bg_image = format_kspace_display(kspace_raw)
|
|
|
|
| 95 |
buf.seek(0)
|
| 96 |
return Image.open(buf)
|
| 97 |
|
| 98 |
+
# สร้างภาพองค์ประกอบ K-Space แบบมีลวดลายคลื่น 2D และลูกศรบอกแกนตามรูปตัวอย่าง
|
| 99 |
def draw_kspace_diagram():
|
| 100 |
fig, ax = plt.subplots(figsize=(6, 6))
|
| 101 |
|
| 102 |
+
# สร้างตารางและลวดลายคลื่น 2D ทแยงมุมเต็มพื้นที่กล่องสี่เหลี่ยม
|
| 103 |
x = np.linspace(-112, 112, 224)
|
| 104 |
y = np.linspace(112, -112, 224)
|
| 105 |
X, Y = np.meshgrid(x, y)
|
| 106 |
|
| 107 |
+
freq_x = 8 / 224.0
|
| 108 |
+
freq_y = 8 / 224.0
|
| 109 |
wave = np.cos(2 * np.pi * (freq_x * X + freq_y * Y))
|
| 110 |
|
| 111 |
+
# แสดงรูปคลื่นในกรอบสี่เหลี่ยม
|
| 112 |
+
ax.imshow(wave, cmap='gray', extent=[-1, 1, -1, 1], origin='upper')
|
| 113 |
|
| 114 |
+
# ตีกรอบสี่เหลี่ยมทับรอบนอก
|
| 115 |
+
rect = plt.Rectangle((-1, -1), 2, 2, fill=False, edgecolor='black', lw=2.5)
|
| 116 |
ax.add_patch(rect)
|
| 117 |
|
| 118 |
+
# วาดแกน kx (แนวนอน) ด้านล่างกล่อง
|
| 119 |
ax.annotate('', xy=(1, -1.2), xytext=(-1, -1.2), arrowprops=dict(arrowstyle='<|-|>', color='black', lw=3))
|
| 120 |
ax.text(0, -1.3, 'kx (Frequency)', ha='center', va='top', fontsize=18, fontweight='bold')
|
| 121 |
|
| 122 |
+
# วาดแกน ky (แนวตั้ง) ด้านซ้ายกล่อง
|
| 123 |
ax.annotate('', xy=(-1.2, 1), xytext=(-1.2, -1), arrowprops=dict(arrowstyle='<|-|>', color='black', lw=3))
|
| 124 |
ax.text(-1.3, 0, 'ky (Phase)', ha='right', va='center', rotation=90, fontsize=18, fontweight='bold')
|
| 125 |
|
|
|
|
| 132 |
|
| 133 |
def draw_kspace_point(kx, ky, bg_image):
|
| 134 |
fig, ax = plt.subplots(figsize=(4, 4))
|
|
|
|
| 135 |
ax.imshow(bg_image, cmap='gray', extent=[-112, 112, -112, 112], vmin=0, vmax=1)
|
| 136 |
ax.plot(kx, ky, 'ro', markersize=6)
|
| 137 |
ax.annotate('', xy=(kx, ky), xytext=(0, 0), arrowprops=dict(arrowstyle='->', color='yellow', lw=2))
|
|
|
|
| 168 |
|
| 169 |
def draw_filtered_kspace(filtered_k):
|
| 170 |
fig, ax = plt.subplots(figsize=(4, 4))
|
|
|
|
| 171 |
ax.imshow(format_kspace_display(filtered_k), cmap='gray', vmin=0, vmax=1)
|
| 172 |
ax.axis('off')
|
| 173 |
return get_image_from_plot(fig)
|
|
|
|
| 276 |
ข้อมูลใน k-space มักจะถูกนำมาแสดงผลในรูปแบบตารางสี่เหลี่ยม (Grid) โดยมีแกนหลักคือ **kx (แนวนอน - Frequency)** และ **ky (แนวตั้ง - Phase)** จุดสำคัญคือ **แกน kx และ ky เหล่านี้ ไม่ได้���อกตำแหน่งพิกัดในภาพอวัยวะ** แต่มันคือแกนที่บอกถึงลักษณะของ **"ความถี่เชิงพื้นที่"** ที่เป็นคลื่น (Sinusoidal wave) ด้วยเหตุนี้ **จุดแต่ละจุดบน K-space จึงไม่ได้จับคู่แบบ 1 ต่อ 1 กับพิกเซลบนภาพ MRI** (เช่น จุดมุมซ้ายบนของ K-space ไม่ได้สร้างภาพมุมซ้ายบนของอวัยวะ)
|
| 277 |
""")
|
| 278 |
|
| 279 |
+
_, col_img_center, _ = st.columns([2.5, 3, 2.5])
|
| 280 |
with col_img_center:
|
| 281 |
st.image(draw_kspace_diagram(), use_container_width=True)
|
| 282 |
|
|
|
|
| 414 |
|
| 415 |
_, col_fslide, _ = st.columns([1.5, 5, 1.5])
|
| 416 |
with col_fslide:
|
| 417 |
+
# ปรับขยายขอบเขตรัศมีสูงสุดเป็น 160 เพื่อให้คลุมครบทั้ง 4 มุมจอเมื่อเปิดสุดตามหลักคณิตศาสตร์
|
| 418 |
if mode == "Low frequency":
|
| 419 |
+
radius = st.slider("ปรับระดับความถี่ที่ยอมให้ผ่าน (รัศมีจากตรงกลาง)", 1, 160, 160)
|
| 420 |
else:
|
| 421 |
+
radius = st.slider("ปรับระดับการตัดข้อมูลส่วนกลาง (รัศมีจากตรงกลาง)", 0, 160, 0)
|
| 422 |
|
| 423 |
filtered_k, mri_result = apply_filter(kspace_raw, mode, radius)
|
| 424 |
|