SQ(シークエンス)の構造
DICOM規格日本語訳のPS3.5 p39-を読み解いていきます
図のように,SQのVRが来ると,その次の2byteは予約済み(普通は0x0000がはいっている)で,関係が無いので飛ばします.
続く4byteにデータ長が入っています.
データ長は2種類あり,
種類 | データ長のバイト列 | 概要 |
---|---|---|
明示的長さ | 0x00 01 13 50 (例) | このように値が入っている場合はデータ長を示す |
未定義長さ | 0xFF FF FF FF | データ長が明示されていない. この場合は,項目を区切るタグを目印によむ |
このような未定議長さの場合には,区切りタグを基に読む必要があります.
タグ | 意味 | 概要 |
---|---|---|
FFFE, E0000 | 項目の開始 | 項目の開始に必要なタグ |
FFFE, E00D | 項目の区切り | 項目の長さが明示されている場合は省略される |
FFFE, E0DD | SQの終わり | シークエンスの長さが明示されている場合は省略される |
今回のファイルで最初にSQが登場するのは,アドレス0x21C(540)からです.
この部分を図示すると次の通りとなります.
実装
####コーディング
DicomData.swift
func analyzeData(){
currentPosition = 128 + 4
// シークエンス用
var hierarchy = 0
while currentPosition < dicomData.count {
let position = currentPosition
let group = readUInt16()
let element = readUInt16()
// SQ用の特殊タグをチェックする
if (group == 0xFFFE && element == 0xE000){
// 項目開始
let length = readUInt32()
if length == 0xFFFFFFFF{
printLog(hierarchy: hierarchy, position: position, group: group, element: element, vr: "", length: length)
hierarchy += 1
continue
}else{
// TODO: 明示長さの場合は,指定の部位まで読んだら階層を下げる必要がある
printLog(hierarchy: hierarchy, position: position, group: group, element: element, vr: "", length: length)
currentPosition += Int(length)
continue
}
}else if (group == 0xFFFE && element == 0xE00D){
// 項目終わり
let length = readUInt32() // 0xFFFFFFFF
printLog(hierarchy: hierarchy, position: position, group: group, element: element, vr: "", length: length)
hierarchy -= 1
continue
}else if (group == 0xFFFE && element == 0xE0DD){
// シークエンスの終わり
let length = readUInt32() // 0xFFFFFFFF
printLog(hierarchy: hierarchy, position: position, group: group, element: element, vr: "", length: length)
hierarchy -= 1
continue
}
let vr = readChar(length: 2)
if ["OB", "OW", "OF", "UT"].contains(vr){
// VRの続きの2byteは意味をなさないので飛ばす
currentPosition += 2
let length = readUInt32()
if length == 0xFFFFFFFF{
printLog(hierarchy: hierarchy, position: position, group: group, element: element, vr: vr, length: length)
hierarchy += 1
}else{
printLog(hierarchy: hierarchy, position: position, group: group, element: element, vr: vr, length: length)
currentPosition += Int(length)
}
}else if vr == "SQ"{
// SQでは,データ長さが0xFFFFFFFFの場合に注意
currentPosition += 2
let length = readUInt32()
if length == 0xFFFFFFFF{
// 未定義長さ
printLog(hierarchy: hierarchy, position: position, group: group, element: element, vr: vr, length: length)
hierarchy += 1
}else{
// 明示長さ
currentPosition += Int(length)
printLog(hierarchy: hierarchy, position: position, group: group, element: element, vr: vr, length: length)
}
}else{
let length = readUInt16()
print("\(String(repeating: " ", count: hierarchy))0x\(String(position, radix: 16).uppercased())(\(position)), tag: (\(String(format: "%04x", group)), \(String(format: "%04x", element))), VR: \(vr), Length: \(UInt32( length))")
currentPosition += Int( length)
}
}
}
(省略 readUInt16, readUInt32, readCharは変更なし)
func printLog(hierarchy: Int, position: Int, group: UInt16, element:UInt16, vr:String, length:UInt32){
if length == 0xFFFFFFFF{
print("\(String(repeating: " ", count: hierarchy))0x\(String(position, radix: 16).uppercased())(\(position)), tag: (\(String(format: "%04x", group)), \(String(format: "%04x", element))), VR: \(vr), Length:")
}else{
print("\(String(repeating: " ", count: hierarchy))0x\(String(position, radix: 16).uppercased())(\(position)), tag: (\(String(format: "%04x", group)), \(String(format: "%04x", element))), VR: \(vr), Length: \(length)")
}
}
解読の流れ
- タグ(Group, Element)をよむ
- 特殊なタグの場合は個別処理
- FFFE, E000 : 項目の始まりなので,階層を上げる
- FFFE, E00D : 項目の終わりなので,階層を下げる
- FFFE, E0DD : シークエンスの終わりなので,階層を下げる
- 上記の特殊タグの場合は続くVRは無いので,
continue
でループの最初に戻る - VRを読む
- "OB", "OW", "OF", "UT"の場合は画像データが入っていたりする.
いまはまだ読まないので,後日実装 - SQの場合はシークエンスの始まり.
長さは明示されている場合もあるし未定義の場合もある
現時点では明示されている場合は,その長さ分すっ飛ばして解読を続けている - 他のVRは2byteの長さを読む
- "OB", "OW", "OF", "UT"の場合は画像データが入っていたりする.
実行結果
dicom file loaded
0x84(132), tag: (0002, 0000), VR: UL, Length: 4
0x90(144), tag: (0002, 0001), VR: OB, Length: 2
0x9E(158), tag: (0002, 0002), VR: UI, Length: 28
0xC2(194), tag: (0002, 0003), VR: UI, Length: 46
0xF8(248), tag: (0002, 0010), VR: UI, Length: 22
0x116(278), tag: (0002, 0012), VR: UI, Length: 8
0x126(294), tag: (0008, 0008), VR: CS, Length: 38
0x154(340), tag: (0008, 0016), VR: UI, Length: 28
0x178(376), tag: (0008, 0018), VR: UI, Length: 46
0x1AE(430), tag: (0008, 0020), VR: DA, Length: 8
0x1BE(446), tag: (0008, 0030), VR: TM, Length: 6
0x1CC(460), tag: (0008, 0050), VR: SH, Length: 0
0x1D4(468), tag: (0008, 0060), VR: CS, Length: 2
0x1DE(478), tag: (0008, 0070), VR: LO, Length: 0
0x1E6(486), tag: (0008, 0080), VR: LO, Length: 0
0x1EE(494), tag: (0008, 0081), VR: ST, Length: 0
0x1F6(502), tag: (0008, 0090), VR: PN, Length: 0
0x1FE(510), tag: (0008, 1030), VR: LO, Length: 0
0x206(518), tag: (0008, 1050), VR: PN, Length: 0
0x20E(526), tag: (0008, 2110), VR: CS, Length: 2
0x218(536), tag: (0008, 2112), VR: SQ, Length:
0x224(548), tag: (fffe, e000), VR: , Length:
0x22C(556), tag: (0008, 1150), VR: UI, Length: 28
0x250(592), tag: (0008, 1155), VR: UI, Length: 46
0x286(646), tag: (fffe, e00d), VR: , Length: 0
0x28E(654), tag: (fffe, e0dd), VR: , Length: 0
0x296(662), tag: (0009, 0010), VR: LO, Length: 14
0x2AC(684), tag: (0009, 1002), VR: OB, Length: 904
0x640(1600), tag: (0009, 1003), VR: OB, Length: 528
0x85C(2140), tag: (0009, 1005), VR: OB, Length: 24
0x880(2176), tag: (0010, 0010), VR: PN, Length: 12
0x894(2196), tag: (0010, 0020), VR: LO, Length: 8
0x8A4(2212), tag: (0010, 0030), VR: DA, Length: 8
0x8B4(2228), tag: (0010, 0040), VR: CS, Length: 2
0x8BE(2238), tag: (0018, 0060), VR: DS, Length: 0
0x8C6(2246), tag: (0018, 1063), VR: DS, Length: 2
0x8D0(2256), tag: (0018, 1152), VR: IS, Length: 0
0x8D8(2264), tag: (0018, 1155), VR: CS, Length: 2
0x8E2(2274), tag: (0018, 1500), VR: CS, Length: 0
0x8EA(2282), tag: (0018, 1510), VR: DS, Length: 4
0x8F6(2294), tag: (0018, 1511), VR: DS, Length: 2
0x900(2304), tag: (0019, 0010), VR: LO, Length: 16
0x918(2328), tag: (0019, 1030), VR: UL, Length: 4
0x924(2340), tag: (0020, 000d), VR: UI, Length: 54
0x962(2402), tag: (0020, 000e), VR: UI, Length: 54
0x9A0(2464), tag: (0020, 0010), VR: SH, Length: 0
0x9A8(2472), tag: (0020, 0011), VR: IS, Length: 2
0x9B2(2482), tag: (0020, 0013), VR: IS, Length: 0
0x9BA(2490), tag: (0020, 0020), VR: CS, Length: 0
0x9C2(2498), tag: (0021, 0010), VR: LO, Length: 16
0x9DA(2522), tag: (0021, 1013), VR: IS, Length: 2
0x9E4(2532), tag: (0028, 0002), VR: US, Length: 2
0x9EE(2542), tag: (0028, 0004), VR: CS, Length: 12
0xA02(2562), tag: (0028, 0008), VR: IS, Length: 2
0xA0C(2572), tag: (0028, 0009), VR: AT, Length: 4
0xA18(2584), tag: (0028, 0010), VR: US, Length: 2
0xA22(2594), tag: (0028, 0011), VR: US, Length: 2
0xA2C(2604), tag: (0028, 0100), VR: US, Length: 2
0xA36(2614), tag: (0028, 0101), VR: US, Length: 2
0xA40(2624), tag: (0028, 0102), VR: US, Length: 2
0xA4A(2634), tag: (0028, 0103), VR: US, Length: 2
0xA54(2644), tag: (0028, 1040), VR: CS, Length: 4
0xA60(2656), tag: (0028, 1090), VR: CS, Length: 4
0xA6C(2668), tag: (0028, 6040), VR: US, Length: 6
0xA7A(2682), tag: (0028, 6100), VR: SQ, Length:
0xA86(2694), tag: (fffe, e000), VR: , Length:
0xA8E(2702), tag: (0028, 6101), VR: CS, Length: 4
0xA9A(2714), tag: (0028, 6110), VR: US, Length: 2
0xAA4(2724), tag: (fffe, e00d), VR: , Length: 0
0xAAC(2732), tag: (fffe, e0dd), VR: , Length: 0
0xAB4(2740), tag: (0029, 0010), VR: LO, Length: 16
0xACC(2764), tag: (0029, 1000), VR: SQ, Length:
0xAD8(2776), tag: (fffe, e000), VR: , Length:
0xAE0(2784), tag: (0029, 0010), VR: LO, Length: 16
0xAF8(2808), tag: (0029, 1001), VR: US, Length: 4
0xB04(2820), tag: (0029, 1002), VR: US, Length: 50
0xB3E(2878), tag: (0029, 1003), VR: FL, Length: 4
0xB4A(2890), tag: (fffe, e00d), VR: , Length: 0
0xB52(2898), tag: (fffe, e0dd), VR: , Length: 0
0xB5A(2906), tag: (5000, 0005), VR: US, Length: 2
0xB64(2916), tag: (5000, 0010), VR: US, Length: 2
0xB6E(2926), tag: (5000, 0020), VR: CS, Length: 4
0xB7A(2938), tag: (5000, 0030), VR: SH, Length: 10
0xB8C(2956), tag: (5000, 0103), VR: US, Length: 2
0xB96(2966), tag: (5000, 0104), VR: US, Length: 0
0xB9E(2974), tag: (5000, 0105), VR: US, Length: 0
0xBA6(2982), tag: (5000, 0106), VR: US, Length: 0
0xBAE(2990), tag: (5000, 0110), VR: US, Length: 4
0xBBA(3002), tag: (5000, 0112), VR: US, Length: 2
0xBC4(3012), tag: (5000, 0114), VR: US, Length: 2
0xBCE(3022), tag: (5000, 3000), VR: OW, Length: 7680
0x29DA(10714), tag: (7fe0, 0010), VR: OB, Length:
0x29E6(10726), tag: (fffe, e000), VR: , Length: 384
0x2B6E(11118), tag: (fffe, e000), VR: , Length: 17912
0x716E(29038), tag: (fffe, e000), VR: , Length: 18680
0xBA6E(47726), tag: (fffe, e000), VR: , Length: 18644
0x1034A(66378), tag: (fffe, e000), VR: , Length: 17820
0x148EE(84206), tag: (fffe, e000), VR: , Length: 16848
0x18AC6(101062), tag: (fffe, e000), VR: , Length: 16308
0x1CA82(117378), tag: (fffe, e000), VR: , Length: 16020
0x2091E(133406), tag: (fffe, e000), VR: , Length: 16088
0x247FE(149502), tag: (fffe, e000), VR: , Length: 16280
0x2879E(165790), tag: (fffe, e000), VR: , Length: 16408
0x2C7BE(182206), tag: (fffe, e000), VR: , Length: 16568
0x3087E(198782), tag: (fffe, e000), VR: , Length: 16556
0x34932(215346), tag: (fffe, e000), VR: , Length: 16604
0x38A16(231958), tag: (fffe, e000), VR: , Length: 16536
0x3CAB6(248502), tag: (fffe, e000), VR: , Length: 16628
0x40BB2(265138), tag: (fffe, e000), VR: , Length: 16428
0x44BE6(281574), tag: (fffe, e000), VR: , Length: 16328
0x48BB6(297910), tag: (fffe, e000), VR: , Length: 16456
0x4CC06(314374), tag: (fffe, e000), VR: , Length: 16468
0x50C62(330850), tag: (fffe, e000), VR: , Length: 16528
0x54CFA(347386), tag: (fffe, e000), VR: , Length: 16576
0x58DC2(363970), tag: (fffe, e000), VR: , Length: 16648
0x5CED2(380626), tag: (fffe, e000), VR: , Length: 16684
0x61006(397318), tag: (fffe, e000), VR: , Length: 16788
0x651A2(414114), tag: (fffe, e000), VR: , Length: 16852
0x6937E(430974), tag: (fffe, e000), VR: , Length: 16960
0x6D5C6(447942), tag: (fffe, e000), VR: , Length: 17164
0x718DA(465114), tag: (fffe, e000), VR: , Length: 17376
0x75CC2(482498), tag: (fffe, e000), VR: , Length: 17428
0x7A0DE(499934), tag: (fffe, e000), VR: , Length: 17392
0x7E4D6(517334), tag: (fffe, e000), VR: , Length: 17240
0x82836(534582), tag: (fffe, e000), VR: , Length: 17216
0x86B7E(551806), tag: (fffe, e000), VR: , Length: 17272
0x8AEFE(569086), tag: (fffe, e000), VR: , Length: 17416
0x8F30E(586510), tag: (fffe, e000), VR: , Length: 17480
0x9375E(603998), tag: (fffe, e000), VR: , Length: 17568
0x97C06(621574), tag: (fffe, e000), VR: , Length: 17572
0x9C0B2(639154), tag: (fffe, e000), VR: , Length: 17676
0xA05C6(656838), tag: (fffe, e000), VR: , Length: 17612
0xA4A9A(674458), tag: (fffe, e000), VR: , Length: 17760
0xA9002(692226), tag: (fffe, e000), VR: , Length: 17716
0xAD53E(709950), tag: (fffe, e000), VR: , Length: 17800
0xB1ACE(727758), tag: (fffe, e000), VR: , Length: 17952
0xB60F6(745718), tag: (fffe, e000), VR: , Length: 17916
0xBA6FA(763642), tag: (fffe, e000), VR: , Length: 17984
0xBED42(781634), tag: (fffe, e000), VR: , Length: 18120
0xC3412(799762), tag: (fffe, e000), VR: , Length: 18112
0xC7ADA(817882), tag: (fffe, e000), VR: , Length: 18008
0xCC13A(835898), tag: (fffe, e000), VR: , Length: 17984
0xD0782(853890), tag: (fffe, e000), VR: , Length: 17908
0xD4D7E(871806), tag: (fffe, e000), VR: , Length: 17960
0xD93AE(889774), tag: (fffe, e000), VR: , Length: 18112
0xDDA76(907894), tag: (fffe, e000), VR: , Length: 18256
0xE21CE(926158), tag: (fffe, e000), VR: , Length: 18240
0xE6916(944406), tag: (fffe, e000), VR: , Length: 18168
0xEB016(962582), tag: (fffe, e000), VR: , Length: 18092
0xEF6CA(980682), tag: (fffe, e000), VR: , Length: 18052
0xF3D56(998742), tag: (fffe, e000), VR: , Length: 18008
0xF83B6(1016758), tag: (fffe, e000), VR: , Length: 18048
0xFCA3E(1034814), tag: (fffe, e000), VR: , Length: 17976
0x10107E(1052798), tag: (fffe, e000), VR: , Length: 18056
0x10570E(1070862), tag: (fffe, e000), VR: , Length: 18040
0x109D8E(1088910), tag: (fffe, e000), VR: , Length: 18068
0x10E42A(1106986), tag: (fffe, e000), VR: , Length: 17984
0x112A72(1124978), tag: (fffe, e000), VR: , Length: 18012
0x1170D6(1142998), tag: (fffe, e000), VR: , Length: 18024
0x11B746(1161030), tag: (fffe, e000), VR: , Length: 18048
0x11FDCE(1179086), tag: (fffe, e000), VR: , Length: 17940
0x1243EA(1197034), tag: (fffe, e000), VR: , Length: 17984
0x128A32(1215026), tag: (fffe, e000), VR: , Length: 17952
0x12D05A(1232986), tag: (fffe, e000), VR: , Length: 18048
0x1316E2(1251042), tag: (fffe, e000), VR: , Length: 17996
0x135D36(1269046), tag: (fffe, e000), VR: , Length: 18040
0x13A3B6(1287094), tag: (fffe, e000), VR: , Length: 18048
0x13EA3E(1305150), tag: (fffe, e000), VR: , Length: 17936
0x143056(1323094), tag: (fffe, e000), VR: , Length: 18020
0x1476C2(1341122), tag: (fffe, e000), VR: , Length: 18112
0x14BD8A(1359242), tag: (fffe, e000), VR: , Length: 18200
0x1504AA(1377450), tag: (fffe, e000), VR: , Length: 18128
0x154B82(1395586), tag: (fffe, e000), VR: , Length: 18164
0x15927E(1413758), tag: (fffe, e000), VR: , Length: 18192
0x15D996(1431958), tag: (fffe, e000), VR: , Length: 18108
0x16205A(1450074), tag: (fffe, e000), VR: , Length: 18088
0x16670A(1468170), tag: (fffe, e000), VR: , Length: 18116
0x16ADD6(1486294), tag: (fffe, e000), VR: , Length: 18032
0x16F44E(1504334), tag: (fffe, e000), VR: , Length: 17976
0x173A8E(1522318), tag: (fffe, e000), VR: , Length: 18096
0x178146(1540422), tag: (fffe, e000), VR: , Length: 18016
0x17C7AE(1558446), tag: (fffe, e000), VR: , Length: 18032
0x180E26(1576486), tag: (fffe, e000), VR: , Length: 17996
0x18547A(1594490), tag: (fffe, e000), VR: , Length: 17964
0x189AAE(1612462), tag: (fffe, e000), VR: , Length: 17992
0x18E0FE(1630462), tag: (fffe, e000), VR: , Length: 17996
0x192752(1648466), tag: (fffe, e000), VR: , Length: 17952
0x196D7A(1666426), tag: (fffe, e000), VR: , Length: 17972
0x19B3B6(1684406), tag: (fffe, e000), VR: , Length: 17976
0x19F9F6(1702390), tag: (fffe, e0dd), VR: , Length: 0
このように,DICOMファイルの終端までエラーなく読むことができました.
0x29DA(10714), tag: (7fe0, 0010)
に格納されている情報が画像データとなっています.
次回
次回以降,各tagに入っているデータをチェックしていきましょう
なお,今回のコードでは,SQや項目タグの長さが明示されている場合にはうまく読み取れないかもしれません.
次回以降も,初回に記載したDICOMデータファイルで解読を進めます.