Rsna_ida
https://www.kaggle.com/code/yosukeyama/rsna2025-32ch-img-infer-lb-0-69-share
举例: Found 176 DICOM files in series
“176 个 DICOM” 通常表示同一个 Series 里有 176 个 instance,而一个 instance(SOPInstanceUID)通常就是一张 2D 切片(CT 的单帧图像对象)。预处理把这 176 张切片按空间顺序堆叠成一个 3D 体(volume),再重采样到模型需要的固定尺寸 (32, 384, 384)。
“Found 176 DICOM files in series X” 意味着:这个 Series 里有 176 个 instance(≈ 176 张切片)。
也就是说这个DICOM数据本质上是3D数据。这也是为什么discussion中有人尝试使用3DGCN来解决问题。现在的LB069方案是使用EffNetv2将所有的DICOM数据通过预处理变为固定尺寸(32, 384, 384)的体素实现的。
1
2
3
4
5
6
7
> test_datasets, test_series_name = load_dicom_series(test_series_path)
Found 176 DICOM files in series 1.2.826.0.1.3680043.8.498.10028406715369553772267826812576760572
> print(len(test_datasets))
> print(test_series_name)
176
1.2.826.0.1.3680043.8.498.10028406715369553772267826812576760572
其中的 SOP Class UID标记了当前DICOM的采集数据类型: MRI
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
> test_datasets[0]
Dataset.file_meta -------------------------------
(0002,0001) File Meta Information Version OB: b'\x00\x01'
(0002,0002) Media Storage SOP Class UID UI: MR Image Storage
(0002,0003) Media Storage SOP Instance UID UI: 1.2.826.0.1.3680043.8.498.60167621473192127650530987989038873804
(0002,0010) Transfer Syntax UID UI: Explicit VR Little Endian
(0002,0012) Implementation Class UID UI: 1.2.40.0.13.1.1.1
(0002,0013) Implementation Version Name SH: 'PYDICOM 3.0.1'
-------------------------------------------------
(0008,0016) SOP Class UID UI: MR Image Storage
(0008,0018) SOP Instance UID UI: 1.2.826.0.1.3680043.8.498.60167621473192127650530987989038873804
(0008,0060) Modality CS: 'MR'
(0010,0020) Patient ID LO: '2d7056cd-a66'
(0018,0050) Slice Thickness DS: '1'
(0020,000D) Study Instance UID UI: 1.2.826.0.1.3680043.8.498.92036735550297900604720522165601531201
(0020,000E) Series Instance UID UI: 1.2.826.0.1.3680043.8.498.10028406715369553772267826812576760572
(0020,0013) Instance Number IS: '169'
(0020,0032) Image Position (Patient) DS: [-115.01414203644, -137.79509544372, 62.293177057151]
(0020,0037) Image Orientation (Patient) DS: [1, -6.123234e-017, 7.888609052e-031, 6.123233996e-017, 1, -7.10542736e-015]
(0020,0052) Frame of Reference UID UI: 1.2.826.0.1.3680043.8.498.11811620029624765973121972843116097787
(0028,0002) Samples per Pixel US: 1
(0028,0004) Photometric Interpretation CS: 'MONOCHROME2'
(0028,0010) Rows US: 256
(0028,0011) Columns US: 256
(0028,0030) Pixel Spacing DS: [1, 1]
(0028,0100) Bits Allocated US: 16
(0028,0101) Bits Stored US: 16
(0028,0102) High Bit US: 15
(0028,0103) Pixel Representation US: 1
(7FE0,0010) Pixel Data OW: Array of 131072 elements
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import numpy as np
import matplotlib.pyplot as plt
from pydicom.pixel_data_handlers.util import apply_voi_lut
def dicom_to_u8(ds):
img = ds.pixel_array
# 应用 VOI LUT(若无则等价返回原图)
try:
img = apply_voi_lut(img, ds)
except Exception:
pass
img = img.astype(np.float32)
# 分位数拉伸,防止极端值(VOI 缺失时更稳定)
lo, hi = np.percentile(img, [1, 99])
den = max(hi - lo, 1e-6)
img = np.clip((img - lo) / den, 0, 1)
# MONOCHROME1 反相
if getattr(ds, "PhotometricInterpretation", "") == "MONOCHROME1":
img = 1.0 - img
return (img * 255).astype(np.uint8)
# ---------- 显示当前第0张 ----------
ds0 = test_datasets[0]
img0 = dicom_to_u8(ds0)
plt.figure(figsize=(4,4))
plt.imshow(img0, cmap='gray')
plt.title(f"SOPInstanceUID: {getattr(ds0,'SOPInstanceUID','N/A')}")
plt.axis('off')
plt.show()
# ---------- 显示多张 ----------
idxs = np.linspace(0, len(test_datasets)-1, num=min(8, len(test_datasets)), dtype=int)
fig, axes = plt.subplots(1, len(idxs), figsize=(2.6*len(idxs), 2.6))
if len(idxs) == 1:
axes = [axes]
for ax, i in zip(axes, idxs):
img = dicom_to_u8(test_datasets[i])
ax.imshow(img, cmap='gray')
ax.set_title(f"idx {i}")
ax.axis('off')
plt.tight_layout()
plt.show()
图像的尺寸为(256, 256)的灰度图。
所以该比赛的challenge其实有几点:
- multimodel data, 输入数据有CT, CTA, MRA, MRI等好几种
- 13个解刨位置(多分类任务,有14个类别)
- 目标(IDA)可能非常小
Data
train.csv
14列的标签对应着是否包含该病症, Aneurysm Present则是一个总的结果,表示是否有病症。即前面13个如果有任意一个,Aneurysm Present就是1.
Problem
Try-Except
https://www.kaggle.com/competitions/rsna-intracranial-aneurysm-detection/discussion/608575
该discussion提到测试序列存在问题,会触发大量的错误。导致输出0.5虚拟预测。
这个错误在本地复现不了,因为submit之后输出的log和output并不会返回。(与imc25一样,测试是黑盒)
可能是同一个错误的讨论:https://www.kaggle.com/competitions/rsna-intracranial-aneurysm-detection/discussion/596296#3274179
其他
https://www.kaggle.com/competitions/rsna-intracranial-aneurysm-detection/discussion/596296#3265689
有意思的一点是,数据的模态(Modality,即数据是在何种设备上采集的)并不能作为input被提取到。但是如果真的需要,使用pixel data-based method也能够识别。(对每个模态单独训练模型?)
pipeline
EffNet from xyz direction
3D volume
加载n张图像后,如果按一般的体素进行处理,得到的结果大概率如下:
需要做额外的对齐操作
噪声部分(如y:0, 19, 39, 235, 255 x:0, 19, 39, 215, 235, 255)可能需要进行识别和删除。