<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>너 1인분할수있어?</title>
    <link>https://chaechae0.tistory.com/</link>
    <description>1인분하는 개발자가 되어보자</description>
    <language>ko</language>
    <pubDate>Thu, 11 Jun 2026 22:08:52 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>odod00</managingEditor>
    <image>
      <title>너 1인분할수있어?</title>
      <url>https://tistory1.daumcdn.net/tistory/7844430/attach/978d4fd653324183ada4b3dc20f3b754</url>
      <link>https://chaechae0.tistory.com</link>
    </image>
    <item>
      <title>[DICOM] 파일 포맷, 보안/익명화, DICOMweb, Orthanc 실전</title>
      <link>https://chaechae0.tistory.com/46</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oleg Pianykh, Digital Imaging and Communications in Medicine (DICOM) (Springer, 2008) 정리 7편&lt;br /&gt;참고 챕터: Ch 10, Ch 11 + 책에 없는 PS3.18 (DICOMweb)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시리즈 마무리 글&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;DICOM 파일 포맷&lt;/b&gt; &amp;mdash; &lt;code&gt;DICM&lt;/code&gt; 헤더, Group 0002, DICOMDIR&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안 &amp;amp; 익명화&lt;/b&gt; &amp;mdash; HIPAA, 환자 데이터 보호의 함정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DICOMweb&lt;/b&gt; &amp;mdash; 책에 없는 현대 PACS의 표준&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Orthanc 실전 통합 시나리오&lt;/b&gt; &amp;mdash; AI 추론 앱 전체 파이프라인&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시리즈 정리 + 다음 학습 방향&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. DICOM 파일 포맷 구조&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.1 전체 레이아웃&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;┌──────────────────────────────────────┐
│  Preamble (128 bytes, 보통 모두 0)    │
├──────────────────────────────────────┤
│  Magic: &quot;DICM&quot; (4 bytes)              │
├──────────────────────────────────────┤
│  File Meta Information (group 0002)   │  &amp;larr; Explicit VR 강제
│  - Transfer Syntax UID                │
│  - SOP Class UID                      │
│  - SOP Instance UID                   │
│  - ...                                │
├──────────────────────────────────────┤
│  Data Object (group 0008 이상)         │  &amp;larr; Meta에서 명시한 Transfer Syntax로
│  - Patient Name, ID, ...              │
│  - Image Pixel Data                   │
│  - ...                                │
└──────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.2 Preamble (128 byte)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;첫 128 byte&lt;/b&gt;는 자유롭게 사용&lt;/li&gt;
&lt;li&gt;표준은 내용을 지정 안 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대부분의 구현이 그냥 0으로 채움&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;TIFF 등 다른 포맷도 같은 관행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  일부 응용에서 활용 가능: 예를 들어 이 영역에 small thumbnail BMP를 넣어두면 비-DICOM 뷰어에서도 미리보기 가능. 거의 안 쓰임.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.3 &quot;DICM&quot; Magic Header&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;byte 129~132&lt;/b&gt;: 정확히 &lt;code&gt;'D' 'I' 'C' 'M'&lt;/code&gt; 4글자&lt;/li&gt;
&lt;li&gt;이게 &lt;b&gt;DICOM 파일 식별의 유일한 신뢰 가능한 방법&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;파일 확장자도, UID도, 이름도 다 못 믿음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;def is_dicom_file(path):
    with open(path, 'rb') as f:
        f.seek(128)
        return f.read(4) == b'DICM'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ 옛 ACR-NEMA 2.0 파일은 DICM 헤더 없음. 점점 드물어짐.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.4 File Meta Information (Group 0002)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;byte 133부터 시작. &lt;b&gt;Explicit VR Little Endian으로 강제 인코딩&lt;/b&gt;.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;이름&lt;/th&gt;
&lt;th&gt;VR&lt;/th&gt;
&lt;th&gt;필수&lt;/th&gt;
&lt;th&gt;비고&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0002, 0000)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Group Length&lt;/td&gt;
&lt;td&gt;UL&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;group 0002 전체 길이&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0002, 0001)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;File Meta Version&lt;/td&gt;
&lt;td&gt;OB&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x00 0x01&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0002, 0002)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Media Storage SOP Class UID&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;UI&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;이 파일이 어떤 IOD인지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0002, 0003)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Media Storage SOP Instance UID&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;UI&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;이 인스턴스의 UID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0002, 0010)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Transfer Syntax UID&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;UI&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;&lt;b&gt;데이터 영역 인코딩 방식&lt;/b&gt; ⭐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0002, 0012)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Implementation Class UID&lt;/td&gt;
&lt;td&gt;UI&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;누가 만들었나&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0002, 0013)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Implementation Version Name&lt;/td&gt;
&lt;td&gt;SH&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;&amp;le;16자! (&lt;a href=&quot;./06-Association.md&quot;&gt;6편 &amp;sect;7.2&lt;/a&gt; 함정)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0002, 0016)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Source AET&lt;/td&gt;
&lt;td&gt;AE&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;어느 AE가 마지막 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0002, 0100)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Private Info Creator UID&lt;/td&gt;
&lt;td&gt;UI&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0002, 0102)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Private Information&lt;/td&gt;
&lt;td&gt;OB&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⭐ &lt;b&gt;&lt;code&gt;(0002, 0010) Transfer Syntax UID&lt;/code&gt;가 가장 중요.&lt;/b&gt; 이 값에 따라 그 뒤 Data Object를 Implicit/Explicit/압축 중 어떤 걸로 읽을지 결정.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.5 Data Object (group 0008 이상)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;우리가 &lt;a href=&quot;https://chaechae0.tistory.com/41&quot;&gt;2편&lt;/a&gt;에서 본 그 객체&lt;/li&gt;
&lt;li&gt;Meta의 Transfer Syntax UID에 따라 인코딩&lt;/li&gt;
&lt;li&gt;group 0008부터 시작 (group 0002 = meta, group 0004 = directory)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;함정&lt;/b&gt;: 많은 DICOM 구현이 group 0002는 Explicit으로 잘 읽다가 Data 영역에서 &lt;b&gt;Transfer Syntax 전환을 깜빡&lt;/b&gt;해서 깨짐.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.6 ⚠️ 파일 이름 함정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM 표준 PS3.10이 정의하는 File ID:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트 8개, 각 8자 이내&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대문자/숫자/언더스코어만&lt;/b&gt; (&lt;code&gt;A-Z 0-9 _&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;컴포넌트는 &lt;code&gt;\&lt;/code&gt; 로 구분 (예: &lt;code&gt;DIR1\SUBDIR\ABC123&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 1: 백슬래시 &lt;code&gt;\&lt;/code&gt; 는 DICOM 와일드카드!&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;erlang&quot;&gt;&lt;code&gt;&quot;DIR1\SUBDIR\ABC123&quot; = ?
  &amp;rarr; 파일 경로?
  &amp;rarr; 아니면 &quot;DIR1 OR SUBDIR OR ABC123&quot; ?
  &amp;rarr; DICOM 소프트웨어가 헷갈림. 흔한 버그.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결&lt;/b&gt;: 내부에서는 &lt;code&gt;/&lt;/code&gt; 로 통일.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 2: &lt;code&gt;.dcm&lt;/code&gt; 확장자&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;표준에 명시 안 됨 (어떤 곳은 prohibited, 어떤 곳은 required)&lt;/li&gt;
&lt;li&gt;실무에선 다 쓰지만 &lt;b&gt;공식적으로 모호함&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 3: 실무에서는 SOP Instance UID를 파일명으로 쓰는 게 흔함&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;1.2.840.10008.234.2354.437345.79086.dcm
1.2.840.10008.5.1.4.1.1.4.20260601.103014.0042.dcm&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점: 항상 unique&lt;/li&gt;
&lt;li&gt;단점: 너무 김 (Windows 경로 제한 260자 부딪힐 수 있음)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;AI 추론 앱 / Orthanc 시 권장&lt;/b&gt;:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;파일명에 환자 정보 절대 노출 X (보안)&lt;/li&gt;
&lt;li&gt;SOP Instance UID 기반 (전역 유일)&lt;/li&gt;
&lt;li&gt;디렉토리 구조로 정리: &lt;code&gt;{StudyUID}/{SeriesUID}/{SOPInstanceUID}.dcm&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. DICOMDIR &amp;mdash; 미디어 인덱스 파일&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 무엇인가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DVD/CD/USB 같은 &lt;b&gt;이동식 미디어&lt;/b&gt;에 DICOM 영상을 담을 때 함께 들어있는 &lt;b&gt;인덱스 파일&lt;/b&gt;.&lt;/p&gt;
&lt;pre class=&quot;erlang&quot;&gt;&lt;code&gt;DICOM_CD/
├── DICOMDIR          &amp;larr; 이 파일이 인덱스
├── IMAGES/
│   ├── STUDY01/
│   │   ├── SERIES01/
│   │   │   ├── IMG001
│   │   │   ├── IMG002
│   │   │   └── ...
│   │   └── SERIES02/
│   └── STUDY02/
└── ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM CD를 PC에 넣었을 때 뷰어가 &quot;환자 / 검사 / 시리즈 / 영상 목록&quot; 을 트리로 보여주는 게 &lt;b&gt;DICOMDIR을 읽어서&lt;/b&gt; 만든 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 구조&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOMDIR도 &lt;b&gt;하나의 DICOM 파일&lt;/b&gt;. group 0002 + Basic Directory IOD.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;DICOMDIR (자체도 DICOM 파일)
├── Preamble + DICM
├── Group 0002 (File Meta)
└── Data Object (Basic Directory IOD)
    ├── (0004, 1130) File Set ID
    ├── (0004, 1200) Offset of first root record
    ├── (0004, 1220) Directory Record Sequence (SQ)
    │   ├── Item 1: PATIENT record
    │   ├── Item 2: STUDY record
    │   ├── Item 3: SERIES record
    │   ├── Item 4: IMAGE record (파일 위치 포함)
    │   ├── Item 5: IMAGE record
    │   └── ...
    └── ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3 Directory Record 종류&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;(0004, 1430) Directory Record Type&lt;/code&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;PATIENT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;STUDY&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SERIES&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IMAGE&lt;/code&gt; ⭐ &amp;mdash; 실제 파일 위치 포함&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OVERLAY&lt;/code&gt;, &lt;code&gt;WAVEFORM&lt;/code&gt;, &lt;code&gt;SR DOCUMENT&lt;/code&gt;, ...&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 IMAGE record에는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;(0004, 1500)&lt;/code&gt; Referenced File ID &amp;mdash; 파일 경로&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(0004, 1510)&lt;/code&gt; Referenced SOP Class UID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(0004, 1511)&lt;/code&gt; Referenced SOP Instance UID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(0004, 1512)&lt;/code&gt; Referenced Transfer Syntax UID&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; DICOMDIR만 읽어도 어떤 환자 / 검사가 들어있는지 빠르게 파악 가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.4 AI 추론 앱에서의 활용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;병원 외부에서 받은 &lt;b&gt;CD/DVD에 담긴 영상&lt;/b&gt;을 AI 추론 앱이 처리해야 할 때:&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;import pydicom

# DICOMDIR 읽기
dcmdir = pydicom.dcmread(&quot;D:/DICOMDIR&quot;)

# 환자/검사/시리즈/영상 트리 순회
for patient_record in dcmdir.patient_records:
    print(f&quot;Patient: {patient_record.PatientName}&quot;)
    for study in patient_record.children:
        print(f&quot;  Study: {study.StudyDate}&quot;)
        for series in study.children:
            print(f&quot;    Series: {series.Modality}&quot;)
            for image in series.children:
                # 실제 파일 위치
                rel_path = &quot;/&quot;.join(image.ReferencedFileID)
                file_path = f&quot;D:/{rel_path}&quot;
                ds = pydicom.dcmread(file_path)
                # AI 추론 입력으로 사용&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  Orthanc 사용 시: &lt;b&gt;REST API로 DICOMDIR 자동 생성 가능&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;GET /studies/{id}/media   &amp;rarr; DICOMDIR + 영상 zip&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.5 한계&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DICOMDIR 작성에는 &lt;b&gt;모든 영상이 사전에 다 있어야&lt;/b&gt; 함 (length 미리 계산)&lt;/li&gt;
&lt;li&gt;영상 추가/삭제 시 DICOMDIR 다시 빌드 필요&lt;/li&gt;
&lt;li&gt;실무에서는 &lt;b&gt;자동 생성에 맡기는 게 정신건강에 좋음&lt;/b&gt; (Orthanc, dcm4chee 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. DICOM 보안 &amp;mdash; 평문 그대로 노출&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 ⚠️ 충격적 사실: DICOM 파일은 사실상 평문&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자의 hacking 데모. &lt;b&gt;메모장(WordPad)으로 열어도 환자 정보가 보임&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;(binary garbage) DICM (binary)
... SMITH^JOHN ... 19560423 ... M ... PATIENT123 ... DR.KIM ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름, ID, 생년월일이 그냥 ASCII로 박혀 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 평문 = 변조 가능&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자가 시연&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;WordPad에서 DICOM 파일 열기&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SMITH^JOE&lt;/code&gt; 검색&lt;/li&gt;
&lt;li&gt;&lt;b&gt;같은 길이&lt;/b&gt;(9자)로 다른 이름 입력 (&lt;code&gt;BETH^MARY&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;저장 &amp;rarr; DICOM 뷰어에서 환자 이름이 바뀌어 보임&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; VR length가 변하지 않게 같은 길이로 바꾸면 &lt;b&gt;DICOM 구조 그대로 유지&lt;/b&gt;되면서 데이터 변조됨. 어떤 DICOM 검증도 못 잡음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3 ⚠️ 픽셀 추출도 단순함&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자의 또 다른 시연:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CT/MR 영상이 보통 256&amp;times;256 또는 512&amp;times;512, 1 or 2 byte/pixel&lt;/li&gt;
&lt;li&gt;파일 크기 보고 차원 추측&lt;/li&gt;
&lt;li&gt;&lt;b&gt;파일 끝에서 N&amp;times;N&amp;times;bytes 만큼 잘라내면 그게 픽셀&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;BMP로 변환 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; DICOM 파일은 &lt;b&gt;암호화되지 않으면 평문&lt;/b&gt;. PACS 시스템 전체를 보호망으로 둘러싸야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Workflow 보안 &amp;mdash; 환경 단단히&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1 기본 원칙 (HIPAA 베스트)&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;전용 서버에 격리&lt;/b&gt; &amp;mdash; 영상 서버에 다른 서비스 X&lt;/li&gt;
&lt;li&gt;&lt;b&gt;물리적 보안&lt;/b&gt; &amp;mdash; 잠긴 방, 출입 통제&lt;/li&gt;
&lt;li&gt;&lt;b&gt;백업 매일&lt;/b&gt; &amp;mdash; 영상 손실은 회복 불가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다른 의료기관과 서버 공유 절대 금지&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용자별 권한 분리&lt;/b&gt; &amp;mdash; 각자 자기 데이터만&lt;/li&gt;
&lt;li&gt;&lt;b&gt;VPN + 방화벽&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자동 화면 잠금&lt;/b&gt; (15분 idle)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2 VPN vs 방화벽 &amp;mdash; 자주 헷갈림&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&amp;nbsp;&lt;/th&gt;
&lt;th&gt;방화벽&lt;/th&gt;
&lt;th&gt;VPN&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;보호 범위&lt;/td&gt;
&lt;td&gt;&lt;b&gt;단일 컴퓨터&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;두 컴퓨터 간 통신 전체&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;통신 자체 암호화&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;외부 접근 차단&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;방화벽만으로는 부족.&lt;/b&gt; 데이터가 공용망을 지나가면 평문 노출. &lt;b&gt;VPN 필수&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.3 ❌ 안티패턴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자가 본 사고:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;그냥 우리 서버에 로그인해서 봐주세요&quot; &amp;mdash; 가장 흔하고 가장 위험&lt;/li&gt;
&lt;li&gt;&quot;옛날 DOS 컴퓨터가 보안이 낫다&quot; &amp;mdash; 정반대. 권한 관리 자체가 없음&lt;/li&gt;
&lt;li&gt;&quot;컴퓨터를 안 쓰면 보안이 좋다&quot; &amp;mdash; 잠긴 문 없는 은행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.4 ⭐ HIPAA가 정의한 18가지 PHI (Protected Health Information)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM에서 제거/익명화 대상:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이름 (Name)&lt;/li&gt;
&lt;li&gt;지리 정보 (주보다 작은 단위, 우편번호 포함)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;날짜&lt;/b&gt; (생년월일, 입원, 퇴원, 검사 등 모든 날짜)&lt;/li&gt;
&lt;li&gt;전화번호&lt;/li&gt;
&lt;li&gt;팩스&lt;/li&gt;
&lt;li&gt;이메일&lt;/li&gt;
&lt;li&gt;사회보장번호&lt;/li&gt;
&lt;li&gt;&lt;b&gt;의료기록번호&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;보험 수혜자 번호&lt;/li&gt;
&lt;li&gt;계좌번호&lt;/li&gt;
&lt;li&gt;자격증/면허 번호&lt;/li&gt;
&lt;li&gt;차량 식별번호&lt;/li&gt;
&lt;li&gt;장비 시리얼 번호&lt;/li&gt;
&lt;li&gt;URL&lt;/li&gt;
&lt;li&gt;IP 주소&lt;/li&gt;
&lt;li&gt;생체 식별자 (지문, 음성)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;얼굴 전체 사진&lt;/b&gt; (CT/MR head로 3D 재구성 가능!)&lt;/li&gt;
&lt;li&gt;기타 식별 가능한 모든 코드&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;17번이 의외의 함정&lt;/b&gt;. Head CT/MR을 3D rendering하면 얼굴 복원됨. 진정한 익명화 어려움.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 익명화 (Anonymization) ⭐⭐⭐&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PACS 통신 모듈에서 가장 중요한 보안 작업.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1 익명화 정의&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;원본 파일에서 PHI를 제거하거나 변환&lt;/b&gt;해 환자 식별 불가능하게 만드는 작업.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;비가역적&lt;/b&gt; (irreversible) &amp;mdash; 일반적으로 원본 복원 불가&lt;/li&gt;
&lt;li&gt;그래서 &lt;b&gt;암호화보다 안전&lt;/b&gt;: 해커도 없는 데이터는 못 뽑음&lt;/li&gt;
&lt;li&gt;단점: &lt;b&gt;임상 가치 손상 가능성&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.2 단순 wipe의 함정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;❌ 잘못된 익명화&lt;/b&gt;: Patient ID를 빈 값으로&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;(0010, 0020) Patient ID = &quot;&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DICOM 표준: Patient ID는 &lt;b&gt;Type 1&lt;/b&gt; (필수 + 값 필수)&lt;/li&gt;
&lt;li&gt;빈 값 = &lt;b&gt;와일드카드로 해석&lt;/b&gt;될 수도 (&lt;a href=&quot;./03-Hierarchy-IOD.md&quot;&gt;3편 &amp;sect;2.2&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;결과: &lt;b&gt;모든 환자가 한 명으로 merge&lt;/b&gt; &amp;rarr; &quot;Mr. Unknown&quot; 사고&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.3 일관성 (Consistency) 함정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;❌ 잘못된 익명화&lt;/b&gt;: 같은 환자를 다르게 매핑&lt;/p&gt;
&lt;pre class=&quot;arcade&quot;&gt;&lt;code&gt;Day 1:  Patient ID &quot;12345&quot; &amp;rarr; &quot;anon_001&quot;
Day 2:  Patient ID &quot;12345&quot; &amp;rarr; &quot;anon_487&quot;   &amp;larr; 다른 값!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과: &lt;b&gt;같은 환자의 시간순 검사가 분리&lt;/b&gt; &amp;rarr; 추적 불가, 임상 가치 0.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 올바른 익명화&lt;/b&gt;: 결정론적 매핑 (deterministic)&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;# 같은 원본 &amp;rarr; 항상 같은 가명
import hashlib

def anonymize_patient_id(original_id, salt):
    h = hashlib.sha256((original_id + salt).encode()).hexdigest()
    return f&quot;ANON_{h[:12]}&quot;

anonymize_patient_id(&quot;12345&quot;, salt=&quot;my_secret&quot;)
# &amp;rarr; 항상 &quot;ANON_a8f3c4d2e9b1&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 매번 같은 결과. 같은 환자 = 같은 가명. 다른 환자 = 다른 가명.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.4 충돌 함정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시 출력 공간이 좁으면 &lt;b&gt;다른 환자 &amp;rarr; 같은 가명&lt;/b&gt; 가능.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;# ❌ 위험: 16비트만 사용 &amp;rarr; 65,536명 넘으면 collision
short_id = h[:4]

# ✅ 안전: 충분히 긴 prefix
long_id = h[:16]   # 16^16 가지&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.5 픽셀에 박힌 정보 (Burned-in PHI) ⚠️&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;US, 일부 X-ray는 &lt;b&gt;픽셀 데이터에 환자 이름이 그려져&lt;/b&gt; 있음.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;┌──────────────────────────────────┐
│  PATIENT: SMITH^JOHN             │  &amp;larr; 이 부분이 픽셀!
│  ID: 12345                       │  &amp;larr; Tag로는 못 지움
│  DATE: 2026-06-10                │
│ ┌──────────────────────────────┐ │
│ │                              │ │
│ │      [Ultrasound]            │ │
│ │                              │ │
│ └──────────────────────────────┘ │
└──────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;태그만 익명화하면 픽셀의 텍스트는 그대로 남음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결책&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단순: 상단 N픽셀을 검은색으로 (US 헤더 영역) &amp;rarr; 임상 정보 손실 위험&lt;/li&gt;
&lt;li&gt;OCR로 텍스트 영역 인식 &amp;rarr; 자동화 어려움&lt;/li&gt;
&lt;li&gt;메타데이터 &lt;code&gt;(0028, 0301) Burned In Annotation = &quot;YES&quot;&lt;/code&gt; 가 있는지 확인 + 사람 검수&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;실무 추천&lt;/b&gt;: Burned-in 가능 modality (US, 일부 X-ray) 는 &lt;b&gt;반드시 사람 검수&lt;/b&gt; 단계 거치기.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.6 임상 가치 균형&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자의 노하우: &lt;b&gt;HIPAA 18가지를 다 지우면 임상 데이터로 못 씀&lt;/b&gt;.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;HIPAA&lt;/th&gt;
&lt;th&gt;임상적 가치&lt;/th&gt;
&lt;th&gt;권장&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Patient Name&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;낮음&lt;/td&gt;
&lt;td&gt;익명화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patient ID&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;낮음&lt;/td&gt;
&lt;td&gt;결정론적 매핑&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Birth Date&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;&lt;b&gt;나이 계산에 필요&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;연도만 남기거나 나이로 변환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patient Age&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;&lt;b&gt;중간&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;보통 남김&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Study Date&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;&lt;b&gt;시계열 추적에 필수&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;남기는 게 표준 (저자 권장)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Study Description&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;&lt;b&gt;높음&lt;/b&gt; (예: &quot;Prostate MR Protocol&quot;)&lt;/td&gt;
&lt;td&gt;남김&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patient Weight&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;임상 중요&lt;/td&gt;
&lt;td&gt;남김&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patient Comments&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;가변&lt;/td&gt;
&lt;td&gt;검토 후 결정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Referring Physician&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;낮음&lt;/td&gt;
&lt;td&gt;제거&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Institution Name&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;낮음&lt;/td&gt;
&lt;td&gt;제거 또는 일반화&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  저자: &quot;Study Date를 지우면 진단 데이터로서 가치가 사라진다. &lt;b&gt;read radiologist에게는 남기되, 공개 시에는 월 단위로 jitter&lt;/b&gt; (예: &amp;plusmn;15일 random shift, 환자별 일관).&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.7 ⚠️ 안 좋은 패턴 &amp;mdash; 사설 태그로 숨기기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자가 발견한 어처구니 없는 익명화 도구:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;원본 (0010, 0010) Patient Name = &quot;SMITH^JOHN&quot;
&amp;rarr; 익명화 후:
  (0010, 0010) = &quot;ANON_X1&quot;        &amp;larr; 가명
  (0099, 1010) = &quot;SMITH^JOHN&quot;     &amp;larr; 원본을 사설 태그에 숨김 ⚠️&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WordPad로 열면 그대로 보임. &lt;b&gt;&quot;숨기기&quot;는 보안이 아니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.8 권장 익명화 도구&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표준 + 검증된 도구:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;DICOM PS3.15 Annex E&lt;/b&gt; &amp;mdash; 공식 익명화 가이드라인&lt;/li&gt;
&lt;li&gt;&lt;b&gt;gdcmanon&lt;/b&gt; (GDCM의 익명화) &amp;mdash; 오픈소스&lt;/li&gt;
&lt;li&gt;&lt;b&gt;dcm4che &lt;code&gt;dcm2dcm&lt;/code&gt;&lt;/b&gt; + 익명화 프로파일&lt;/li&gt;
&lt;li&gt;&lt;b&gt;pydicom-anonymizer&lt;/b&gt; (간단한 Python 도구)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Orthanc 익명화 API&lt;/b&gt; ⭐&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Orthanc 익명화 예시&lt;/h4&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;import requests

# POST: Study 단위 익명화
r = requests.post(
    &quot;http://orthanc:8042/studies/{study_id}/anonymize&quot;,
    json={
        &quot;Replace&quot;: {
            &quot;PatientName&quot;: &quot;ANON_001&quot;,
            &quot;PatientID&quot;: &quot;ANON_001&quot;
        },
        &quot;Keep&quot;: [
            &quot;StudyDescription&quot;,
            &quot;SeriesDescription&quot;,
            &quot;StudyDate&quot;     # 임상 가치 위해 유지
        ],
        &quot;KeepPrivateTags&quot;: False,   # 사설 태그 제거
        &quot;Force&quot;: True,
        &quot;DicomVersion&quot;: &quot;2021b&quot;      # PS3.15 프로파일 버전
    }
)

# 결과: 새 익명 study가 생성됨
new_study_id = r.json()[&quot;ID&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Orthanc는 &lt;b&gt;PS3.15 Annex E 표준 프로파일을 자동 적용&lt;/b&gt;. 안전한 default.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 암호화 (Encryption)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.1 익명화 vs 암호화&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&amp;nbsp;&lt;/th&gt;
&lt;th&gt;익명화&lt;/th&gt;
&lt;th&gt;암호화&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;가역성&lt;/td&gt;
&lt;td&gt;&lt;b&gt;비가역&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;가역&lt;/b&gt; (키 있으면 복원)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;목적&lt;/td&gt;
&lt;td&gt;정보 자체 제거&lt;/td&gt;
&lt;td&gt;정보 숨김&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;임상 손실&lt;/td&gt;
&lt;td&gt;가능&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;위험&lt;/td&gt;
&lt;td&gt;키 분실 시 영구 손실&lt;/td&gt;
&lt;td&gt;키 분실 시 복호화 불가&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.2 알고리즘 &amp;mdash; DICOM이 채택한 것들&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;알고리즘&lt;/th&gt;
&lt;th&gt;종류&lt;/th&gt;
&lt;th&gt;용도&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;RSA&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;비대칭&lt;/td&gt;
&lt;td&gt;키 교환, 디지털 서명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;AES&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;대칭&lt;/td&gt;
&lt;td&gt;대용량 데이터 암호화 (현대 표준)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DES&lt;/b&gt;, &lt;b&gt;3DES&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;대칭&lt;/td&gt;
&lt;td&gt;(구식, 점점 비추)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;SHA-1/256/512&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;해시&lt;/td&gt;
&lt;td&gt;무결성 검증&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.3 공개키/개인키 &amp;mdash; 돼지저금통 비유 ⭐&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자의 비유:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;돼지저금통&lt;/b&gt;: 동전 넣기는 쉬움, 꺼내기는 키 없으면 어려움&lt;/li&gt;
&lt;li&gt;같은 원리: &lt;b&gt;공개키로 암호화는 쉬움, 개인키 없이 복호화는 사실상 불가능&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수학적 기반: &lt;b&gt;큰 소수 인수분해&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 큰 소수 A &amp;times; B = N (곱셈은 빠름)&lt;/li&gt;
&lt;li&gt;N에서 A, B 찾기 (인수분해는 매우 느림)&lt;/li&gt;
&lt;li&gt;A를 알려주면 B = N / A (나눗셈은 빠름)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 이게 RSA의 핵심.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.4 SHA 무결성 검증&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;원본 데이터 &amp;rarr; SHA-256 &amp;rarr; 짧은 hash 문자열 (32 byte)

데이터 + hash 를 같이 전송
받는 쪽에서 다시 SHA-256 돌려서 일치 확인
&amp;rarr; 1바이트라도 변조되면 hash 완전히 다름&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://chaechae0.tistory.com/44&quot;&gt;5편 &amp;sect;8.1&lt;/a&gt;의 Storage Commitment와 결합 가능: &quot;받았는데 무결한가?&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.5 디지털 서명 vs 스캔 서명&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;디지털 서명 &amp;ne; 스캔된 사인 이미지&lt;/b&gt;.&lt;/p&gt;
&lt;pre class=&quot;haml&quot;&gt;&lt;code&gt;❌ 가짜 디지털 서명:
  - 사인을 사진으로 찍어서 PDF에 붙이기
  - &quot;Signed by: 김의사&quot; 텍스트
  - 단순 체크박스

✅ 진짜 디지털 서명:
  - 인증기관(CA)에서 발급한 인증서
  - 개인키로 서명
  - 공개키로 검증
  - 변조 시 무효화
  - 서명 시점/위치/이유 기록&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM PS3.15 Annex C에서 정의. SR(Structured Report) 에 서명 첨부 가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.6 Secure DICOM File Format (Ch 10.2.2)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PS3.10이 정의하는 보안 파일 포맷:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전체 DICOM 파일을 &lt;b&gt;하나의 암호화된 객체로 래핑&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;키 없이는 group 0002조차 못 봄&lt;/li&gt;
&lt;li&gt;디지털 서명 첨부 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;현실&lt;/b&gt;: 거의 모든 PACS가 미지원. 표준이 너무 모호. &lt;b&gt;VPN + 안전한 저장 환경&lt;/b&gt;으로 보안하는 게 표준 패턴.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. DICOMweb &amp;mdash; 책에 없지만 현대 PACS의 표준 ⭐&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Pianykh 책 2008년판에는 없음.&lt;/b&gt; 하지만 현대 PACS 통신에서 빠질 수 없는 표준 (PS3.18, 2011~).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.1 등장 배경&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DIMSE의 한계 (&lt;a href=&quot;./06-Association.md&quot;&gt;6편 &amp;sect;13&lt;/a&gt;):&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;점-대-점 정적 등록&lt;/b&gt; (AE Title + IP + Port 사전 등록)&lt;/li&gt;
&lt;li&gt;방화벽 친화적이지 않음 (특히 C-Move)&lt;/li&gt;
&lt;li&gt;모바일/웹/클라우드와 잘 안 맞음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOMweb의 해결:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;HTTP REST API&lt;/b&gt; 기반&lt;/li&gt;
&lt;li&gt;정적 등록 불필요&lt;/li&gt;
&lt;li&gt;방화벽 통과 (HTTPS 사용)&lt;/li&gt;
&lt;li&gt;JSON 응답 가능 (XML/DICOM도 가능)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.2 3개 핵심 서비스&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;DIMSE&lt;/th&gt;
&lt;th&gt;DICOMweb&lt;/th&gt;
&lt;th&gt;역할&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;C-Store&lt;/td&gt;
&lt;td&gt;&lt;b&gt;STOW-RS&lt;/b&gt; (Store Over the Web)&lt;/td&gt;
&lt;td&gt;영상 업로드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C-Find&lt;/td&gt;
&lt;td&gt;&lt;b&gt;QIDO-RS&lt;/b&gt; (Query based on ID for DICOM Objects)&lt;/td&gt;
&lt;td&gt;검색&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C-Move / C-Get&lt;/td&gt;
&lt;td&gt;&lt;b&gt;WADO-RS&lt;/b&gt; (Web Access to DICOM Objects)&lt;/td&gt;
&lt;td&gt;다운로드&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.3 QIDO-RS &amp;mdash; 검색&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;GET /studies?PatientID=12345&amp;amp;StudyDate=20260601-
Accept: application/dicom+json&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;응답 (JSON):&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;[
  {
    &quot;0020000D&quot;: {&quot;vr&quot;: &quot;UI&quot;, &quot;Value&quot;: [&quot;1.2.840.xxx&quot;]},
    &quot;00100010&quot;: {&quot;vr&quot;: &quot;PN&quot;, &quot;Value&quot;: [{&quot;Alphabetic&quot;: &quot;SMITH^JOHN&quot;}]},
    &quot;00100020&quot;: {&quot;vr&quot;: &quot;LO&quot;, &quot;Value&quot;: [&quot;12345&quot;]},
    &quot;00080020&quot;: {&quot;vr&quot;: &quot;DA&quot;, &quot;Value&quot;: [&quot;20260601&quot;]},
    &quot;00080060&quot;: {&quot;vr&quot;: &quot;CS&quot;, &quot;Value&quot;: [&quot;MR&quot;]}
  },
  ...
]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;JSON으로 응답하니까 웹 프론트엔드에서 바로 사용 가능.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.4 WADO-RS &amp;mdash; 다운로드&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Study 통째로&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;GET /studies/{StudyUID}
Accept: multipart/related; type=&quot;application/dicom&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; Multipart 응답으로 모든 영상 받음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;단일 영상 메타데이터만 (JSON)&lt;/h4&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;GET /studies/{StudyUID}/series/{SeriesUID}/instances/{SOPUID}/metadata
Accept: application/dicom+json&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;픽셀만 (rendered PNG/JPEG)&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;GET /studies/.../instances/.../rendered?window=400,40
Accept: image/jpeg&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;브라우저에서 바로 표시 가능!&lt;/b&gt; 별도 DICOM 디코더 불필요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.5 STOW-RS &amp;mdash; 업로드&lt;/h3&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;POST /studies
Content-Type: multipart/related; type=&quot;application/dicom&quot;

(여러 DICOM 파일을 multipart로 첨부)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.6 DICOMweb의 장점&lt;/h3&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;                  DIMSE                    DICOMweb
                ────────                  ──────────
연결            점-대-점 정적 등록         HTTP 호출 즉시
인증            AE Title whitelist         OAuth2, JWT, Bearer Token
방화벽          C-Move 특히 곤란            HTTPS 1포트만
프론트엔드      DICOM 라이브러리 필요       JSON + rendered JPEG
스케일링        제한적                     로드밸런서 / CDN
캐싱            없음                      HTTP 캐시
모니터링        custom                    표준 HTTP 로그&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.7 Orthanc의 DICOMweb 플러그인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Orthanc는 &lt;b&gt;공식 DICOMweb 플러그인&lt;/b&gt; 제공:&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;// orthanc.json
{
  &quot;Plugins&quot;: [
    &quot;/usr/share/orthanc/plugins/libOrthancDicomWeb.so&quot;
  ],
  &quot;DicomWeb&quot;: {
    &quot;Enable&quot;: true,
    &quot;Root&quot;: &quot;/dicom-web/&quot;,
    &quot;EnableMetadata&quot;: true,
    &quot;PublicRoot&quot;: &quot;https://my-hospital.com/dicom-web/&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 자동으로&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;/dicom-web/studies&lt;/code&gt; (QIDO-RS)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/dicom-web/studies/{uid}/series/...&lt;/code&gt; (WADO-RS)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /dicom-web/studies&lt;/code&gt; (STOW-RS)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔드포인트 활성화.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.8 ⚠️ DIMSE를 안 버리는 이유&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기존 PACS / modality의 90%가 DIMSE만 지원&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;DICOMweb 지원 PACS는 신형/고급&lt;/li&gt;
&lt;li&gt;&lt;b&gt;현실의 통합 모듈은 DIMSE + DICOMweb 둘 다&lt;/b&gt; 지원해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  Orthanc는 &lt;b&gt;양쪽 다 동시 지원&lt;/b&gt;. DIMSE로 받고 DICOMweb으로 노출 가능.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. AI 추론 앱 전체 통합 시나리오 (실전)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제까지 본 모든 개념을 종합한 &lt;b&gt;현실적 배포 아키텍처&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.1 아키텍처 다이어그램&lt;/h3&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;                      ┌─────────────────────────────────┐
                      │       병원 내부 네트워크          │
                      │                                  │
   ┌───────────┐      │   ┌─────────────────────────┐  │
   │           │      │   │                          │  │
   │  CT/MR    │─DIMSE│   │   Hospital PACS          │  │
   │ Scanner   │─────&amp;rarr;│   │   (DIMSE + DICOMweb)     │  │
   │           │      │   │                          │  │
   └───────────┘      │   └────────┬────────────────┘  │
                      │            │                    │
                      │            │ DIMSE (C-Store/Move)│
                      │            │ 또는 DICOMweb        │
                      │            &amp;darr;                    │
                      │   ┌─────────────────────────┐  │
                      │   │     Orthanc (게이트웨이)   │  │
                      │   │                          │  │
                      │   │  ┌─────────────────────┐ │  │
                      │   │  │  DIMSE SCP (4242)    │ │  │
                      │   │  │  DICOMweb (8042)     │ │  │
                      │   │  └─────────────────────┘ │  │
                      │   │                          │  │
                      │   │  Lua / Python plugin     │  │
                      │   │  └─&amp;rarr; AI 추론 트리거        │ │  │
                      │   └────────┬────────────────┘  │
                      │            │                    │
                      │            &amp;darr;                    │
                      │   ┌─────────────────────────┐  │
                      │   │   AI 추론 앱              │  │
                      │   │   (nnU-Net, etc.)        │  │
                      │   │                          │  │
                      │   │  ┌─────────────────────┐ │  │
                      │   │  │ Preprocessing       │ │  │
                      │   │  │ Inference (GPU)     │ │  │
                      │   │  │ Postprocessing      │ │  │
                      │   │  │ DICOM SC/SR 생성     │ │  │
                      │   │  └─────────────────────┘ │  │
                      │   └────────┬────────────────┘  │
                      │            │                    │
                      │            │ 결과 업로드          │
                      │            &amp;darr;                    │
                      │   ┌─────────────────────────┐  │
                      │   │     Orthanc             │  │
                      │   │  &amp;rarr; DIMSE C-Store        │  │
                      │   │  &amp;rarr; Hospital PACS         │  │
                      │   └──────────────────────────┘  │
                      └─────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.2 단계별 흐름&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Step 1: 의사 트리거&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PACS UI 또는 별도 시스템에서 &lt;b&gt;&quot;이 환자 AI 분석&quot;&lt;/b&gt; 클릭.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Step 2: PACS &amp;rarr; Orthanc로 영상 전달&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법 A (DIMSE):&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;PACS &amp;rarr; DIMSE C-Store &amp;rarr; Orthanc:4242
SOP Class UID: 1.2.840.10008.5.1.4.1.1.4 (MR)
Transfer Syntax: 1.2.840.10008.1.2 (Implicit VR LE)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법 B (DICOMweb):&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;PACS &amp;rarr; STOW-RS POST /dicom-web/studies &amp;rarr; Orthanc:8042&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Step 3: Orthanc Lua/Python 훅 &amp;rarr; AI 트리거&lt;/h4&gt;
&lt;pre class=&quot;lua&quot;&gt;&lt;code&gt;-- orthanc.json: &quot;LuaScripts&quot;: [&quot;./on_store.lua&quot;]
function OnStoredInstance(instanceId, tags, metadata)
    -- 어떤 modality + body part?
    if tags['Modality'] == 'MR' and
       string.find(tags['StudyDescription'] or '', 'PROSTATE') then
        -- AI 추론 앱 호출
        os.execute('curl -X POST http://ai-app:8080/infer?instance=' .. instanceId)
    end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Step 4: AI 추론&lt;/h4&gt;
&lt;pre class=&quot;nix&quot;&gt;&lt;code&gt;# AI 추론 앱 (Python)
@app.post(&quot;/infer&quot;)
def infer(instance: str):
    # Orthanc에서 영상 다운로드 (DICOMweb)
    r = requests.get(
        f&quot;http://orthanc:8042/instances/{instance}/file&quot;,
        auth=(&quot;user&quot;, &quot;pass&quot;)
    )
    ds = pydicom.dcmread(io.BytesIO(r.content))

    # 추론용 numpy array
    pixel_array = ds.pixel_array

    # 추론
    result = ai_model(pixel_array)
    segmentation_mask = result['mask']

    # Secondary Capture IOD 생성
    sc = create_secondary_capture(
        pixel_array=segmentation_mask,
        patient_id=ds.PatientID,            # 원본 유지
        study_uid=ds.StudyInstanceUID,      # 원본 유지!
        series_uid=generate_uid(),          # 새로 생성
        sop_instance_uid=generate_uid(),    # 새로 생성
        sop_class_uid=&quot;1.2.840.10008.5.1.4.1.1.7&quot;  # SC
    )

    # Orthanc에 다시 업로드 &amp;rarr; PACS로 자동 전달
    requests.post(
        &quot;http://orthanc:8042/instances&quot;,
        data=sc.tobytes(),
        headers={&quot;Content-Type&quot;: &quot;application/dicom&quot;}
    )&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Step 5: Orthanc &amp;rarr; PACS로 결과 송신&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Orthanc에 자동 라우팅 규칙 설정&lt;/p&gt;
&lt;pre class=&quot;lua&quot;&gt;&lt;code&gt;-- 결과 SC가 들어오면 자동 PACS 전송
function OnStoredInstance(instanceId, tags, metadata)
    if tags['Modality'] == 'SC' and
       string.find(tags['SeriesDescription'] or '', 'AI_RESULT') then
        SendToModality(instanceId, 'HOSPITAL_PACS')
    end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Step 6: PACS UI에 결과 표시&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PACS UI에서 환자 study 펼치면:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;SMITH^JOHN &amp;mdash; 2026-06-10 &amp;mdash; Prostate MR
├── Series 1: T2W axial
├── Series 2: DWI
├── Series 3: ADC
└── Series 99: AI_RESULT (Secondary Capture)   &amp;larr; AI 추론 결과&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.3 익명화가 필요한 시나리오&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연구 데이터로 외부 공유 시&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;# Orthanc 익명화 API
r = requests.post(
    f&quot;http://orthanc:8042/studies/{study_id}/anonymize&quot;,
    json={
        &quot;Replace&quot;: {
            &quot;PatientName&quot;: deterministic_anonymize(name, salt),
            &quot;PatientID&quot;: deterministic_anonymize(pid, salt)
        },
        &quot;Keep&quot;: [&quot;StudyDescription&quot;, &quot;SeriesDescription&quot;],
        &quot;KeepPrivateTags&quot;: False,
        &quot;Force&quot;: True
    }
)
# r.json()[&quot;Path&quot;] = 익명화된 새 study의 URL&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.4 최종 체크리스트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포 전 점검&lt;/p&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;☐ Orthanc + AI 앱이 분리된 네트워크 세그먼트
☐ Orthanc &amp;harr; PACS DIMSE 양방향 등록 완료
☐ C-Echo 양방향 verify 통과
☐ Transfer Syntax 협상 OK (Implicit LE + 압축 옵션)
☐ Max PDU Length 조정 (필요시 65536)
☐ Orthanc DICOMweb 활성화
☐ AI 결과 SOP Class UID 올바름 (SC 또는 SR)
☐ 결과의 Patient/Study UID 원본 유지
☐ 결과의 Series/SOP Instance UID 새로 생성
☐ 익명화 (연구 데이터인 경우)
☐ 모든 통신 VPN 또는 HTTPS
☐ Orthanc 인증 활성화 (RegisteredUsers)
☐ 로그 보존 + 외부 SIEM 연동
☐ 백업 정책
☐ 장애 시 fallback (큐, 재시도, 알림)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 시리즈 마무리 &amp;mdash; 전체 그림&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큰 그림으로 정리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9.1 7편 매핑&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;편&lt;/th&gt;
&lt;th&gt;주제&lt;/th&gt;
&lt;th&gt;핵심 개념&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;1편&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;DICOM 입문 + VR&lt;/td&gt;
&lt;td&gt;27가지 VR, Endian, 짝수 길이&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;2편&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Tag, Dictionary, Encoding&lt;/td&gt;
&lt;td&gt;(group,element), Implicit/Explicit, SQ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;3편&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;4계층 + IOD&lt;/td&gt;
&lt;td&gt;Patient/Study/Series/Image, Module &amp;rarr; IE &amp;rarr; IOD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;4편&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;C-Echo, C-Store, C-Find&lt;/td&gt;
&lt;td&gt;AE Title, SCU/SCP, DIMSE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;5편&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;C-Move, C-Get, MWL&lt;/td&gt;
&lt;td&gt;Q/R, SC/SR (AI 결과 출력 포맷)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;6편&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Association ⭐&lt;/td&gt;
&lt;td&gt;Abstract/Transfer Syntax 협상, PDU, &lt;b&gt;디버깅 본진&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;7편&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;파일, 보안, DICOMweb, Orthanc&lt;/td&gt;
&lt;td&gt;DICM 헤더, 익명화, REST API&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9.2 DICOM의 모순&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;아름다운 점&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1990년대 설계가 2026년에도 작동&lt;/li&gt;
&lt;li&gt;객체지향 모델 (IOD/SOP)&lt;/li&gt;
&lt;li&gt;모든 modality를 하나의 표준으로&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;불편한 점&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 표준이 16권 문서로 분산&lt;/li&gt;
&lt;li&gt;점-대-점 정적 등록의 한계&lt;/li&gt;
&lt;li&gt;&quot;No reason given&quot; 거부 메시지&lt;/li&gt;
&lt;li&gt;Implementation Version Name 16자 같은 사소한 함정&lt;/li&gt;
&lt;li&gt;시간대 미지원&lt;/li&gt;
&lt;li&gt;익명화 vs 임상 가치의 영원한 트레이드오프&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9.3 책에서 다 못 다룬 것 (별도 학습 권장)&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;주제&lt;/th&gt;
&lt;th&gt;학습 자료&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DICOMweb&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;DICOM PS3.18, &lt;a href=&quot;https://dicomweb.org&quot;&gt;dicomweb.org&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DICOM SEG&lt;/b&gt; (Segmentation 전용 SOP)&lt;/td&gt;
&lt;td&gt;PS3.3 Annex A.51&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DICOM SR Templates&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;David Clunie의 책&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;IHE Profiles&lt;/b&gt; (워크플로우 통합)&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.ihe.net&quot;&gt;ihe.net&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;HL7 FHIR + DICOM&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;FHIRcast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DICOM 표준 매뉴얼 (공식)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.dicomstandard.org&quot;&gt;dicomstandard.org&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9.4 다음 단계 &amp;mdash; 실전으로&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 시리즈가 &lt;b&gt;이론 + 개념&lt;/b&gt;까지 줬다면, 다음은:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Orthanc 직접 설치 + 가지고 놀기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DIMSE C-Echo, C-Store 보내보기&lt;/li&gt;
&lt;li&gt;DICOMweb 호출해보기&lt;/li&gt;
&lt;li&gt;Lua 스크립트로 자동화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;pynetdicom 으로 작은 SCU/SCP 직접 짜보기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;책의 표를 코드로 옮겨보기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Wireshark로 DIMSE 패킷 보기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;A-Associate-RQ/AC 까보기&lt;/li&gt;
&lt;li&gt;6편의 PDU 구조가 진짜로 그렇게 생겼나 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PACS 벤더의 실제 Conformance Statement 읽기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시리즈 전체 개념이 어떻게 명세되어 있는지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DICOM 익명화 도구 비교&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PS3.15 Annex E 프로파일&lt;/li&gt;
&lt;li&gt;Orthanc vs gdcm vs custom&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. 핵심 정리 (전체)&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────┐
│                        DICOM의 전체 구조                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  데이터 계층                                                       │
│  ├── VR (27가지)                          ─── 1편                 │
│  ├── Tag (group, element)                  ─── 2편                 │
│  ├── Encoding (Implicit/Explicit)          ─── 2편                 │
│  ├── Patient/Study/Series/Image            ─── 3편                 │
│  └── IOD (Information Object Definition)   ─── 3편                 │
│                                                                  │
│  서비스 계층                                                       │
│  ├── SOP = DIMSE + IOD                     ─── 4편                 │
│  ├── C-Echo / C-Store / C-Find             ─── 4편                 │
│  ├── C-Move / C-Get / MWL                  ─── 5편                 │
│  └── Storage Commitment / SR / SC          ─── 5편                 │
│                                                                  │
│  통신 인프라                                                        │
│  ├── Association                           ─── 6편                 │
│  ├── Abstract / Transfer Syntax            ─── 6편                 │
│  ├── Presentation Context                  ─── 6편                 │
│  └── PDU                                   ─── 6편                 │
│                                                                  │
│  파일 + 보안                                                        │
│  ├── DICOM File Format                     ─── 7편                 │
│  ├── DICOMDIR                              ─── 7편                 │
│  ├── 익명화 / 암호화                          ─── 7편                 │
│  └── DICOMweb (현대 표준)                    ─── 7편                 │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM은 &lt;b&gt;이론은 단순하지만 실무가 까다로운 표준&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pianykh, O.S. &lt;i&gt;Digital Imaging and Communications in Medicine (DICOM)&lt;/i&gt;. Springer, 2008.&lt;/li&gt;
&lt;li&gt;공식 표준:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;PS3.10&lt;/b&gt; &amp;mdash; Media Storage and File Format&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PS3.11&lt;/b&gt; &amp;mdash; Media Storage Application Profiles&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PS3.12&lt;/b&gt; &amp;mdash; Media Formats and Physical Media&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PS3.15&lt;/b&gt; &amp;mdash; Security and System Management Profiles ⭐&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PS3.18&lt;/b&gt; &amp;mdash; Web Services (DICOMweb) ⭐&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;라이브러리/도구:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://orthanc.uclouvain.be/&quot;&gt;Orthanc&lt;/a&gt; &amp;mdash; DICOM 서버 + DICOMweb 게이트웨이&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pydicom.github.io/&quot;&gt;pydicom&lt;/a&gt; &amp;mdash; Python DICOM 파일 처리&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pydicom.github.io/pynetdicom/&quot;&gt;pynetdicom&lt;/a&gt; &amp;mdash; Python DIMSE&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.dcm4che.org/&quot;&gt;dcm4che&lt;/a&gt; &amp;mdash; Java DICOM 도구&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://gdcm.sourceforge.net/&quot;&gt;GDCM&lt;/a&gt; &amp;mdash; C++ DICOM 라이브러리 + 익명화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;참고 사이트:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.dicomstandard.org&quot;&gt;DICOM Standard 공식&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dicomweb.org&quot;&gt;DICOMweb 가이드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dicom.innolitics.com/&quot;&gt;DICOM Tag 검색&lt;/a&gt; &amp;mdash; 시각화된 dictionary&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;학습 자료:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Clunie, D. &lt;i&gt;DICOM Structured Reporting&lt;/i&gt; (2000)&lt;/li&gt;
&lt;li&gt;IHE Profiles (워크플로우 통합)&lt;/li&gt;
&lt;li&gt;NEMA의 DICOM webinar / Working Group 문서&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Dev/DICOM</category>
      <category>dicom</category>
      <category>의료 데이터 통신</category>
      <author>odod00</author>
      <guid isPermaLink="true">https://chaechae0.tistory.com/46</guid>
      <comments>https://chaechae0.tistory.com/46#entry46comment</comments>
      <pubDate>Wed, 10 Jun 2026 15:20:40 +0900</pubDate>
    </item>
    <item>
      <title>[DICOM] DICOM Association &amp;mdash; PACS 통신 디버깅이 일어나는 곳</title>
      <link>https://chaechae0.tistory.com/45</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oleg Pianykh, Digital Imaging and Communications in Medicine (DICOM) (Springer, 2008) 정리 6편&lt;br /&gt;참고 챕터: Ch 9&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 편에서 우리는 &lt;b&gt;얼버무리고 넘어온 것&lt;/b&gt;이 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;두 AE가 통신하려면 먼저 &lt;b&gt;Association&lt;/b&gt; 을 맺어야 한다&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 6편은 그 &lt;b&gt;Association의 정체&lt;/b&gt;를 다룬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PACS 연동에서 가장 자주 마주치는 에러들&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;Association rejected (no reason given)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Abstract syntax not supported&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Transfer syntaxes not supported&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Implementation version name too long&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Calling AE not in whitelist&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모든 게 &lt;b&gt;Association 협상 단계&lt;/b&gt;에서 일어난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자가 말한 그대로&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;DICOM association failures account for the vast majority of all DICOM networking problems.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글이 끝나면 Orthanc/pynetdicom 로그를 보고 직접 해석할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Association이란?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.1 DICOM Upper Layer (DICOM UL)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM Association은 &lt;b&gt;TCP/IP 위에서 도는 DICOM 전용 통신 계층&lt;/b&gt;.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;┌─────────────────────────────────────┐
│    DIMSE (Service messages)          │  &amp;larr; 4-5편
├─────────────────────────────────────┤
│    DICOM Upper Layer (UL)            │  &amp;larr; 6편 (이번 글)
│    = Association 협상 + PDU 전송      │
├─────────────────────────────────────┤
│    TCP / IP                          │
└─────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP는 그냥 &quot;바이트 스트림 옮기는 통로&quot;일 뿐.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM UL이 그 위에&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;&lt;b&gt;우리가 통신할 수 있는 사이인지&lt;/b&gt;&quot; 협상하고&lt;/li&gt;
&lt;li&gt;&quot;&lt;b&gt;어떤 형식으로 데이터를 주고받을지&lt;/b&gt;&quot; 합의하고&lt;/li&gt;
&lt;li&gt;&quot;&lt;b&gt;실제 데이터를 PDU 단위로&lt;/b&gt; 흘려보낸다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.2 Association = &quot;DICOM 핸드셰이크&quot;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전화 비유:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TCP 연결 = 전화선이 깔림&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Association 협상&lt;/b&gt; = &quot;여보세요, ○○입니다. △△ 하려고요&quot; + &quot;네, 가능합니다&quot;&lt;/li&gt;
&lt;li&gt;DIMSE 메시지 = 실제 대화&lt;/li&gt;
&lt;li&gt;Association 종료 = &quot;끊을게요&quot; + &quot;네 끊으세요&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Association 협상 실패하면 그 뒤 통신은 절대 안 됨.&lt;/b&gt; TCP는 살아있어도 의미 없음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Association의 3막 (직관적 이해) ⭐&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자가 책에서 만든 비유. 이거 하나만 알고 있어도 50% 끝.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Act 1 &amp;mdash; Association Establishment (협상)&lt;/h3&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;MR scanner: &quot;Hi, 나 MR scanner고 DICOM 할 줄 알아. 너도?&quot;
ARCHIVE:    &quot;응 나도 DICOM 함&quot;

MR:         &quot;너 MR Image Storage SCP 야?&quot;
ARCHIVE:    &quot;맞아&quot;

MR:         &quot;MR 영상 100장 있어. 압축 안 한 채로 보낼 수도 있고,
             JPEG2000으로 압축해서 보낼 수도 있고, JPEG-LS도 가능.&quot;
ARCHIVE:    &quot;OK, MR 받을게. 압축 안 한 거로 받을게.&quot;

MR:         &quot;좋아, 보낼게.&quot;
ARCHIVE:    &quot;받을 준비 완료.&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 이게 &lt;b&gt;A-Associate-RQ&lt;/b&gt; &amp;harr; &lt;b&gt;A-Associate-AC&lt;/b&gt; 의 본질.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Act 2 &amp;mdash; Data Transfer (전송)&lt;/h3&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;MR:      &quot;1번 영상.&quot; &quot;2번.&quot; &quot;3번...&quot;
ARCHIVE: &quot;1번 OK.&quot; &quot;2번 OK...&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;P-Data-TF&lt;/b&gt; PDU로 실제 영상 흐름.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Act 3 &amp;mdash; Association Termination (종료)&lt;/h3&gt;
&lt;pre class=&quot;http&quot;&gt;&lt;code&gt;MR:      &quot;100장 다 보냈음. 0장 실패. 성공. 끝낼게.&quot;
ARCHIVE: &quot;다 받았음. 끝!&quot;

(연결 종료)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;A-Release-RQ&lt;/b&gt; &amp;harr; &lt;b&gt;A-Release-RP&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Abstract Syntax &amp;mdash; &quot;어떤 서비스?&quot;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;협상 단계에서 가장 먼저 합의하는 것: &lt;b&gt;무슨 SOP에 대해 통신할 건지&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 Abstract Syntax = SOP Class UID&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;Abstract Syntax UID = SOP Class UID&quot;&lt;/b&gt; 는 사실상 같은 말. 둘 다 같은 UID를 가리킨다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Abstract Syntax 1.2.840.10008.5.1.4.1.1.4 = MR Image Storage SOP
                                              &amp;uarr;
                                        이 SOP를 위해 협상하자&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 주요 Abstract Syntax UID&lt;/h3&gt;
&lt;table style=&quot;height: 244px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 24px;&quot;&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;분류&lt;/th&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;Abstract Syntax 이름&lt;/th&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;UID&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Verification&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Verification&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;1.2.840.10008.1.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Storage&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;CR Image&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Storage&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;CT Image&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;Storage&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;MR Image&lt;/b&gt; ⭐&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.4&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Storage&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;US Image&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.6.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;Storage&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;Secondary Capture&lt;/b&gt; ⭐&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.7&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Storage&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Enhanced SR&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.88.22&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Q/R Find&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Study Root&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.2.2.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Q/R Get&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Study Root&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.2.2.3&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Q/R Move&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Study Root&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.2.2.2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Q/R Find&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Patient Root&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.2.1.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;MWL&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;MWL Find&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;1.2.840.10008.5.1.4.31&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3 인코딩&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A-Associate-RQ 메시지 안에서 Abstract Syntax는 이런 형식:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;┌──────┬──────────┬─────────┬─────────────────────┐
│ 0x30 │ reserved │ Length  │  UID string         │
│ 1byte│ 1 byte=0 │ 2 bytes │  L bytes            │
└──────┴──────────┴─────────┴─────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: &lt;code&gt;1.2.840.10008.5.1.4.1.1.4&lt;/code&gt; (MR Image Storage, 25자 = &lt;code&gt;0x19&lt;/code&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;30 00 00 19 31 2E 32 2E 38 34 30 2E 31 30 30 30 38 2E 35 2E 31 2E 34 2E 31 2E 31 2E 34&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.4 거부 시나리오&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ARCHIVE가 MR Image Storage만 지원하고 CT Image Storage는 미지원이라면&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;CT 장비 &amp;rarr; ARCHIVE: &quot;1.2.840.10008.5.1.4.1.1.2 (CT Storage) SCP 야?&quot;
ARCHIVE &amp;rarr; CT 장비: &quot;❌ 아니야. Abstract Syntax not supported.&quot;
                    &amp;rarr; 또는 그 Presentation Context만 거부&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Abstract Syntax는 협상 불가.&lt;/b&gt; 이건 장비 기능 자체. 합의가 아닌 매칭.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Transfer Syntax &amp;mdash; &quot;어떻게 인코딩?&quot;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 &lt;b&gt;DICOM 호환성의 마법&lt;/b&gt;. 1980년대 CT 스캐너가 2026년 Windows 노트북과 통신할 수 있는 이유.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1 Transfer Syntax가 다루는 것&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Endian&lt;/b&gt; (Big/Little) &amp;mdash; &lt;a href=&quot;./01-dicom-%EC%9E%85%EB%AC%B8-VR.md&quot;&gt;1편&lt;/a&gt; 6번 참조&lt;/li&gt;
&lt;li&gt;&lt;b&gt;VR encoding&lt;/b&gt; (Implicit/Explicit) &amp;mdash; &lt;a href=&quot;./02-Tag-Dictionary-Encoding.md&quot;&gt;2편&lt;/a&gt; 4번&lt;/li&gt;
&lt;li&gt;&lt;b&gt;압축 알고리즘&lt;/b&gt; (JPEG, JPEG-LS, JPEG2000, RLE)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2 주요 Transfer Syntax UID&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Transfer Syntax&lt;/th&gt;
&lt;th&gt;UID&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Implicit VR Little Endian&lt;/b&gt; ⭐&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.1.2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;DICOM 기본값. 무조건 지원 필수&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Explicit VR Little Endian&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.1.2.1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Explicit 안전성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Explicit VR Big Endian&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.1.2.2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;구 Mac 등 (거의 사용 안 함)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JPEG Baseline 8-bit Lossy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.1.2.4.50&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;일반 JPEG 손실&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JPEG Baseline 12-bit Lossy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.1.2.4.51&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;12bit 의료영상용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JPEG Lossless&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.1.2.4.57&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JPEG 무손실&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;JPEG-LS Lossless&lt;/b&gt; ⭐&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.1.2.4.80&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;의료영상에서 흔함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JPEG-LS Near-Lossless&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.1.2.4.81&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;거의 무손실&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;JPEG 2000 Lossless&lt;/b&gt; ⭐&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.1.2.4.90&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;최신, 권장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JPEG 2000 Lossy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.1.2.4.91&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;손실 압축&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RLE Lossless&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.1.2.5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run-Length, 단순&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.3 핵심 규칙&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;모든 DICOM AE는 &lt;code&gt;1.2.840.10008.1.2&lt;/code&gt; (Implicit VR LE) 를 무조건 지원해야 함.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 안전망. 다른 압축 협상 다 실패해도 이걸로 fallback 하면 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.4 인코딩 (Abstract와 거의 동일)&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;┌──────┬──────────┬─────────┬─────────────────────┐
│ 0x40 │ reserved │ Length  │  UID string         │
│ 1byte│ 1 byte=0 │ 2 bytes │  L bytes            │
└──────┴──────────┴─────────┴─────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 바이트가 &lt;code&gt;0x40&lt;/code&gt; (Transfer Syntax)인 것만 다름.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.5 ⚠️ 압축 함정 &amp;mdash; 저자 사례&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 병원 US 장비가 영상을 압축 형식으로 저장 (디스크 용량 절약).&lt;br /&gt;Archive 서버는 압축 미지원.&lt;br /&gt;&amp;rarr; US가 영상 보내려 했을 때 &amp;rarr; &lt;b&gt;Transfer Syntax 불일치로 거부&lt;/b&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 진단&lt;/b&gt;:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;US 기사가 자기도 모르게 압축 켬 &amp;rarr; Transfer Syntax 바뀜&lt;/li&gt;
&lt;li&gt;US 장비 펌웨어가 &quot;압축 거부되면 압축 안 한 거로 fallback&quot; 안 함 &amp;rarr; 표준 위반&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 AE는 거부당하면 &lt;b&gt;Implicit VR LE로 fallback&lt;/b&gt; 해야 함&lt;/li&gt;
&lt;li&gt;또는 Archive에서 그 압축 지원 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.6 압축 옵션 함정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Transfer Syntax는 &lt;b&gt;알고리즘 이름&lt;/b&gt;만 협상. &lt;b&gt;품질/비율 같은 파라미터는 협상 안 됨&lt;/b&gt;.&lt;br /&gt;&amp;rarr; 받는 쪽은 &quot;JPEG2000으로 압축됐다&quot;만 알지 &quot;품질 80%&quot; 같은 건 모름.&lt;br /&gt;&amp;rarr; 그래서 의료영상은 &lt;b&gt;무손실 압축 (Lossless)&lt;/b&gt; 선호.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. Presentation Context = Abstract + Transfer 묶음 ⭐⭐&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기가 핵심. 위 두 개념이 합쳐진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1 정의&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Presentation Context&lt;/b&gt; = 1개의 Abstract Syntax + 여러 개의 Transfer Syntax 후보&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────┐
│  Presentation Context (PrC)                              │
│  ├── Presentation Context ID (1, 3, 5, ... 홀수)         │
│  ├── Abstract Syntax: MR Image Storage                   │
│  └── Transfer Syntax 후보들:                              │
│      ├── 1.2.840.10008.1.2 (Implicit VR LE)              │
│      ├── 1.2.840.10008.1.2.4.80 (JPEG-LS Lossless)       │
│      └── 1.2.840.10008.1.2.4.91 (JPEG 2000 Lossy)        │
└─────────────────────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  비유: &quot;이 일(Abstract)을 다음 언어들(Transfer) 중 어떤 걸로든 할 수 있어요&quot; 라는 명함.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.2 협상 과정&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Calling AE &amp;rarr; Called AE (요청)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 Presentation Context를 묶어서 보냄:&lt;/p&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;A-Associate-RQ
├── PrC ID=1: MR Storage / [Implicit LE, JPEG-LS, JPEG2000]
├── PrC ID=3: CT Storage / [Implicit LE]
├── PrC ID=5: Verification / [Implicit LE]
└── ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Called AE &amp;rarr; Calling AE (응답)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 PrC에 대해 수락/거부 + &lt;b&gt;선택한 Transfer Syntax 1개&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;A-Associate-AC
├── PrC ID=1: ✅ Accept, Transfer Syntax = Implicit LE
├── PrC ID=3: ❌ Reject (reason 3: Abstract syntax not supported)
├── PrC ID=5: ✅ Accept, Transfer Syntax = Implicit LE
└── ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; PrC ID로 어떤 컨텍스트의 응답인지 매칭.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.3 Acceptance Reason 코드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A-Associate-AC의 각 PrC 응답에 들어가는 &quot;왜 수락/거부했나&quot;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;코드&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ Acceptance (성공)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;❌ User-rejection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;❌ No-reason (provider)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;❌ &lt;b&gt;Abstract syntax not supported&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;❌ &lt;b&gt;Transfer syntaxes not supported&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;PACS 통신 디버깅의 진짜 핵심&lt;/b&gt;:&lt;br /&gt;로그에서 PrC가 거부됐다면 reason 코드 먼저 확인.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;3이면 &amp;rarr; SOP Class 자체를 안 받는 거 (장비 호환성 문제)&lt;/li&gt;
&lt;li&gt;4면 &amp;rarr; SOP는 OK지만 압축 등 인코딩 형식이 안 맞는 거 (해결 가능)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.4 실제 인코딩 &amp;mdash; 두 가지 형식&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A-Associate-&lt;b&gt;RQ&lt;/b&gt;의 PrC: 첫 바이트 &lt;code&gt;0x20&lt;/code&gt;. Abstract 1개 + Transfer 여러 개.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A-Associate-&lt;b&gt;AC&lt;/b&gt;의 PrC: 첫 바이트 &lt;code&gt;0x21&lt;/code&gt;. &lt;b&gt;Abstract 없음&lt;/b&gt;. Transfer 1개만. PrC ID로 매칭.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; AC에 Abstract Syntax 안 들어있어서 &lt;b&gt;PrC ID 매칭이 유일한 방법&lt;/b&gt;. ID 잘못 맞추면 망함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. Application Context (대부분 무시)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A-Associate에 들어가지만 거의 안 봄.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;표준 default: &lt;code&gt;1.2.840.10008.3.1.1.1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;거의 모든 구현이 이 default 사용&lt;/li&gt;
&lt;li&gt;이론상 &quot;어떤 회사 소프트웨어인지&quot; 식별 가능 &amp;mdash; 사설 협상 트리거용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실무에서는 그냥 default 보내고 받는 쪽도 무시&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ 가끔 악용: 일부 PACS가 &quot;경쟁사 Application Context면 거부&quot; 한다는 루머. 대부분 그냥 무시.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. User Information &amp;mdash; 작지만 까다로운 함정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A-Associate-RQ/AC에 들어가는 잡다한 추가 정보.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.1 주요 subitem&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Subitem&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;th&gt;기본값&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Maximum PDU Length&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;PDU 최대 크기 (byte)&lt;/td&gt;
&lt;td&gt;16384, 64KB 등&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implementation Class UID&lt;/td&gt;
&lt;td&gt;구현 식별자&lt;/td&gt;
&lt;td&gt;(벤더별)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implementation Version Name&lt;/td&gt;
&lt;td&gt;버전 문자열 (&lt;b&gt;&amp;le; 16자&lt;/b&gt;)&lt;/td&gt;
&lt;td&gt;(벤더별)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Async Operations Window&lt;/td&gt;
&lt;td&gt;비동기 큐 사이즈&lt;/td&gt;
&lt;td&gt;1 (= 동기)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;SCP/SCU Role Selection&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;역할 협상&lt;/td&gt;
&lt;td&gt;RQ측=SCU 가정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extended Negotiation&lt;/td&gt;
&lt;td&gt;추가 협상 (relational query 등)&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.2 ⚠️ 저자의 함정 사례 &amp;mdash; 두 글자 때문에 하루 날림&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CR &amp;harr; Archive 연결이 안 됨. 하루 종일 디버깅.&lt;br /&gt;원인: Archive의 &lt;b&gt;Implementation Version Name이 18자&lt;/b&gt; (&lt;code&gt;&quot;ArchiveVersion.123&quot;&lt;/code&gt;).&lt;br /&gt;DICOM 표준상 &lt;b&gt;최대 16자&lt;/b&gt;. CR이 그걸 엄격히 검사해서 통째로 거부.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;교훈&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;User Information의 &lt;b&gt;모든 길이 제한 엄수&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;그래야 까다로운 벤더와도 호환&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.3 Maximum PDU Length&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PDU(Protocol Data Unit) 한 번에 보낼 수 있는 최대 크기. 큰 영상은 여러 PDU로 쪼갬.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;너무 작으면&lt;/b&gt;: 영상이 잘게 쪼개져 오버헤드&amp;uarr;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;너무 크면&lt;/b&gt;: 메모리 부담, 네트워크 단편화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔한 값: 16384 (16KB), 65536 (64KB), 131072 (128KB)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  Orthanc/pynetdicom 기본값은 보통 16KB. 큰 영상 자주 주고받으면 늘려도 됨.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.4 SCP/SCU Role Negotiation&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 가정: RQ를 보낸 쪽 = SCU, 받는 쪽 = SCP.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예외&lt;/b&gt;: C-Get/C-Move 처럼 SCP가 SCU에게 거꾸로 C-Store 하는 경우. 이때 Role 명시 필요.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;A-Associate-RQ
├── PrC: MR Storage
├── User Info:
│   └── SCP/SCU Role Selection: &quot;나는 SCU 이자 SCP 역할 둘 다 함&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; Calling AE가 &quot;내가 보내준 영상을 받을 수도 있어요&quot; 라고 알림.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. PDU &amp;mdash; Protocol Data Unit&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Association 위에서 흐르는 7가지 메시지 단위.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PDU&lt;/th&gt;
&lt;th&gt;1st Byte&lt;/th&gt;
&lt;th&gt;역할&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;A-Associate-RQ&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x01&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;연결 요청&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;A-Associate-AC&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x02&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;연결 수락&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;A-Associate-RJ&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x03&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;연결 거부&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;P-Data-TF&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x04&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;실제 데이터 전송&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;A-Release-RQ&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x05&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;정상 종료 요청&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;A-Release-RP&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x06&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;정상 종료 응답&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;A-Abort&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x07&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;비정상 종료&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.1 전체 흐름도&lt;/h3&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;Calling AE                    Called AE
   │                              │
   │  A-Associate-RQ (0x01)       │
   ─────────────────────────────&amp;rarr; │
   │                              │
   │       ┌────────────────────┐ │
   │       │ 협상 결과          │ │
   │       └────────────────────┘ │
   │                              │
   │  A-Associate-AC (0x02)       │
   &amp;larr;───────────────────────────── │  &amp;larr; 성공 시
   │                              │
   │      또는                    │
   │                              │
   │  A-Associate-RJ (0x03)       │
   &amp;larr;───────────────────────────── │  &amp;larr; 거부 시
   │                              │
   │  ─── 협상 성공한 경우 ───      │
   │                              │
   │  P-Data-TF (0x04) &amp;harr;  &amp;harr;  &amp;harr;   │
   ─────────────────────────────&amp;rarr; │  &amp;larr; DIMSE 메시지들 흐름
   &amp;larr;───────────────────────────── │
   │  ...                         │
   │                              │
   │  A-Release-RQ (0x05)         │
   ─────────────────────────────&amp;rarr; │
   │                              │
   │  A-Release-RP (0x06)         │
   &amp;larr;───────────────────────────── │
   │                              │
   │  ─── 또는 비정상 종료 ───     │
   │                              │
   │  A-Abort (0x07)              │
   ─────────────────────────────&amp;rarr; │  (양방향 가능)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.2 A-Associate-RQ 구조&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;┌────────────────────────────────────────────────────┐
│ PDU type = 0x01                                     │
│ Reserved (0x00)                                     │
│ Length (4 bytes)                                    │
│ Protocol version (2 bytes, = 0x0001)               │
│ Reserved (2 bytes)                                  │
│ Called AE Title (16 bytes, blank padded)            │
│ Calling AE Title (16 bytes, blank padded)           │
│ Reserved (32 bytes)                                 │
│                                                     │
│ ─── Variable items ─────────────────────────       │
│   Application Context Item                          │
│   Presentation Context Item(s) (여러 개 가능)        │
│   User Information Item                             │
└────────────────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.3 ⚠️ AE Title 16바이트 패딩&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AE Title은 정확히 &lt;b&gt;16바이트&lt;/b&gt;. 짧으면 &lt;b&gt;공백(&lt;code&gt;0x20&lt;/code&gt;) 으로 패딩&lt;/b&gt;.&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;&quot;ORTHANC&quot; &amp;rarr; &quot;ORTHANC         &quot;  (앞 7자 + 공백 9개)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;양쪽이 padding 처리 다르면 매칭 실패.&lt;/b&gt; 일부 PACS가 trailing space를 strip 안 하고 비교해서 거부하는 사례 있음. AE Title은 짧고 명확하게 (8자 이하 권장).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.4 화이트리스트 검사&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A-Associate-RQ 받자마자 Called AE가 하는 일:&lt;/p&gt;
&lt;pre class=&quot;perl&quot;&gt;&lt;code&gt;# 의사코드
def on_associate_rq(rq):
    if rq.calling_ae_title not in self.whitelist:
        return A_Associate_RJ(reason=&quot;no reason given&quot;)  # 흔한 거부 사유
    ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ 이게 &lt;a href=&quot;https://chaechae0.tistory.com/43&quot;&gt;4편 &amp;sect;2.4&lt;/a&gt;에서 본 &lt;b&gt;&quot;양방향 등록 함정&quot;&lt;/b&gt; 의 정체. PACS의 whitelist에 AI 추론 앱 AE 등록 안 되면 무조건 거부.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. A-Associate-RJ (거부)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A-Associate-RQ의 거부 응답. 단순 구조.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9.1 거부 메시지 필드&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;필드&lt;/th&gt;
&lt;th&gt;값&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Result&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rejected-Permanent (영구)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rejected-Transient (일시)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Source&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;DICOM UL service-user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;DICOM UL service-provider (ACSE)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;DICOM UL service-provider (Presentation)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Reason&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;No reason given&lt;/b&gt; &amp;larr; 가장 자주 봄&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Application context name not supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Calling AE Title not recognized&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;4-6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;(reserved)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;7&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Called AE Title not recognized&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9.2 &quot;No reason given&quot; 의 진실&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM 디버깅의 최대 적. &lt;b&gt;벤더가 정보 안 줘서&lt;/b&gt; 그런 거지 실제로는 명확한 이유가 있음. 가장 흔한 실제 원인&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;⭐ &lt;b&gt;Calling AE Title이 whitelist에 없음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Abstract Syntax 미지원&lt;/b&gt; (장비가 해당 SOP 모름)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Maximum PDU Length 협상 실패&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Implementation Version Name 형식 위반&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;방화벽이 association 막음&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;저자 권고&lt;/b&gt;:&lt;br /&gt;&quot;No reason given&quot; 받으면 자체 디버깅하지 말고 &lt;b&gt;양쪽 벤더를 한자리에 모아라&lt;/b&gt;. 단독으로 X 벤더에게 물으면 Y 탓 하고, Y에게 물으면 X 탓 함.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. P-Data-TF &amp;mdash; 실제 데이터 전송&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Association이 성공한 후 흐르는 &lt;b&gt;데이터 PDU&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10.1 구조&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;┌──────────────────────────────────────────────────┐
│ PDU type = 0x04                                   │
│ Reserved (0x00)                                   │
│ PDU Length                                        │
│                                                   │
│ ─── PDV (Protocol Data Value) items ───          │
│   PDV Length (4 bytes)                            │
│   Presentation Context ID (1 byte)                │
│   MCH (Message Control Header, 1 byte) &amp;darr;          │
│   PDV Data (DIMSE message fragment)               │
│   ...                                             │
└──────────────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10.2 MCH (Message Control Header) &amp;mdash; 1바이트의 비밀&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;  Bit 7 6 5 4 3 2 1 0
            │   │ │ │
            │   │ │ └─ Command(1) or Data(0)?
            │   │ └─── Last fragment(1) or not(0)?
            └─── reserved&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;bit 0&lt;/b&gt;: 1이면 Command 객체 (group 0000), 0이면 Data 객체&lt;/li&gt;
&lt;li&gt;&lt;b&gt;bit 1&lt;/b&gt;: 1이면 &lt;b&gt;이게 마지막 fragment&lt;/b&gt;, 0이면 더 옴&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; DIMSE 메시지를 PDU 크기에 맞게 쪼개고, 받는 쪽에서 다시 조립.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10.3 흐름 예시: C-Store 한 번&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;C-Store-Rq (Command Object, 작음)
  &amp;rarr; 1개 PDV (MCH=0x03 = command + last)

영상 데이터 (큰 IOD, 10MB)
  &amp;rarr; 여러 PDV로 쪼개짐:
    PDV 1: MCH=0x00 (data + 계속)
    PDV 2: MCH=0x00 (data + 계속)
    ...
    PDV N: MCH=0x02 (data + last)

&amp;rarr; C-Store 완료 &amp;rarr; C-Store-Rsp 응답&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10.4 PrC ID 매칭&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 PDV에는 &lt;b&gt;Presentation Context ID&lt;/b&gt; 가 붙어 있음.&lt;br /&gt;&amp;rarr; 받는 쪽이 &quot;이 PDV는 Implicit LE로 해석해야 하나, JPEG 압축으로 해석해야 하나&quot; 를 PrC ID로 결정.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. Association 종료&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;11.1 정상 종료 &amp;mdash; A-Release&lt;/h3&gt;
&lt;pre class=&quot;dns&quot;&gt;&lt;code&gt;SCU                            SCP
 │                              │
 │  A-Release-RQ (0x05)         │  &amp;larr; 작업 끝, 끊자
 ────────────────────────────&amp;rarr;  │
 │                              │
 │  A-Release-RP (0x06)         │  &amp;larr; OK
 &amp;larr;────────────────────────────  │
 │                              │
 ─── TCP 연결 종료 ───&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;11.2 비정상 종료 &amp;mdash; A-Abort&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오류 상황에서 즉시 끊기:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;잘못된 PDU 받음&lt;/li&gt;
&lt;li&gt;타임아웃&lt;/li&gt;
&lt;li&gt;사용자가 강제 종료&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;A-Abort (0x07) &amp;rarr; 한쪽이 일방적으로 보냄 &amp;rarr; TCP close&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;11.3 Timeout 종료&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상대가 응답 없으면 일정 시간 후 자동 종료. 보통 &lt;b&gt;30-60초&lt;/b&gt; 설정.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  너무 짧으면 느린 네트워크에서 끊김. 너무 길면 죽은 연결 감지 늦음.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;11.4 ⚠️ 동시 Association 수 라이선스&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일부 PACS 벤더는 &lt;b&gt;동시 Association 수 라이선스&lt;/b&gt;로 판매. 10개, 50개 등.&lt;br /&gt;&amp;rarr; 모든 Association을 &lt;b&gt;반드시 A-Release로 정상 종료&lt;/b&gt; 해야 슬롯 회수됨.&lt;br /&gt;&amp;rarr; 안 그러면 슬롯이 누적되어 새 Association 받을 수 없게 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12. Association 디버깅 &amp;mdash; 실전 가이드 ⭐⭐⭐&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자의 노하우 + 실무 베스트 프랙티스.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;12.1 디버깅 순서&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1. C-Echo (ping)
   ├── 성공 &amp;rarr; AE Title, IP, Port, whitelist 모두 OK &amp;rarr; 다음 단계로
   └── 실패 &amp;rarr; 12.2 로

2. C-Store SCU (실제 영상 전송)
   ├── 성공 &amp;rarr; 완료
   └── 실패 &amp;rarr; Abstract/Transfer Syntax 협상 문제 &amp;rarr; 12.3 로

3. C-Find / C-Move (검색/가져오기)
   └── ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;12.2 C-Echo 실패 트러블슈팅&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;증상&lt;/th&gt;
&lt;th&gt;확인&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TCP timeout&lt;/td&gt;
&lt;td&gt;1) 네트워크 케이블/방화벽&lt;br /&gt;2) IP/Port 오타&lt;br /&gt;3) SCP 데몬이 안 돔&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Association rejected (no reason)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1) &lt;b&gt;Calling AE Title이 PACS whitelist에 있나?&lt;/b&gt; ⭐&lt;br /&gt;2) Called AE Title 오타&lt;br /&gt;3) Implementation Version Name 16자 초과&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Abstract syntax not supported&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Verification SOP SCP 미지원 (Conformance 확인)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;즉시 disconnect&lt;/td&gt;
&lt;td&gt;일부 PACS는 whitelist 미등록 시 그냥 끊음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;12.3 C-Store 실패 트러블슈팅&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;증상&lt;/th&gt;
&lt;th&gt;확인&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Abstract syntax not supported&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SOP Class UID 확인. CT 영상 보내는데 PACS가 MR Storage만 받는 등.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Transfer syntaxes not supported&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;압축 형식 미지원. Implicit LE로 fallback 시도.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Out of resources&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PACS 디스크/메모리 부족. 관리자에게&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Cannot understand&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;IOD 형식 위반. Type 1 필드 누락 등&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;일부 영상만 실패&lt;/td&gt;
&lt;td&gt;Patient ID 빈 값, 손상된 픽셀 등 개별 데이터 문제&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;12.4 로그 분석 핵심 키워드&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Orthanc 로그&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;W [Orthanc Plugin]   Connection failed (rc = 0xc0001000, ...)
I [Orthanc Plugin]   ASSOCIATE-RQ from CT_SCANNER (10.0.0.5:11112)
I [Orthanc Plugin]   ASSOCIATE-AC sent
I [Orthanc Plugin]   P-DATA-TF: 1 PDV, ...
W [Orthanc Plugin]   Refusing presentation context (abstract syntax not supported)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;pynetdicom 로그&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;import logging
logging.basicConfig(level=logging.DEBUG)
# 또는
from pynetdicom import debug_logger
debug_logger()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 모든 PDU/PDV 바이트 단위로 출력. RQ/AC 협상 내용 다 보임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;12.5 패킷 캡처 (Wireshark)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진짜 안 풀리는 경우 마지막 수단:&lt;/p&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;tshark -i any -f &quot;port 4242&quot; -w dicom.pcap&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Wireshark는 &lt;b&gt;DICOM dissector&lt;/b&gt; 내장. 모든 PDU/PDV/Abstract/Transfer Syntax를 트리로 보여줌. AE Title의 trailing space, PDU length 오류 같은 것도 한 번에 드러남.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;12.6 ⚠️ 책의 황금률&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;DICOM 협상 실패는 거의 항상 양쪽 벤더 책임.&lt;/b&gt; 한쪽만 잡지 말고 둘을 마주 앉혀라.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;명확한 로그/에러 표시 없는 PACS는 사지 말 것.&lt;/b&gt; 디버깅 불가.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Conformance Statement를 신뢰하되 검증하라.&lt;/b&gt; &quot;지원한다&quot;고 적힌 게 실제로는 미구현인 경우 흔함.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13. Point-to-Point의 한계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM의 근본적 약점 하나 더.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;13.1 정적 등록 강제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모든 AE는 통신할 상대의 (AET, IP, Port)를 미리 등록&lt;/b&gt; 해야 함.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;변경되면 모든 곳을 다시 등록해야 함.&lt;/li&gt;
&lt;li&gt;모바일/원격 접근 어려움.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;13.2 저자의 허리케인 카트리나 사례&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카트리나 후 정전 &amp;rarr; 라우터 재부팅 &amp;rarr; IP 주소가 공장 default로 리셋&lt;br /&gt;&amp;rarr; PACS 서버 IP 바뀜 &amp;rarr; 모든 AE가 PACS를 못 찾음 &amp;rarr; 전체 마비&lt;br /&gt;&amp;rarr; IP 복원하니 즉시 정상화&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; TCP/IP는 살아있는데 &lt;b&gt;DICOM의 정적 등록 때문에&lt;/b&gt; 전체 시스템이 죽는 패러독스.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;13.3 C-Move vs C-Get 와 연결&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://chaechae0.tistory.com/44&quot;&gt;5편 &amp;sect;4.2&lt;/a&gt;에서 본 방화벽 함정과 같은 뿌리:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;C-Move는 정적 등록 필수&lt;/b&gt; (별도 association 열어야 하니까)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;C-Get은 동적 가능&lt;/b&gt; (같은 association으로 응답)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;13.4 워크어라운드&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;방식&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VPN&lt;/td&gt;
&lt;td&gt;가상 사설망으로 정적 IP처럼 보이게&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DICOMweb (WADO/STOW/QIDO)&lt;/td&gt;
&lt;td&gt;HTTP REST 기반, 정적 등록 불필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Orthanc/dcm4chee gateway&lt;/td&gt;
&lt;td&gt;외부에서 들어온 요청을 내부 PACS로 중계&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;현대 PACS는 DICOMweb 지원이 점점 표준화 중.&lt;/b&gt; DICOMweb은 책에 없지만 별도 학습할 가치 있음 (PS3.18).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14. AI 추론 앱 관점 &amp;mdash; Orthanc 사용 시 ⭐&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저수준 PDU는 Orthanc가 다 처리해줌. 하지만 &lt;b&gt;설정과 디버깅에서 위 개념들이 그대로 등장&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;14.1 Orthanc 설정 예시&lt;/h3&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;// orthanc.json
{
  &quot;DicomAet&quot;: &quot;ORTHANC&quot;,
  &quot;DicomPort&quot;: 4242,
  &quot;DicomCheckCalledAet&quot;: false,
  &quot;DicomCheckModalityHost&quot;: false,

  &quot;DicomModalities&quot;: {
    &quot;HOSPITAL_PACS&quot;: {
      &quot;AET&quot;: &quot;HOSPITAL_PACS&quot;,
      &quot;Host&quot;: &quot;10.0.0.50&quot;,
      &quot;Port&quot;: 11112,
      &quot;Manufacturer&quot;: &quot;Generic&quot;,
      &quot;AllowEcho&quot;: true,
      &quot;AllowFind&quot;: true,
      &quot;AllowGet&quot;: false,
      &quot;AllowMove&quot;: true,
      &quot;AllowStore&quot;: true
    }
  },

  // ⭐ Transfer Syntax 협상 제어
  &quot;AcceptedTransferSyntaxes&quot;: [
    &quot;1.2.840.10008.1.*&quot;
  ],

  // ⭐ Abstract Syntax 협상 제어
  &quot;DefaultEncoding&quot;: &quot;Latin1&quot;,
  &quot;MaximumPduLength&quot;: 16384,

  // ⭐ Whitelist
  &quot;DicomAlwaysAllowEcho&quot;: true,
  &quot;DicomAlwaysAllowStore&quot;: true
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 위 설정의 거의 모든 필드가 이번 글에서 다룬 개념과 직접 대응&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;DicomAet&lt;/code&gt; = 우리 AI 추론 앱의 &lt;b&gt;Calling AE Title&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AET&lt;/code&gt;/&lt;code&gt;Host&lt;/code&gt;/&lt;code&gt;Port&lt;/code&gt; = 원격 PACS의 (AE Title, IP, Port) &lt;b&gt;사전 등록&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AcceptedTransferSyntaxes&lt;/code&gt; = 협상 시 받아들일 &lt;b&gt;Transfer Syntax UID&lt;/b&gt; 목록&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MaximumPduLength&lt;/code&gt; = User Information의 &lt;b&gt;Max PDU Length&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DicomAlwaysAllowStore&lt;/code&gt; = whitelist 검사 우회 (개발 환경에서)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;14.2 디버깅 명령&lt;/h3&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;# C-Echo 테스트
curl -X POST http://orthanc:8042/modalities/HOSPITAL_PACS/echo

# 협상 로그 보기 (Orthanc verbose 모드)
Orthanc.exe --verbose orthanc.json
# 또는
Orthanc.exe --trace-dicom orthanc.json   # &amp;larr; Association/PDU 레벨 로그&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;14.3 흔한 시나리오와 매핑&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;증상&lt;/th&gt;
&lt;th&gt;원인 (이번 글의 개념)&lt;/th&gt;
&lt;th&gt;해결&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Orthanc에서 PACS로 C-Echo 실패&lt;/td&gt;
&lt;td&gt;Whitelist 미등록&lt;/td&gt;
&lt;td&gt;PACS에 ORTHANC AE 등록 요청&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C-Store 시 &lt;code&gt;RejectedPresentationContext&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Transfer Syntax 미협상&lt;/td&gt;
&lt;td&gt;&lt;code&gt;AcceptedTransferSyntaxes&lt;/code&gt;에 압축 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C-Move 했는데 영상 안 옴&lt;/td&gt;
&lt;td&gt;Move Destination 등록 안 됨&lt;/td&gt;
&lt;td&gt;PACS에 우리 AE를 destination으로 등록&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implementation 16자 오류&lt;/td&gt;
&lt;td&gt;User Info 길이 위반&lt;/td&gt;
&lt;td&gt;Orthanc 버전 업데이트 또는 벤더 문의&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;큰 영상 전송 중단&lt;/td&gt;
&lt;td&gt;Max PDU Length&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MaximumPduLength&lt;/code&gt; 늘림 (e.g., 65536)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;15. 핵심 정리&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;개념&lt;/th&gt;
&lt;th&gt;한 줄&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Association&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;DICOM Upper Layer 통신 단위. TCP 위 핸드셰이크&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Act 1/2/3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Establishment / Data Transfer / Termination&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Abstract Syntax&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&quot;어떤 SOP&quot; &amp;mdash; UID 형식. 협상 불가, 매칭만&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Transfer Syntax&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&quot;어떤 인코딩&quot; &amp;mdash; Endian/Implicit/Explicit/압축. 여러 후보 협상&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;기본 Transfer Syntax&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.1.2&lt;/code&gt; (Implicit VR LE) &amp;mdash; &lt;b&gt;무조건 지원 필수&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Presentation Context&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Abstract 1개 + Transfer 후보 N개. PrC ID로 추적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;A-Associate-RQ/AC&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;협상 요청/수락 PDU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;A-Associate-RJ&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;거부. &quot;no reason given&quot;이 흔함 &amp;rarr; 실제는 whitelist 문제 다수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;A-Abort&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;비정상 즉시 종료&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;A-Release-RQ/RP&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;정상 종료 (라이선스 슬롯 회수)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;P-Data-TF&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;실제 데이터 PDU. PDV로 쪼갬. MCH 1바이트로 command/data + last 표시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;User Information&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Max PDU, Version Name(16자!), Role Selection 등&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;PrC Reject Reason 3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Abstract Syntax 미지원 (SOP 자체 문제)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;PrC Reject Reason 4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Transfer Syntax 미지원 (인코딩 문제, fallback 가능)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;AE Title&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;16바이트, 공백 패딩. 짧고 명확하게&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;디버깅 순서&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;C-Echo &amp;rarr; C-Store &amp;rarr; 로그 &amp;rarr; Wireshark&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;점-대-점 한계&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;정적 등록 강제. DICOMweb이 대안&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;16. 다음 글에서 다룰 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM 통신의 &lt;b&gt;모든 기본기&lt;/b&gt;가 완성됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 7편은 &lt;b&gt;운영 환경에서의 실전&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7편: DICOM 파일/보안 + Orthanc 실전&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;DICOM File 포맷&lt;/b&gt; &amp;mdash; &lt;code&gt;DICM&lt;/code&gt; 매직 헤더, Preamble, Meta Information&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DICOMDIR&lt;/b&gt; &amp;mdash; DVD/CD/USB 미디어 인덱스&lt;/li&gt;
&lt;li&gt;&lt;b&gt;익명화 (Anonymization)&lt;/b&gt; &amp;mdash; HIPAA, 환자 데이터 보호 ⭐&lt;/li&gt;
&lt;li&gt;&lt;b&gt;암호화&lt;/b&gt; &amp;mdash; Secure DICOM, 디지털 서명&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Orthanc 실전 통합 시나리오&lt;/b&gt; &amp;mdash; AI 추론 앱 전체 파이프라인&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DICOMweb 맛보기&lt;/b&gt; &amp;mdash; WADO-RS, STOW-RS, QIDO-RS&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pianykh, O.S. &lt;i&gt;Digital Imaging and Communications in Medicine (DICOM)&lt;/i&gt;. Springer, 2008.&lt;/li&gt;
&lt;li&gt;공식 표준:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;PS3.7&lt;/b&gt; (Message Exchange) &amp;mdash; DIMSE&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PS3.8&lt;/b&gt; (Network Communication Support) &amp;mdash; &lt;b&gt;이번 글의 핵심&lt;/b&gt;: PDU, Association protocol&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;도구:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Wireshark&lt;/b&gt; &amp;mdash; DICOM dissector 내장. 패킷 단위 분석.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;pynetdicom&lt;/b&gt; &amp;mdash; Python 구현 + DEBUG 로깅&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Orthanc&lt;/b&gt; &amp;mdash; &lt;code&gt;--trace-dicom&lt;/code&gt; 옵션으로 PDU 레벨 로그&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DCMTK&lt;/b&gt; &lt;code&gt;dcmnet&lt;/code&gt; &amp;mdash; &lt;code&gt;storescu&lt;/code&gt;, &lt;code&gt;findscu&lt;/code&gt;, &lt;code&gt;echoscu&lt;/code&gt; 등 CLI 도구&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Dev/DICOM</category>
      <category>dicom</category>
      <category>의료 데이터 통신</category>
      <author>odod00</author>
      <guid isPermaLink="true">https://chaechae0.tistory.com/45</guid>
      <comments>https://chaechae0.tistory.com/45#entry45comment</comments>
      <pubDate>Wed, 10 Jun 2026 14:53:28 +0900</pubDate>
    </item>
    <item>
      <title>[DICOM] 영상을 가져오는 방법 &amp;mdash; C-Move, C-Get, Modality Worklist</title>
      <link>https://chaechae0.tistory.com/44</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oleg Pianykh, Digital Imaging and Communications in Medicine (DICOM) (Springer, 2008) 정리 5편&lt;br /&gt;참고 챕터: Ch 7.5 &amp;ndash; 7.10, Ch 8.1&amp;ndash;8.3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C-Find로 &quot;PACS에 뭐가 있는지&quot; 알아냈으니, 이제 &lt;b&gt;&quot;그 영상을 실제로 가져오는&quot;&lt;/b&gt; 방법을 다룰 차례.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 편의 핵심:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;C-Get / C-Move&lt;/b&gt; &amp;mdash; 영상 가져오기의 두 가지 방식&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Modality Worklist (MWL)&lt;/b&gt; &amp;mdash; RIS에서 일정 받기&lt;/li&gt;
&lt;li&gt;DICOM 현장 용어 (ping/push/pull)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Conformance Statement의 진짜 의미&lt;/b&gt; &amp;mdash; SCU/SCP 역할 매칭&lt;/li&gt;
&lt;li&gt;보너스: Storage Commitment, Secondary Capture, Structured Report&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 다 보면 &lt;b&gt;PACS 통신의 모든 기본기&lt;/b&gt;가 완성된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 왜 C-Find만으론 부족한가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C-Find로 &quot;Study UID 목록&quot;은 얻을 수 있지만, &lt;b&gt;실제 픽셀은 못 받는다.&lt;/b&gt; C-Find는 메타데이터만 응답함.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;C-Find &amp;rarr; &quot;John Smith의 MR Study UID = 1.2.840.xxx 가 PACS에 있어요&quot;
        &amp;darr;
        그래서? 영상 자체는?&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 영상을 &lt;b&gt;실제로 가져오는&lt;/b&gt; 두 가지 방식이 있다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;C-Get&lt;/b&gt; &amp;mdash; 단순. 같은 연결 위에서 영상 받아옴&lt;/li&gt;
&lt;li&gt;&lt;b&gt;C-Move&lt;/b&gt; &amp;mdash; 복잡. PACS가 별도 연결로 보내줌&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 방식은 동일한 SOP Class 패밀리지만 동작이 완전히 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. C-Get &amp;mdash; 단순한 영상 가져오기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 동작 원리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C-Get은 &lt;b&gt;C-Find + C-Store를 한 묶음으로&lt;/b&gt; 처리한다. 같은 association(연결) 안에서 영상이 돌아온다.&lt;/p&gt;
&lt;pre class=&quot;perl&quot;&gt;&lt;code&gt;SCU (워크스테이션)          SCP (PACS)
  │                            │
  │  C-Get-Rq (Study UID)      │
  ──────────────────────────&amp;rarr;
  │                            │
  │  C-Store-Rq (영상 1)        │  &amp;larr; SCP가 SCU에게 거꾸로 보냄!
  &amp;larr;──────────────────────────
  │                            │
  │  C-Store-Rsp                │
  ──────────────────────────&amp;rarr;
  │  C-Store-Rq (영상 2)        │
  &amp;larr;──────────────────────────
  │  ...                        │
  │                            │
  │  C-Get-Rsp Status=0xFF00    │  &amp;larr; 진행 상황 보고
  │  (suboperation 카운트 포함)  │
  &amp;larr;──────────────────────────
  │  ...                        │
  │  C-Get-Rsp Status=0x0000    │  &amp;larr; 완료
  &amp;larr;──────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;핵심 포인트&lt;/b&gt;: 같은 association 위에서 &lt;b&gt;SCU가 일시적으로 C-Store SCP 역할&lt;/b&gt;을 한다. 즉 영상을 받으려면 SCU도 C-Store SCP를 구현해야 함.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 C-Get SOP Class UID&lt;/h3&gt;
&lt;table style=&quot;height: 74px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;th style=&quot;height: 18px;&quot;&gt;Query Root&lt;/th&gt;
&lt;th style=&quot;height: 18px;&quot;&gt;SOP Class UID&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Patient Root Q/R Get&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.2.1.3&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;Study Root Q/R Get&lt;/b&gt; ⭐&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.2.2.3&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Patient-Study Root Q/R Get&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.2.3.3&lt;/code&gt; (&lt;b&gt;Retired&lt;/b&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  SOP Class UID 패턴 기억하기:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C-Find: &lt;code&gt;...1.2.x.1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;C-Get: &lt;code&gt;...1.2.x.3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;C-Move: &lt;code&gt;...1.2.x.2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(x는 root 종류: 1=Patient, 2=Study, 3=Patient-Study)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3 C-Get IOD &amp;mdash; 자유도가 낮다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C-Get은 &lt;b&gt;C-Find와 달리 정확한 키만 받음.&lt;/b&gt; 와일드카드/range 매칭 안 됨.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;(0008, 0052) Retrieve Level = &quot;STUDY&quot;
(0010, 0020) Patient ID = &quot;12345&quot;            &amp;larr; 정확값
(0020, 000D) Study Instance UID = &quot;1.2.84...&quot; &amp;larr; 정확값&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;rarr; 그래서 항상 C-Find를 먼저 해서 키를 얻고, 그 키로 C-Get 호출&lt;/b&gt; 하는 패턴이 표준.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;사용자 검색어
   &amp;darr; (&quot;Smith 환자의 지난달 MR&quot;)
C-Find (wildcard, range 가능)
   &amp;darr;
Study UID 목록 받음
   &amp;darr;
C-Get (UID 정확값만)
   &amp;darr;
영상 다운로드&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.4 C-Get-Rsp의 진행률 필드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C-Get은 진행 상황을 상세히 보고:&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0000, 1020)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remaining Suboperations (남은 개수)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0000, 1021)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Completed (성공한 개수)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0000, 1022)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Failed (실패한 개수)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0000, 1023)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Warning (경고로 끝난 개수)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; PACS UI의 &quot;다운로드 진행률 ████░░ 60%&quot; 가 이걸로 만들어짐.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. C-Move &amp;mdash; 영상을 다른 곳으로 보내기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 동작 원리 &amp;mdash; 3주체&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C-Move의 핵심 차이: &lt;b&gt;영상을 SCU가 아닌 제3의 AE로 보낼 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;   Workstation 1                Archive (PACS)              Workstation 2
   (C-Move SCU)                 (C-Move SCP)                (C-Store SCP)
       │                            │                            │
       │  C-Move-Rq                 │                            │
       │  Move Destination = WS2    │                            │
       ──────────────────────────&amp;rarr;  │                            │
       │                            │                            │
       │                            │  새 association 열기        │
       │                            ──────────────────────────&amp;rarr;  │
       │                            │                            │
       │                            │  C-Store-Rq (영상)         │
       │                            ──────────────────────────&amp;rarr;  │
       │                            │  C-Store-Rsp                │
       │                            &amp;larr;──────────────────────────  │
       │                            │                            │
       │  C-Move-Rsp Status=0xFF00  │                            │
       │  (진행률)                  │                            │
       &amp;larr;──────────────────────────  │                            │
       │  ...                       │                            │
       │  C-Move-Rsp Status=0x0000  │                            │
       &amp;larr;──────────────────────────  │                            │&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 C-Move SOP Class UID&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Query Root&lt;/th&gt;
&lt;th&gt;SOP Class UID&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Patient Root Q/R Move&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.2.1.2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Study Root Q/R Move&lt;/b&gt; ⭐&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.2.2.2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patient-Study Root Q/R Move&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.2.3.2&lt;/code&gt; (&lt;b&gt;Retired&lt;/b&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3 C-Move-Rq의 핵심 필드: Move Destination&lt;/h3&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;(0000, 0600) Move Destination = &quot;WORKSTATION_2&quot;   &amp;larr; AE Title&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;목적지는 AE Title만&lt;/b&gt; 적는다. IP/Port는 안 적음.&lt;br /&gt;&amp;rarr; SCP가 자기 AE 목록에서 그 AE Title을 찾아서 IP/Port를 알아내야 한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.4 ⚠️ 가장 큰 함정: SCP의 AE 등록부&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;C-Move SCP는 목적지 AE의 IP/Port를 미리 알고 있어야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;❌ 시나리오:
AI 추론 앱 (= WS2) 가 PACS에 처음 연결
&amp;rarr; AI 추론 앱이 C-Find로 영상 검색 &amp;rarr; 됨
&amp;rarr; AI 추론 앱이 C-Move로 자기 자신에게 보내달라고 요청
&amp;rarr; PACS: &quot;AIAPP_AE가 누구야?&quot; &amp;rarr; ❌ 거부 (Unknown destination)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;해결&lt;/b&gt;: PACS 관리자에게 AI 추론 앱의 (AE Title + IP + Port) 등록 요청 필수.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.5 C-Move = C-Get 으로 쓰기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔한 패턴: &lt;b&gt;자기 자신을 destination으로 지정&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;WS1                Archive             WS1 (= 자기 자신)
 │                   │                   │
 │ C-Move-Rq         │                   │
 │ Dest = WS1        │                   │
 ──────────────&amp;rarr;    │                   │
 │                   │  C-Store-Rq      │
 │                   ──────────────&amp;rarr;
 │                   │                   │&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 효과상 C-Get과 동일. 그런데 &lt;b&gt;굳이 별도 association을 여는 비효율&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.6 실무 비밀&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자 의견:&lt;br /&gt;대부분의 PACS가 C-Move를 사용하지만, 실제로는 &lt;b&gt;자기 자신을 destination으로 지정해서 C-Get처럼 쓰는 경우&lt;/b&gt;가 대부분.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유: C-Move SCP를 단순화하고, 진짜 3-주체 시나리오는 큰 PACS 내부 클러스터링에서만 쓰임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. C-Move vs C-Get 비교 ⭐&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PACS 통신 모듈 개발 시 &lt;b&gt;반드시 알아야 할 비교&lt;/b&gt;.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1 비교 표&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&amp;nbsp;&lt;/th&gt;
&lt;th&gt;&lt;b&gt;C-Get&lt;/b&gt;&lt;/th&gt;
&lt;th&gt;&lt;b&gt;C-Move&lt;/b&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Association 수&lt;/td&gt;
&lt;td&gt;&lt;b&gt;1개&lt;/b&gt; (반전 사용)&lt;/td&gt;
&lt;td&gt;&lt;b&gt;2개&lt;/b&gt; (별도)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;목적지 지정&lt;/td&gt;
&lt;td&gt;불필요 (자기)&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Move Destination 필수&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사전 등록&lt;/td&gt;
&lt;td&gt;SCP가 SCU만 알면 됨&lt;/td&gt;
&lt;td&gt;&lt;b&gt;SCP가 목적지 AE 사전 등록 필수&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;방화벽 친화성&lt;/td&gt;
&lt;td&gt;✅ Outbound만&lt;/td&gt;
&lt;td&gt;❌ Inbound 연결 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;동적 환경&lt;/td&gt;
&lt;td&gt;✅ 좋음&lt;/td&gt;
&lt;td&gt;❌ 정적 환경에 적합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;텔레라디올로지&lt;/td&gt;
&lt;td&gt;✅ 적합&lt;/td&gt;
&lt;td&gt;❌ 어려움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;큰 PACS 내부 클러스터링&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;표준 위상&lt;/td&gt;
&lt;td&gt;&quot;Archaic&quot; 취급&lt;/td&gt;
&lt;td&gt;권장&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2 방화벽 함정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사/병원 방화벽 환경에서 흔히 발생:&lt;/p&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;회사 방화벽: outbound 허용, inbound 차단 (일반적 설정)

C-Echo (SCU &amp;rarr; SCP): ✅ outbound, OK
C-Find (SCU &amp;rarr; SCP): ✅ outbound, OK
C-Get  (SCU &amp;harr; SCP, 같은 association): ✅ outbound로 시작, OK
C-Move (SCU &amp;rarr; SCP, 그 다음 SCP &amp;rarr; SCU의 새 연결): ❌ 두 번째가 inbound!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;C-Move를 위해 방화벽 구멍을 뚫어야 함.&lt;/b&gt; 보안팀이 싫어함. VPN이 더 안전.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.3 저자의 결론&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;&lt;b&gt;C-Move inside, C-Get outside&lt;/b&gt;&quot;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;큰 PACS 내부 (한 통제된 환경 안): C-Move&lt;/li&gt;
&lt;li&gt;외부 시스템 (텔레라디올로지, 모바일): C-Get&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.4 AI 추론 앱 적용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 추론 앱은 &lt;b&gt;병원 내부 시스템&lt;/b&gt;이라 C-Move 환경에 있을 가능성이 높다:&lt;/p&gt;
&lt;pre class=&quot;sqf&quot;&gt;&lt;code&gt;시나리오 1: 병원 내부 (가장 흔함)
  의사 워크스테이션이 PACS에 &quot;이 환자 영상을 AIAPP_AE로 보내&quot; 요청
  &amp;rarr; PACS가 AI 추론 앱에 C-Store
  &amp;rarr; AI 추론 앱은 단순히 &quot;C-Store SCP&quot;만 구현하면 됨

시나리오 2: AI 추론 앱이 직접 트리거
  AI 추론 앱이 C-Find로 영상 찾기 &amp;rarr; C-Move로 자기에게 보내달라 요청
  &amp;rarr; PACS에 AI 추론 앱 등록 필수
  &amp;rarr; AI 추론 앱은 &quot;C-Move SCU&quot; + &quot;C-Store SCP&quot; 둘 다 구현&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;개발 우선순위&lt;/b&gt;:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;C-Store SCP&lt;/b&gt; (영상 받기) &amp;mdash; 무조건 필요&lt;/li&gt;
&lt;li&gt;&lt;b&gt;C-Echo SCU/SCP&lt;/b&gt; &amp;mdash; 연결 테스트&lt;/li&gt;
&lt;li&gt;&lt;b&gt;C-Store SCU&lt;/b&gt; (결과 보내기) &amp;mdash; 추론 후 PACS로 송신&lt;/li&gt;
&lt;li&gt;&lt;b&gt;C-Find SCU + C-Move SCU&lt;/b&gt; &amp;mdash; AI 추론 앱이 능동적 검색하려면&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. Modality Worklist (MWL)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1 무엇인가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MWL = &quot;오늘 찍을 환자 명단을 modality에 미리 알려주는 서비스&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CT 기사가 출근하면 CT 화면에 오늘 검사할 환자 목록이 떠 있어야 한다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;환자 이름, ID, 생년월일, 성별&lt;/li&gt;
&lt;li&gt;임신 여부, 알러지&lt;/li&gt;
&lt;li&gt;검사 종류, 시작 시간&lt;/li&gt;
&lt;li&gt;의뢰의, 판독의&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 데이터를 &lt;b&gt;수동 입력하면 오타 폭격&lt;/b&gt; &amp;rarr; 큰 사고 원인. &lt;b&gt;MWL로 자동 조회&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.2 전체 데이터 흐름&lt;/h3&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;[RIS / EMR]
    │  (환자 예약/오더)
    │  HL7 메시지
    &amp;darr;
[DICOM Broker / MWL Server]
    │  (HL7 &amp;rarr; DICOM 변환)
    &amp;darr;
[MWL SCP]
    │
    │  C-Find-Rq (Modality=CT, AET=CT1)
    &amp;larr;─────────────────────────────────  [CT Scanner = MWL SCU]
    │
    │  C-Find-Rsp (환자 목록)
    ─────────────────────────────────&amp;rarr;
                                          &amp;darr;
                                       기사 화면에 환자 목록 표시
                                       기사가 환자 선택 &amp;rarr; 자동 정보 입력&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  RIS는 보통 &lt;b&gt;HL7 표준&lt;/b&gt;을 쓰고 DICOM이 아님. 그래서 중간에 변환 broker가 필요. (HL7은 14편급 주제, 이 책 Ch 14)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.3 MWL SOP Class UID&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1.2.840.10008.5.1.4.31&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.4 MWL DIMSE = C-Find DIMSE 그대로&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;The MWL DIMSE is nothing more than our good old friend C-Find DIMSE&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MWL은 &lt;b&gt;C-Find와 메시지 구조가 동일&lt;/b&gt;. 차이는 SOP Class UID와 IOD 내용뿐.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.5 MWL IOD 핵심 필드&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;내용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0010, 0010)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Patient Name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0010, 0020)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Patient ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0010, 0030)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Birth Date&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0010, 0040)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sex&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0010, 21C0)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pregnancy Status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0008, 0050)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Accession Number (RIS 오더 번호)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0032, 1032)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Requesting Physician&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0008, 0090)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Referring Physician&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0040, 0100)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Scheduled Procedure Step Sequence&lt;/b&gt; (SQ)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;rarr; &lt;code&gt;(0040, 0001)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scheduled Station AET (어느 modality에서 찍을지)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;rarr; &lt;code&gt;(0040, 0002)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scheduled Start Date&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;rarr; &lt;code&gt;(0040, 0003)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scheduled Start Time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;rarr; &lt;code&gt;(0008, 0060)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;rarr; &lt;code&gt;(0040, 0006)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scheduled Performing Physician&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.6 ⚠️ 흔한 함정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Modality가 요구하는 attribute가 위 목록보다 많을 수 있음. &lt;b&gt;누락되면 modality가 MWL 응답 자체를 거부&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 항상 modality의 Conformance Statement 확인:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;이 modality는 어떤 필드를 필수로 요구하나?&quot;&lt;/li&gt;
&lt;li&gt;&quot;지원하지 않는 필드가 들어오면 어떻게 처리하나?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.7 MWL이 AI 추론 앱과 직접 관련 있나?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분 직접 안 씀. MWL은 &lt;b&gt;modality(촬영 장비) &amp;rarr; MWL 서버&lt;/b&gt; 사이의 일이고, AI 추론 앱은 영상이 다 찍힌 뒤 처리하는 단계.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  예외: AI 추론 앱이 &lt;b&gt;워크리스트 UI&lt;/b&gt; 를 제공해서 &quot;오늘 분석할 환자 목록&quot;을 보여주려면 MWL이나 그에 상응하는 정보를 RIS/PACS에서 받아야 함.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 현장 용어 &amp;mdash; DICOM Ping / Push / Pull&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PACS 엔지니어들은 표준 용어 안 씀. 다음 매핑 기억할 것:&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;현장 용어&lt;/th&gt;
&lt;th&gt;표준&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DICOM Ping&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;C-Echo (Verification SOP)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DICOM Push&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;C-Store (영상을 다른 AE로 보내기)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DICOM Pull&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;C-Move 또는 C-Get (영상을 다른 AE에서 가져오기)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &quot;Test connection&quot; 버튼 함정:&lt;br /&gt;PACS UI의 &quot;Test Connection&quot; 버튼이 진짜 C-Echo인지, 단순 TCP ping인지 확인할 것.&lt;br /&gt;TCP ping만 통과시키고 C-Echo 안 되는 PACS = 진짜 연결 안 되는 PACS.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.1 push vs pull 작동 차이&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Push (C-Store)&lt;/b&gt;: 자동화에 적합. modality &amp;rarr; archive 흐름.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Pull (C-Move/C-Get)&lt;/b&gt;: 사람이 골라서. 워크스테이션에서 옛 검사 보기.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &quot;Pull은 사실상 smart push&quot; &amp;mdash; 결국 영상은 C-Store로 옴.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. SCU/SCP 역할 매칭 &amp;mdash; Conformance Statement의 진짜 의미&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.1 SCU/SCP는 클라이언트/서버가 아니다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔한 오해: &quot;SCP = 서버, SCU = 클라이언트&quot;. &lt;b&gt;틀림.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SCU/SCP는 &lt;b&gt;특정 SOP 클래스에 대한 역할&lt;/b&gt;일 뿐.&lt;/p&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;Digital Archive의 진짜 모습:
  - CT Storage SCP (CT 받음)
  - CT Storage SCU (다른 곳으로 CT 전송)         &amp;larr; 클라이언트 역할도 함!
  - Study Root Q/R Find SCP (검색 받음)
  - Study Root Q/R Move SCP (검색 후 보내기)
  - Storage Commitment SCP
  - ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;같은 AE가 같은 SOP에 대해 SCU + SCP를 동시에&lt;/b&gt; 할 수도 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.2 Conformance Statement = SOP &amp;times; Role 매트릭스&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PACS 벤더가 주는 Conformance Statement는 결국 이런 표:&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SOP&lt;/th&gt;
&lt;th&gt;SCU&lt;/th&gt;
&lt;th&gt;SCP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Verification&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CT Image Storage&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MR Image Storage&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;US Image Storage&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secondary Capture Storage&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Study Root Q/R Find&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Study Root Q/R Move&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patient Root Q/R Find&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modality Worklist&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;두 AE가 통신하려면 한쪽이 SCU, 다른 쪽이 SCP를 같은 SOP에 대해 지원&lt;/b&gt; 해야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.3 ⚠️ 흔한 함정들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자가 꼽은 사고 사례:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Verification SCP 미지원&lt;/b&gt;&lt;br /&gt;&amp;rarr; 그 장비로 C-Echo가 안 됨. 디버깅 불가능.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MR Storage SCP만 지원, CT Storage SCP 미지원&lt;/b&gt;&lt;br /&gt;&amp;rarr; 같은 archive인데 CT는 못 받음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Q/R Find SCU만 있고 SCP 없음&lt;/b&gt;&lt;br /&gt;&amp;rarr; 그 워크스테이션을 다른 곳에서 검색할 수 없음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이미지 압축(Transfer Syntax) 미지원&lt;/b&gt;&lt;br /&gt;&amp;rarr; 텔레라디올로지에서 압축 보낼 수가 없음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;저자의 황당 사례&lt;/b&gt;:&lt;br /&gt;&amp;rarr; &amp;nbsp;CR 장비가 &quot;archive를 printer로 등록하라&quot;고 요구. 즉 archive를 Print SCP로 인식하게 해야 동작.&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.4 PACS 모듈 개발 시 Conformance 체크리스트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PACS 벤더와 협의 시작 전 받아야 할 정보:&lt;/p&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;☐ Verification SOP (양방향)
☐ 받을 영상 SOP Class UID (CT/MR/US/...) - 어느 게 SCP인가?
☐ 보낼 결과 SOP Class UID (SC/SR) - 어느 게 SCP인가?
☐ Q/R Find/Move 지원 여부 + Root (Patient or Study)
☐ Transfer Syntax 지원 목록 (Implicit/Explicit, 압축)
☐ AI 추론 앱 AE를 destination으로 등록 가능한지
☐ 사설 Tag 처리 정책
☐ Storage Commitment 사용 여부
☐ Secondary Capture / Structured Report 지원 여부
☐ 최대 Association 수
☐ 권장 Timeout 값
☐ 에러 코드 (Status) 해석 문서&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 보너스 &amp;mdash; Beyond Basic SOP&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 추론 앱 통신 모듈에서 추가로 알면 좋은 SOP들 (Ch 8).&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.1 Storage Commitment SOP&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;진짜로 저장했어?&quot;&lt;/b&gt; 를 확인하는 SOP.&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;1. AI 추론 앱 &amp;rarr; PACS: C-Store (영상)
2. PACS: 받음 (C-Store-Rsp Status=0x0000)
   ↳ 하지만 진짜 영구 저장한 건지? 메모리에만 있고 곧 날아갈 수도?
3. AI 추론 앱 &amp;rarr; PACS: Storage Commitment Request
4. PACS: &quot;응, 영구 저장했어&quot; 또는 &quot;아니, 못 했어&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ 저자 경고:&lt;br /&gt;Storage Commitment는 DICOM 프로토콜일 뿐, &lt;b&gt;실제 저장 보장은 운영 문제&lt;/b&gt;.&lt;br /&gt;PACS 관리자가 디스크 비우려고 영상 삭제하면 어떤 SOP도 못 막음.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AI 추론 앱은 일반적으로 Storage Commitment 안 써도 됨.&lt;/b&gt; PACS 벤더가 요구하면 그때 구현.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.2 Secondary Capture (SC) ⭐⭐&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AI 추론 앱에서 가장 중요한 SOP.&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SC = &quot;modality에서 직접 찍은 영상이 아닌 영상&quot; 을 DICOM으로 저장하는 형식.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;용도:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;필름 스캔&lt;/li&gt;
&lt;li&gt;화면 캡처&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AI 추론 결과 (segmentation 결과 등)&lt;/b&gt; &amp;larr; AI 추론 앱 용도!&lt;/li&gt;
&lt;li&gt;3D 재구성 결과&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SC SOP Class UID&lt;/b&gt;: &lt;code&gt;1.2.840.10008.5.1.4.1.1.7&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.3 ⚠️ SC의 흔한 함정 &amp;mdash; Modality 라벨링&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자 예시:&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;CT perfusion 분석 후 컬러맵 생성
&amp;rarr; 원본 CT study에 추가하고 싶음
&amp;rarr; Modality를 &quot;CT&quot;로 라벨링?
   ❌ CT IOD 요구사항 불만족 (Hounsfield 스케일, monochrome 등)
   &amp;rarr; CT 처리 함수가 에러
&amp;rarr; Modality를 &quot;SC&quot;로 라벨링?
   ❌ 단순한 PACS가 CT study 전송 시 SC 빠뜨림&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결&lt;/b&gt;: AI 추론 앱은 SC IOD로 만들되, &lt;b&gt;Series 단위로 별도&lt;/b&gt; 생성. Study UID는 원본과 동일하게 유지 (이미 &lt;a href=&quot;https://chaechae0.tistory.com/42&quot;&gt;전편&lt;/a&gt;에서 다룸).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.4 Structured Report (SR)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;텍스트 + 영상 참조 + 측정값&lt;/b&gt; 을 한 객체에 담는 SOP.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 추론 앱의 추론 결과를 SR로 표현 가능:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;PI-RADS score: 4&quot;&lt;/li&gt;
&lt;li&gt;&quot;Lesion location: peripheral zone, left mid&quot;&lt;/li&gt;
&lt;li&gt;&quot;Lesion volume: 1.2 mL&quot;&lt;/li&gt;
&lt;li&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 lesion이 보이는 영상 참조 (SOP Instance UID)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SOP&lt;/th&gt;
&lt;th&gt;UID&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Basic Text SR&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.88.11&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enhanced SR&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.88.22&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Comprehensive SR&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.88.33&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  SR은 &lt;b&gt;검색 가능&lt;/b&gt;. SC 이미지는 이미지일 뿐이라 텍스트 검색 불가.&lt;br /&gt;워크플로우에 SR을 적용하면 &quot;PI-RADS 4 이상 환자 모두 찾기&quot; 같은 쿼리 가능.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AI 추론 앱 출력 전략 옵션&lt;/b&gt;:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;SC + 결과 텍스트 burn-in&lt;/b&gt; (단순, 모든 PACS 지원)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SC + SR&lt;/b&gt; (이상적, PACS가 SR 지원할 때)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DICOM SEG&lt;/b&gt; (segmentation 전용 SOP, 최신 PACS)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PACS 벤더의 SR/SEG 지원 여부를 Conformance에서 확인.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. AI 추론 앱 영상 수신 파이프라인 (완성)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 전체 그림이 보인다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9.1 시나리오 A: PACS가 AI 추론 앱에 push&lt;/h3&gt;
&lt;pre class=&quot;prolog&quot;&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────────┐
│  의사: &quot;이 환자 AI 분석 돌려&quot; 버튼 클릭                            │
│  PACS UI &amp;rarr; 내부 워크플로우                                         │
└──────────────────────────────────────────────────────────────────┘
                              │
                              ▼
   [PACS] ──── C-Store (MR Image Storage SOP) ───&amp;rarr; [AI 추론 앱]
                                                          │
                                                          │ 영상 누적
                                                          │ (한 시리즈 30장)
                                                          ▼
                                                   [추론 트리거]
                                                          │ AI 모델
                                                          ▼
                                                   [Segmentation 결과]
                                                          │
                                                          ▼
                              ┌───────────────────────────┴────────┐
                              ▼                                    ▼
                  [SC Image 생성]                       [Structured Report 생성]
                  (overlay된 영상)                       (PI-RADS score 등)
                              │                                    │
                              └────────────┬───────────────────────┘
                                           ▼
                  [AI 추론 앱] ── C-Store ──&amp;rarr; [PACS]
                                           (Patient/Study UID 원본 유지,
                                            Series/SOP UID 새로 생성)
                                           │
                                           ▼
                              ┌──────────────────────────┐
                              │  PACS UI에서 원본 옆에     │
                              │  &quot;AI 결과&quot; 시리즈 추가됨    │
                              └──────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9.2 시나리오 B: AI 추론 앱이 능동적으로 pull&lt;/h3&gt;
&lt;pre class=&quot;prolog&quot;&gt;&lt;code&gt;[AI 추론 앱 UI] &quot;환자 검색&quot;
        │
        ▼
[AI 추론 앱] ── C-Find (Study Root) ──&amp;rarr; [PACS]
                                          │
                                          │ Patient + Modality + Date
                                          │ 조건으로 검색
        &amp;larr;── C-Find-Rsp (Study UID 목록) ──
        │
        │ 사용자가 Study 선택
        ▼
[AI 추론 앱] ── C-Move ──&amp;rarr; [PACS]
              Dest=AIAPP_AE
                                          │
                                          │ PACS가 별도 association 열기
                                          ▼
[AI 추론 앱] &amp;larr;── C-Store (영상들) ── [PACS]
        │
        ▼
   (이후 추론 &amp;rarr; 결과 송신은 시나리오 A와 동일)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;구현 필요 SOP 역할 (시나리오 A+B 모두)&lt;/b&gt;:&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;SOP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SCU&lt;/td&gt;
&lt;td&gt;Verification, C-Find, C-Move, C-Store (결과 송신)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SCP&lt;/td&gt;
&lt;td&gt;Verification, C-Store (영상 수신)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9.3 Orthanc로 구현 시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Orthanc가 위 모든 SOP를 다 구현해줌. 우리는 HTTP REST로 조작:&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;import requests

# 1) PACS 등록 (Orthanc 설정)
# orthanc.json:
# &quot;DicomModalities&quot;: {
#   &quot;PACS&quot;: [&quot;PACS_AE&quot;, &quot;192.168.1.10&quot;, 104]
# }

# 2) C-Echo
r = requests.post(&quot;http://orthanc:8042/modalities/PACS/echo&quot;)

# 3) C-Find
r = requests.post(
    &quot;http://orthanc:8042/modalities/PACS/query&quot;,
    json={&quot;Level&quot;: &quot;Study&quot;,
          &quot;Query&quot;: {&quot;PatientID&quot;: &quot;12345&quot;,
                    &quot;StudyDate&quot;: &quot;20260601-&quot;,
                    &quot;ModalitiesInStudy&quot;: &quot;MR&quot;}}
)
query_id = r.json()[&quot;ID&quot;]

# 4) 결과 조회 &amp;rarr; Study UID들 얻기
studies = requests.get(
    f&quot;http://orthanc:8042/queries/{query_id}/answers&quot;
).json()

# 5) C-Move (AI 추론 앱 = Orthanc 자기 자신에게)
r = requests.post(
    f&quot;http://orthanc:8042/queries/{query_id}/retrieve&quot;,
    data=&quot;ORTHANC&quot;   # Orthanc 자기 AE Title
)

# 6) 영상 도착 후 webhook으로 추론 트리거 가능
# orthanc.json:
# &quot;LuaScripts&quot;: [&quot;./on_store.lua&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;저수준 DICOM 메시지는 Orthanc가 다 처리.&lt;/b&gt; 우리는 비즈니스 로직만.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. 핵심 정리&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;개념&lt;/th&gt;
&lt;th&gt;한 줄&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;C-Get&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;단일 association, SCP가 SCU에게 C-Store. 단순. 방화벽 친화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;C-Move&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;별도 association, 제3 AE 가능. 정적 환경 권장. 방화벽 함정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;C-Move Dest&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;AE Title만 적음. SCP가 IP/Port 미리 알아야 함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;C-Get IOD&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;정확값만. Wildcard 안 됨. &amp;rarr; C-Find로 키 먼저 얻음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;저자 결론&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&quot;C-Move inside, C-Get outside&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;MWL&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;C-Find DIMSE 그대로. RIS에서 환자 일정 자동 조회. SOP UID = &lt;code&gt;...5.1.4.31&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DICOM Ping/Push/Pull&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;C-Echo / C-Store / C-Move(Get) 의 현장 용어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;SCU/SCP&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;클라이언트/서버 아님. SOP별 역할. 같은 AE가 둘 다 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Conformance Statement&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;SOP &amp;times; Role 매트릭스. PACS 통신의 정답지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Storage Commitment&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;영구 저장 보장. 운영 문제. 보통 안 씀&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Secondary Capture&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;AI 결과 영상 저장에 표준. SOP UID = &lt;code&gt;...1.4.1.1.7&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Structured Report&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;텍스트 + 측정값 + 영상 참조. 검색 가능. 권장 출력 형식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;AI 추론 앱 필수 SOP&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Verification (양), C-Store SCP (영상 받기), C-Store SCU (결과 송신)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. 다음 글에서 다룰 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 DICOM &lt;b&gt;응용 메시지 (DIMSE)&lt;/b&gt; 의 핵심을 다 봤다. 하지만 우리는 한 가지를 &lt;b&gt;얼버무리고 넘어왔다&lt;/b&gt;:&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;두 AE가 통신하려면 먼저 &lt;b&gt;Association&lt;/b&gt; 을 맺어야 한다&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 Association이 어떻게 협상되는지, &lt;b&gt;Transfer Syntax, Abstract Syntax, Presentation Context, PDU&lt;/b&gt; 가 뭔지 &amp;mdash; DICOM 통신 디버깅의 &lt;b&gt;80%가 일어나는 곳&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6편: DICOM Association &amp;mdash; 통신을 떠받치는 인프라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TCP 연결 &amp;rarr; DICOM Association 협상 과정&lt;/li&gt;
&lt;li&gt;Abstract Syntax (어떤 SOP) &amp;harr; Transfer Syntax (어떻게 인코딩) 협상&lt;/li&gt;
&lt;li&gt;Presentation Context&lt;/li&gt;
&lt;li&gt;A-Associate-RQ / AC / RJ&lt;/li&gt;
&lt;li&gt;PDU (Protocol Data Unit)&lt;/li&gt;
&lt;li&gt;실제 Orthanc 로그 해석&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기를 알아야 &quot;Association rejected&quot;, &quot;Presentation context not accepted&quot; 같은 흔한 에러를 직접 디버깅할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pianykh, O.S. &lt;i&gt;Digital Imaging and Communications in Medicine (DICOM)&lt;/i&gt;. Springer, 2008.&lt;/li&gt;
&lt;li&gt;공식 표준 매핑:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;PS3.4&lt;/b&gt; (Service Class Specifications) &amp;mdash; Q/R, MWL 정의&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PS3.7&lt;/b&gt; (Message Exchange) &amp;mdash; DIMSE 메시지 구조&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;라이브러리:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;pynetdicom&lt;/b&gt; &amp;mdash; Python으로 C-Move/C-Get/C-Store/MWL 직접 구현 시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Orthanc REST API&lt;/b&gt; &amp;mdash; 추상화된 인터페이스&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DICOM SR 깊이 학습:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Clunie, D. &lt;i&gt;DICOM Structured Reporting&lt;/i&gt; (2000) &amp;mdash; 저자 추천&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Dev/DICOM</category>
      <category>dicom</category>
      <category>의료데이터통신</category>
      <author>odod00</author>
      <guid isPermaLink="true">https://chaechae0.tistory.com/44</guid>
      <comments>https://chaechae0.tistory.com/44#entry44comment</comments>
      <pubDate>Wed, 10 Jun 2026 13:58:42 +0900</pubDate>
    </item>
    <item>
      <title>[DICOM] DICOM 통신의 시작 &amp;mdash; C-Echo, C-Store, C-Find</title>
      <link>https://chaechae0.tistory.com/43</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oleg Pianykh, Digital Imaging and Communications in Medicine (DICOM) (Springer, 2008) 정리 4편&lt;br /&gt;참고 챕터: Ch 7.1 &amp;ndash; 7.4&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글부터는 &lt;b&gt;&quot;그 데이터가 어떻게 네트워크를 타고 흘러가는가&quot;&lt;/b&gt; 의 세계로 진입이라고 볼 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 편의 목표는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AE Title / IP / Port &amp;mdash; 네트워크에서 DICOM 단위를 식별하는 법&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SCU &amp;harr; SCP&lt;/b&gt; 모델, &lt;b&gt;DIMSE&lt;/b&gt; 프로토콜&lt;/li&gt;
&lt;li&gt;가장 기본 3개 서비스: &lt;b&gt;C-Echo, C-Store, C-Find&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;진짜 PACS 통신 모듈을 짜기 위한 토대&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 알면 Orthanc 로그에서 일어나는 일을 80% 해석할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. DICOM Networking의 위치&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM은 새로운 네트워크 프로토콜이 아니다. &lt;b&gt;TCP/IP 위에서 도는 응용 계층 프로토콜&lt;/b&gt;이다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;┌─────────────────────────────────────┐
│    DIMSE (DICOM 응용 메시지)         │  &amp;larr; 7-9편에서 다룰 것
├─────────────────────────────────────┤
│    DICOM Upper Layer (UL) Protocol   │  &amp;larr; Association (6편)
├─────────────────────────────────────┤
│    TCP                                │
├─────────────────────────────────────┤
│    IP                                 │
├─────────────────────────────────────┤
│    Ethernet / WiFi                    │
└─────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;HTTP가 80번 포트, SMTP가 25번&lt;/b&gt; 처럼&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DICOM 기본 포트는 104번&lt;/b&gt; (옛날에 NEMA가 받아둠)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흥미로운 역사: DICOM은 인터넷이 보급되기 &lt;i&gt;전&lt;/i&gt; 부터 설계됐다. 옛 PS3.9는 &quot;Point-to-Point 케이블 통신&quot;용이었음. 지금은 폐기되고 TCP/IP만 사용.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. AE / AE Title / IP / Port&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 AE (Application Entity)란?&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;헷갈리기 쉬운 포인트&lt;/b&gt;:&lt;br /&gt;&lt;b&gt;AE는 컴퓨터(장비)가 아니라 그 위에서 도는 &quot;DICOM 애플리케이션&quot;&lt;/b&gt; 이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 PC에 여러 AE가 돌 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;PC 1대 (IP: 192.168.1.10)
  ├─ AE &quot;ORTHANC_MAIN&quot;     포트 4242
  ├─ AE &quot;AI_INFERENCE&quot;      포트 11112
  └─ AE &quot;BACKUP_SCP&quot;        포트 11113&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 같은 IP라도 &lt;b&gt;AE Title + Port&lt;/b&gt; 조합으로 구분.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 AE를 식별하는 3종 세트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PACS 네트워크에서 어떤 AE와 통신하려면 &lt;b&gt;3가지 정보&lt;/b&gt;가 필요하다:&lt;/p&gt;
&lt;table style=&quot;height: 87px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 24px;&quot;&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;항목&lt;/th&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;설명&lt;/th&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;AE Title (AET)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;DICOM 상의 이름 (&lt;code&gt;AE&lt;/code&gt; VR, 16자 이내)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;code&gt;ORTHANC&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;IP Address&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;네트워크 주소&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;code&gt;192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;Port Number&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;TCP 포트&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;code&gt;4242&lt;/code&gt; (또는 104)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  비유&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴퓨터 이름 = 거리 이름&lt;/li&gt;
&lt;li&gt;포트 번호 = 집 번호&lt;/li&gt;
&lt;li&gt;AE Title = 거기 사는 사람 이름&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3 AE Title 명명 규칙&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표준은 느슨하지만 실무 컨벤션:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;✅ &lt;b&gt;대문자, 영숫자, &lt;code&gt;_&lt;/code&gt;&lt;/b&gt; 만 사용 (&lt;code&gt;PACSSERVER&lt;/code&gt;, &lt;code&gt;CT_WORKSTATION1&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;❌ 공백, 한글, 특수문자, 소문자 ❌ (벤더마다 대소문자 구분이 다름)&lt;/li&gt;
&lt;li&gt;✅ &lt;b&gt;역할/위치를 의미있게&lt;/b&gt; (&lt;code&gt;MR1FLOOR&lt;/code&gt;, &lt;code&gt;RADIOLOGY_ARCHIVE&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;❌ 의미 없는 이름 (&lt;code&gt;AE1&lt;/code&gt;, &lt;code&gt;XYZ&lt;/code&gt;) ❌&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.4 ⚠️ 양방향 등록 함정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;표준상&lt;/b&gt;: AE X가 AE Y로 보내려면 X가 Y의 (IP/Port/AET)을 알면 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;현실&lt;/b&gt;: 많은 PACS가 &lt;b&gt;양방향 등록&lt;/b&gt; 을 요구한다. Y도 X를 알아야 함.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;❌ 문제 상황 예시
PACS 서버 Y의 화이트리스트에 AI 추론 앱 (X)이 등록 안 됨
&amp;rarr; AI 추론 앱이 보낸 C-Store를 PACS가 거부 (&quot;Unknown AE&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;PACS 모듈 개발 시 체크리스트&lt;/b&gt;:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;AI 추론 앱의 AE 정보를 PACS 벤더에게 알려서 등록 요청&lt;/li&gt;
&lt;li&gt;PACS의 AE/IP/Port를 AI 추론 앱 설정에 넣기&lt;/li&gt;
&lt;li&gt;&lt;b&gt;C-Echo로 양방향 verify&lt;/b&gt; (둘 다 응답해야 함)&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.5 포트 번호 베스트 프랙티스&lt;/h3&gt;
&lt;pre class=&quot;elm&quot;&gt;&lt;code&gt;✅ 104 (DICOM 공식 포트)
✅ 11112 (pynetdicom 기본값, Orthanc 기본 DICOM port와 다름)
✅ 4242 (Orthanc DICOM 기본값)
✅ 10000번대 (충돌 적음)

❌ 80 (HTTP가 잡음)
❌ 22 (SSH)
❌ 25 (SMTP)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Orthanc의 흔한 포트 구성&lt;/b&gt; (참고):&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;4242&lt;/b&gt;: DICOM (DIMSE) 포트&lt;/li&gt;
&lt;li&gt;&lt;b&gt;8042&lt;/b&gt;: HTTP REST API / 웹 UI&lt;/li&gt;
&lt;li&gt;둘 다 따로 설정함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. SCU &amp;harr; SCP 모델&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM의 모든 통신은 &lt;b&gt;클라이언트&amp;ndash;서버&lt;/b&gt; 구조다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;역할&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;SCU (Service Class User)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;서비스를 &lt;b&gt;요청&lt;/b&gt;하는 쪽 (클라이언트)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;SCP (Service Class Provider)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;서비스를 &lt;b&gt;제공&lt;/b&gt;하는 쪽 (서버)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;   &quot;이미지 저장해줘&quot;
SCU ─────────────────&amp;rarr; SCP
              &amp;larr; ─────  &quot;저장 완료&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 같은 AE가 양쪽 다 할 수 있다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 AE가 &lt;b&gt;여러 서비스에서 SCU, SCP 둘 다&lt;/b&gt; 가능. 흔한 패턴:&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;AE&lt;/th&gt;
&lt;th&gt;C-Echo&lt;/th&gt;
&lt;th&gt;C-Store&lt;/th&gt;
&lt;th&gt;C-Find&lt;/th&gt;
&lt;th&gt;C-Move&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CT 장비&lt;/td&gt;
&lt;td&gt;SCP&lt;/td&gt;
&lt;td&gt;&lt;b&gt;SCU&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&amp;ndash;&lt;/td&gt;
&lt;td&gt;&amp;ndash;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PACS 서버&lt;/td&gt;
&lt;td&gt;SCU/SCP&lt;/td&gt;
&lt;td&gt;SCU/&lt;b&gt;SCP&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;SCP&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;SCP&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;판독 워크스테이션&lt;/td&gt;
&lt;td&gt;SCU&lt;/td&gt;
&lt;td&gt;&amp;ndash;&lt;/td&gt;
&lt;td&gt;SCU&lt;/td&gt;
&lt;td&gt;SCU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI 추론 앱&lt;/td&gt;
&lt;td&gt;SCU/SCP&lt;/td&gt;
&lt;td&gt;SCU/SCP&lt;/td&gt;
&lt;td&gt;SCU&lt;/td&gt;
&lt;td&gt;SCU&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;PACS 모듈 개발 시&lt;/b&gt;:&lt;br /&gt;AI 추론 앱은 보통 &lt;b&gt;C-Move SCU&lt;/b&gt;(영상 가져오기) + &lt;b&gt;C-Store SCP&lt;/b&gt;(가져온 영상 받기) + &lt;b&gt;C-Store SCU&lt;/b&gt;(결과 다시 보내기) 의 세 역할을 동시에 함.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. DIMSE &amp;mdash; DICOM의 응용 메시지 프로토콜&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DIMSE&lt;/b&gt; = &lt;b&gt;D&lt;/b&gt;ICOM &lt;b&gt;M&lt;/b&gt;essage &lt;b&gt;S&lt;/b&gt;ervice &lt;b&gt;E&lt;/b&gt;lements&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AE끼리 주고받는 메시지의 표준 형식.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1 메시지 구조 &amp;mdash; Command + (선택적) Data&lt;/h3&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;┌─────────────────────────────┐
│   Command Object             │  &amp;larr; 항상 있음 (group 0000)
│   - 어떤 서비스인지            │
│   - Message ID                │
│   - Status                    │
├─────────────────────────────┤
│   Data Object (선택)          │  &amp;larr; 있을 때도, 없을 때도
│   - 실제 IOD (영상, 환자 정보 등)│
└─────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 필드: &lt;b&gt;&lt;code&gt;(0000, 0800) Data Set Type&lt;/code&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;0x0101&lt;/code&gt; = NULL (Data 없음, Command만)&lt;/li&gt;
&lt;li&gt;그 외 = Data가 뒤따라옴&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2 DIMSE-C vs DIMSE-N&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&amp;nbsp;&lt;/th&gt;
&lt;th&gt;다루는 IOD&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DIMSE-C&lt;/b&gt; (Composite)&lt;/td&gt;
&lt;td&gt;Composite IOD (영상 등)&lt;/td&gt;
&lt;td&gt;C-Echo, C-Store, C-Find, C-Move, C-Get&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DIMSE-N&lt;/b&gt; (Normalized)&lt;/td&gt;
&lt;td&gt;Normalized IOD&lt;/td&gt;
&lt;td&gt;N-Set, N-Get, N-Action, ... (Print, MPPS 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 거의 모든 영상 작업은 &lt;b&gt;DIMSE-C&lt;/b&gt;. PACS 통신 시 99%가 이쪽.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.3 Rq / Rsp 패턴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청(Request)과 응답(Response)이 짝지어 다님:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;C-Store-Rq&lt;/code&gt;&lt;/b&gt; (요청) &amp;harr; &lt;b&gt;&lt;code&gt;C-Store-Rsp&lt;/code&gt;&lt;/b&gt; (응답)&lt;/li&gt;
&lt;li&gt;Command Field 값으로 구분:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;0x0001&lt;/code&gt; = C-Store-Rq&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0x8001&lt;/code&gt; = C-Store-Rsp (&lt;b&gt;Rsp는 항상 &lt;code&gt;8___&lt;/code&gt; 패턴&lt;/b&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.4 Message ID &amp;mdash; 요청/응답 짝맞추기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바쁜 PACS는 초당 수십 개의 DIMSE를 받음. &lt;b&gt;Message ID&lt;/b&gt; 로 짝을 맞춤:&lt;/p&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;SCU                                SCP
 │                                  │
 │ C-Store-Rq  Msg ID = 42         │
 ───────────────────────────────&amp;rarr;
 │                                  │
 │  Msg ID Being Responded To = 42  │
 │  C-Store-Rsp                     │
 &amp;larr;───────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;(0000, 0110) Message ID&lt;/code&gt; (요청) &amp;rarr; &lt;code&gt;(0000, 0120) Message ID Being Responded To&lt;/code&gt; (응답)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. C-Echo &amp;mdash; DICOM의 ping&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1 왜 필요한가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결 확인은 일반 ping으로도 되지 않나? &lt;b&gt;안 된다.&amp;nbsp;&lt;/b&gt;이유는&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;ICMP ping은 &lt;b&gt;TCP/IP만 확인&lt;/b&gt; &amp;mdash; DICOM 소프트웨어 안 돌고 있어도 성공&lt;/li&gt;
&lt;li&gt;AE Title, Port가 잘못돼도 ping은 성공&lt;/li&gt;
&lt;li&gt;방화벽이 DICOM 포트만 막아도 ping은 성공&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;C-Echo만이 &quot;이 AE가 진짜 DICOM 말 할 줄 안다&quot; 를 증명&lt;/b&gt; 한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.2 C-Echo 동작&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;SCU                                 SCP
 │                                   │
 │  C-Echo-Rq                        │
 │  (0000,0002) UID=1.2.840.10008.1.1│
 │  (0000,0100) Command=0x0030       │
 │  (0000,0110) MessageID=42         │
 │  (0000,0800) Data Set Type=0x0101 │
 ───────────────────────────────&amp;rarr;
 │                                   │
 │  C-Echo-Rsp                       │
 │  (0000,0100) Command=0x8030       │
 │  (0000,0120) Resp to=42           │
 │  (0000,0900) Status=0x0000        │ &amp;larr; 0 = 성공
 &amp;larr;───────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;구현해야 할 건 단 하나 &amp;mdash; Message ID 생성/매칭.&lt;/b&gt; 나머지는 다 고정값.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.3 C-Echo-Rq 바이트 덤프&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 네트워크에는 &lt;b&gt;68 byte&lt;/b&gt;가 흘러간다 (Implicit VR + Little Endian):&lt;/p&gt;
&lt;table style=&quot;height: 195px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 24px;&quot;&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;Byte #&lt;/th&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;값&lt;/th&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;1&amp;ndash;8&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;code&gt;00 00 00 00 04 00 00 00&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;code&gt;(0000,0000)&lt;/code&gt; Group Length 태그 + length=4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;9&amp;ndash;12&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;code&gt;38 00 00 00&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Group Length 값 = 56 (이후 바이트 수)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;13&amp;ndash;20&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;00 00 02 00 12 00 00 00&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0000,0002)&lt;/code&gt; + length=18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;21&amp;ndash;38&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;&quot;1.2.840.10008.1.1\0&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;SOP Class UID (18 byte)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;39&amp;ndash;48&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;00 00 00 01 02 00 00 00 30 00&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0000,0100)&lt;/code&gt; + length=2 + value=&lt;code&gt;0x0030&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;49&amp;ndash;56&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;00 00 10 01 02 00 00 00&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0000,0110)&lt;/code&gt; + length=2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;57&amp;ndash;58&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;(생성한 ID)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Message ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;59&amp;ndash;66&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;00 00 00 08 02 00 00 00&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0000,0800)&lt;/code&gt; + length=2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;67&amp;ndash;68&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;01 01&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Data Set Type = &lt;code&gt;0x0101&lt;/code&gt; (NULL)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 정말 단순함. &lt;b&gt;wireshark로 캡처하면 이대로 보임.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.4 C-Echo 실패 시 트러블슈팅&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;증상&lt;/th&gt;
&lt;th&gt;원인&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Timeout&lt;/td&gt;
&lt;td&gt;1. 네트워크 케이블/방화벽&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;2. 잘못된 IP/Port&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;3. SCP가 안 도는 중&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x0211&lt;/code&gt; Unrecognized Operation&lt;/td&gt;
&lt;td&gt;SCP가 Verification SOP 미지원 (벤더 문제)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Association rejected&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;AE Title이 화이트리스트에 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;PACS 통신 디버깅의 첫 단계는 무조건 C-Echo.&lt;/b&gt; Orthanc UI에 &quot;Test Echo&quot; 버튼 있음. 거기서 시작.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.5 ⚠️ Verification SCP 미지원 = 위험 신호&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자가 겪은 실제 사례:&lt;br /&gt;한 CR 장비 벤더가 Verification SCP를 일부러 끄고 &quot;보안&quot; 이라고 주장.&lt;br /&gt;&amp;rarr; &lt;b&gt;C-Echo는 데이터 전송하지 않음.&lt;/b&gt; 보안과 무관. 그냥 게으름.&lt;br /&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;Verification SCP 안 되는 장비는 &lt;/span&gt;&lt;b&gt;사지 말 것&lt;/b&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; (저자 추천).&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. SOP &amp;mdash; Service-Object Pair 의 정확한 의미&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SOP = DIMSE 서비스 + IOD&lt;/b&gt; 를 한 묶음으로 정의한 것.&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;SOP = &quot;이 IOD에 이 서비스를 적용한다&quot; 의 표준화된 단위&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Verification SOP&lt;/b&gt; = C-Echo + (IOD 없음)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CT Image Storage SOP&lt;/b&gt; = C-Store + CT Image IOD&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MR Image Storage SOP&lt;/b&gt; = C-Store + MR Image IOD&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Study Root Query/Retrieve SOP&lt;/b&gt; = C-Find/C-Move + Patient-Study 키 IOD&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;각 SOP는 고유 UID&lt;/b&gt; 를 가짐:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;1.2.840.10008.1.1&lt;/code&gt; = Verification SOP Class UID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.2&lt;/code&gt; = CT Image Storage SOP Class UID&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Conformance Statement는 SOP Class UID 목록의 형태로 작성&lt;/b&gt; 된다.&lt;br /&gt;&quot;우리 장비는 이런 SOP들을 지원하고, 어떤 건 SCU, 어떤 건 SCP다&quot; 식으로.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. C-Store &amp;mdash; 영상 저장&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가장 자주 쓰이는 서비스.&lt;/b&gt; 영상을 한 AE에서 다른 AE로 보낸다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.1 IOD 타입별 SOP Class UID&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Modality / Type&lt;/th&gt;
&lt;th&gt;SOP Class UID&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CR Image&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CT Image&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enhanced CT&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.2.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;MR Image&lt;/b&gt; ⭐&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.4&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enhanced MR&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.4.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;US Single Frame&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.6.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;US Multiframe (cine)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.3.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NM (Nuclear Medicine)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.20&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PET&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.128&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Secondary Capture&lt;/b&gt; ⭐&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.7&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Basic Text SR&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.88.11&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enhanced SR&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.88.22&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Comprehensive SR&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.88.33&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;AI 추론 앱 입장&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;수신&lt;/b&gt;: MR Image Storage SOP (&lt;code&gt;...1.4&lt;/code&gt;) &amp;mdash; MR 받음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;송신&lt;/b&gt;: Secondary Capture (&lt;code&gt;...1.7&lt;/code&gt;) 또는 Enhanced SR &amp;mdash; 추론 결과 보냄&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.2 C-Store 한 번 = 영상 1개&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심 규칙&lt;/b&gt;: 한 C-Store는 &lt;b&gt;1개의 IOD instance만&lt;/b&gt; 보낸다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;CT 시리즈 2000장 &amp;rarr; C-Store 2000번 호출&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예외: Multi-frame IOD (US cine, multi-frame CT 등) 는 한 객체 안에 여러 frame 가능 &amp;rarr; 1번 호출.&lt;br /&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;오버헤드는 좀 있지만 &lt;/span&gt;&lt;b&gt;각 영상의 성공/실패를 개별 추적&lt;/b&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; 할 수 있음.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.3 C-Store-Rq 핵심 필드&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;내용&lt;/th&gt;
&lt;th&gt;비고&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0000,0002)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Affected SOP Class UID&lt;/td&gt;
&lt;td&gt;위 표의 UID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0000,0100)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Command Field = &lt;code&gt;0x0001&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;C-Store-Rq&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0000,0110)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Message ID&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0000,0700)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Priority&lt;/td&gt;
&lt;td&gt;low/med/high (대부분 무시)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0000,0800)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Data Set Type&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;ne; 0x0101&lt;/code&gt; (데이터 있음)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0000,1000)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Affected SOP Instance UID&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;이미지의 UID&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0000,1030)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Move Originator AET&lt;/td&gt;
&lt;td&gt;C-Move로 호출됐을 때만&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0000,1031)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Move Originator Message ID&lt;/td&gt;
&lt;td&gt;위와 같음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 그 뒤에 &lt;b&gt;실제 영상 IOD (Data Object)&lt;/b&gt; 가 붙어서 전송됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.4 C-Store-Rsp Status 값&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x0000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;성공&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0xFF00&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;진행 중&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0xA700&lt;/code&gt;, &lt;code&gt;0xA900&lt;/code&gt;, &lt;code&gt;0xC000~&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;에러 (벤더별 코드, Conformance 참조)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.5 ⚠️ C-Store 실무 함정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자 사례:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 CR 장비가 Patient ID 빈 영상 1건의 C-Store가 reject되자 &lt;b&gt;그 이후 모든 전송을 중단&lt;/b&gt;. 며칠 만에 로컬 디스크 가득 차서 환자 못 받음.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;PACS 모듈 개발 원칙&lt;/b&gt;:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;개별 실패가 전체 큐를 중단시키면 안 됨&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;실패 영상은 별도 큐로 빼고 나머지는 계속 진행&lt;/li&gt;
&lt;li&gt;재시도는 backoff 로 (즉시 재시도 ❌)&lt;/li&gt;
&lt;li&gt;모든 실패를 로그에 남김 (Status 코드, SOP Instance UID 포함)&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. C-Find &amp;mdash; 영상 검색&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PACS에서 &lt;b&gt;&quot;무엇이 있는지&quot;&lt;/b&gt; 질의하는 서비스.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.1 Query Root 3종 (사실상 2종)&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SOP Class&lt;/th&gt;
&lt;th&gt;UID&lt;/th&gt;
&lt;th&gt;비고&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Patient Root Q/R Find&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.2.1.1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Patient부터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Study Root Q/R Find&lt;/b&gt; ⭐&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.2.2.1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Study부터 (가장 흔함)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patient-Study Root&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.2.3.1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Retired&lt;/b&gt; (사용 금지)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;현대 PACS의 99%는 Study Root.&lt;/b&gt; 환자 단위가 아니라 검사 단위로 워크플로우가 돌기 때문.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.2 Query Level &amp;mdash; 4계층 어디서 검색?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;./03-Hierarchy-IOD.md&quot;&gt;3편&lt;/a&gt;의 Patient&amp;rarr;Study&amp;rarr;Series&amp;rarr;Image 4계층. C-Find는 이 중 어느 레벨에서 검색할지 명시:&lt;/p&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;(0008, 0052) Query/Retrieve Level    CS
값: &quot;PATIENT&quot; | &quot;STUDY&quot; | &quot;SERIES&quot; | &quot;IMAGE&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 보통 &lt;b&gt;단계별 drill-down&lt;/b&gt;:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;STUDY 레벨에서 환자/날짜로 검색 &amp;rarr; Study UID 목록&lt;/li&gt;
&lt;li&gt;그 Study UID + SERIES 레벨로 검색 &amp;rarr; Series UID 목록&lt;/li&gt;
&lt;li&gt;그 Series UID + IMAGE 레벨로 검색 &amp;rarr; SOP Instance UID 목록&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.3 매칭 방식 4가지&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;방식&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Wildcard&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Smit*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;*&lt;/code&gt; = 임의 문자열, &lt;code&gt;?&lt;/code&gt; = 한 글자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;List&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Smith\Graham&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\&lt;/code&gt; = OR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Universal&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;&quot;&lt;/code&gt; (빈값)&lt;/td&gt;
&lt;td&gt;모든 값 매칭 (필드를 받아오고 싶을 때)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Range&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;20060101-20070101&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-&lt;/code&gt; = 범위 (날짜/시간용)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.4 C-Find IOD &amp;mdash; 자주 쓰는 필드&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;이름&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;th&gt;매칭&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0008,0052)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Query Level&lt;/td&gt;
&lt;td&gt;&lt;code&gt;STUDY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;필수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0010,0010)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Patient Name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Smit*\Grah*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wildcard + List&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0010,0020)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Patient ID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;12345&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;보통 정확 매칭&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0008,0020)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Study Date&lt;/td&gt;
&lt;td&gt;&lt;code&gt;20260101-20260601&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Range&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0008,0030)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Study Time&lt;/td&gt;
&lt;td&gt;&lt;code&gt;080000-180000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Range&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0008,0050)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Accession Number&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ABC789&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;정확 매칭 (RIS 연동)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0020,000D)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Study Instance UID&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;정확 매칭&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0008,0061)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modalities in Study&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MR\CT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0008,1030)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Study Description&lt;/td&gt;
&lt;td&gt;&lt;code&gt;*chest*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wildcard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0010,0030)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Birth Date&lt;/td&gt;
&lt;td&gt;&lt;code&gt;19560101-19860101&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Range&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;Universal Matching의 미묘함&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빈 값으로 보냄 &amp;rarr; &quot;이 필드 매칭하고 응답에 값 받고 싶음&quot;&lt;/li&gt;
&lt;li&gt;필드 자체를 안 보냄 &amp;rarr; &quot;필요 없음&quot;&lt;/li&gt;
&lt;li&gt;둘이 다름! 응답에서 받고 싶은 필드는 &lt;b&gt;빈 값이라도 반드시 포함&lt;/b&gt; 해야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.5 ⚠️ Modality 함정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분 사람들이 &quot;Modality는 Study의 속성&quot;으로 생각하지만:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;(0008, 0060) Modality&lt;/code&gt; &amp;rarr; &lt;b&gt;실제로는 Series 레벨 속성&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(0008, 0061) Modalities in Study&lt;/code&gt; &amp;rarr; Study 레벨 (옵션, 지원 안 하는 PACS 많음)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; Study Root에서 modality로 필터하고 싶으면:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;Modalities in Study&lt;/code&gt; 시도 (안 될 수 있음)&lt;/li&gt;
&lt;li&gt;안 되면 Study 받아서 &amp;rarr; Series 레벨 추가 쿼리&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.6 C-Find Response &amp;mdash; Multi-response 패턴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C-Find는 &lt;b&gt;응답이 여러 번&lt;/b&gt; 온다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;SCU                                     SCP
 │                                       │
 │  C-Find-Rq                            │
 ────────────────────────────────────&amp;rarr;
 │                                       │
 │  C-Find-Rsp  Status=0xFF00 (pending)  │
 │  + IOD #1                             │
 &amp;larr;────────────────────────────────────
 │  C-Find-Rsp  Status=0xFF00 (pending)  │
 │  + IOD #2                             │
 &amp;larr;────────────────────────────────────
 │  ...                                  │
 │                                       │
 │  C-Find-Rsp  Status=0x0000 (done)     │
 │  (마지막, IOD 없음)                    │
 &amp;larr;────────────────────────────────────&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매치마다 &lt;code&gt;Status=0xFF00 (pending)&lt;/code&gt; + IOD 1개&lt;/li&gt;
&lt;li&gt;마지막에 &lt;code&gt;Status=0x0000 (success)&lt;/code&gt; + IOD 없음&lt;/li&gt;
&lt;li&gt;매치 0건이면 첫 응답이 곧장 success&lt;/li&gt;
&lt;li&gt;에러 시 다른 Status 코드&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.7 C-Cancel &amp;mdash; 검색 중단&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너무 광범위한 쿼리(e.g., wildcard도 안 주고 검색)는 영원히 안 끝남.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;C-Cancel-Find&lt;/code&gt; (Command = &lt;code&gt;0x0FFF&lt;/code&gt;) 로 중단&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(0000, 0120)&lt;/code&gt; 에 중단할 메시지 ID 적음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;PACS 모듈 개발 시&lt;/b&gt;: Find 함수에는 &lt;b&gt;timeout + max_results 가드&lt;/b&gt; 필수. 50,000개 결과 받다가 메모리 터지는 사고 흔함.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.8 C-Find 에러 흔한 원인&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;AE 미등록&lt;/b&gt; &amp;mdash; SCU AET가 SCP 화이트리스트에 없음 (제일 흔함)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Hierarchical 규칙 위반&lt;/b&gt; &amp;mdash; Series 검색하면서 Study UID 안 줌&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Query Root 미스매치&lt;/b&gt; &amp;mdash; Study Root만 지원하는데 Patient Root SOP로 요청&lt;/li&gt;
&lt;li&gt;&lt;b&gt;C-Find SCP 미지원&lt;/b&gt; &amp;mdash; 일부 modality는 C-Store SCU만 함 (Find 안 받음)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. AI 추론 앱 관점 &amp;mdash; 실전 시나리오&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9.1 시나리오: 추론 큐 처리&lt;/h3&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;1. 의사가 PACS UI에서 &quot;AI 분석&quot; 버튼 클릭
   &amp;rarr; PACS가 AI 추론 앱으로 C-Store (MR 시리즈)

2. AI 추론 앱 (= C-Store SCP) 영상 수신
   &amp;rarr; 로컬 디스크 저장 &amp;rarr; AI 모델 추론 시작

3. 추론 완료 &amp;rarr; Secondary Capture IOD 생성
   - Patient ID: 원본 유지
   - Study UID: 원본 유지       &amp;larr; 같은 검사 하위로 묶이게
   - Series UID: 새로 생성
   - SOP Class UID: 1.2.840.10008.5.1.4.1.1.7 (SC)

4. AI 추론 앱 (= C-Store SCU)
   &amp;rarr; PACS로 C-Store
   &amp;rarr; PACS UI에서 원본 옆에 &quot;AI 결과&quot; 시리즈로 보임&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9.2 시나리오: AI 추론 앱이 직접 PACS 쿼리&lt;/h3&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;1. AI 추론 앱 UI에서 환자 검색
   &amp;rarr; PACS로 C-Find (Study Root)
   - Query Level: STUDY
   - Patient ID: &quot;12345&quot;
   - Modality: &quot;MR&quot;
   - Study Date: &quot;20260601-&quot;

2. PACS가 C-Find-Rsp 여러 번 응답
   &amp;rarr; AI 추론 앱 UI에 Study 목록 표시

3. 사용자가 특정 Study 선택
   &amp;rarr; PACS로 C-Move (5편에서)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9.3 Orthanc 사용 시 추상화 레벨&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Orthanc를 쓰면 위 작업이 &lt;b&gt;HTTP REST 호출&lt;/b&gt;로 간략화:&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;# C-Find (Study Root) &amp;rarr; REST
import requests

r = requests.post(
    &quot;http://orthanc:8042/modalities/PACS/query&quot;,
    json={&quot;Level&quot;: &quot;Study&quot;,
          &quot;Query&quot;: {&quot;PatientID&quot;: &quot;12345&quot;,
                    &quot;ModalitiesInStudy&quot;: &quot;MR&quot;}}
)
query_id = r.json()[&quot;ID&quot;]

# 결과 조회
studies = requests.get(
    f&quot;http://orthanc:8042/queries/{query_id}/answers&quot;
).json()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; Orthanc가 내부적으로 진짜 DICOM C-Find를 PACS에 보냄.&lt;br /&gt;&lt;b&gt;하지만 디버깅하려면 결국 위 표들을 알아야 한다.&lt;/b&gt; Orthanc 로그에 똑같이 나옴.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. 핵심 정리&amp;nbsp;&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;개념&lt;/th&gt;
&lt;th&gt;한 줄&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;AE&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;DICOM 애플리케이션 (&amp;ne; 컴퓨터). AET + IP + Port 3종 세트로 식별&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;SCU/SCP&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;클라이언트/서버. 한 AE가 양쪽 다 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DIMSE&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;DICOM 응용 메시지 프로토콜. Command + (옵션) Data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DIMSE-C / DIMSE-N&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Composite IOD용 / Normalized IOD용. 거의 다 C 씀&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Rq / Rsp&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;요청/응답. Message ID로 짝맞춤. Rsp는 Command Field &lt;code&gt;0x8___&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;C-Echo&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;DICOM ping. 연결 확인. 데이터 없음. 디버깅의 시작&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;SOP&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;DIMSE + IOD 묶음. 각 SOP는 고유 UID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;C-Store&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;영상 저장. IOD 종류마다 다른 SOP Class UID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;C-Find&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;영상 검색. Study Root (&lt;code&gt;...2.2.1&lt;/code&gt;) 가 표준&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Query Level&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;PATIENT / STUDY / SERIES / IMAGE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;매칭 방식&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Wildcard, List, Universal, Range&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Multi-response&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;C-Find는 매치마다 응답. 마지막은 Status=&lt;code&gt;0x0000&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. 다음 글에서 다룰 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C-Find로 &lt;b&gt;&quot;무엇이 있는지&quot;&lt;/b&gt; 알아냈으니, 이제 &lt;b&gt;실제로 가져와야&lt;/b&gt; 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5편: C-Move, C-Get, Modality Worklist&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;C-Move&lt;/b&gt; &amp;mdash; 가장 흔한 영상 가져오기 (C-Store를 trigger)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;C-Get&lt;/b&gt; &amp;mdash; 직접 가져오기 (덜 쓰이지만 단순함)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;C-Move vs C-Get&lt;/b&gt; 비교&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Modality Worklist (MWL)&lt;/b&gt; &amp;mdash; RIS에서 환자 일정 받기&lt;/li&gt;
&lt;li&gt;AI 추론 앱 영상 수신 파이프라인 완성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지가 &lt;b&gt;DICOM 통신 서비스의 본진&lt;/b&gt;. 6편 Association이 그 통신을 떠받치는 인프라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pianykh, O.S. &lt;i&gt;Digital Imaging and Communications in Medicine (DICOM)&lt;/i&gt;. Springer, 2008.&lt;/li&gt;
&lt;li&gt;공식 표준 매핑:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;PS3.4&lt;/b&gt; (Service Class Specifications) &amp;mdash; Verification, Storage, Q/R 정의&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PS3.7&lt;/b&gt; (Message Exchange) &amp;mdash; DIMSE 메시지 구조, Command Field 코드&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;라이브러리:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Python: &lt;b&gt;pynetdicom&lt;/b&gt; (DICOM 네트워크), &lt;b&gt;pydicom&lt;/b&gt; (DICOM 파일)&lt;/li&gt;
&lt;li&gt;구현 시 거의 표준&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Orthanc 관련:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://orthanc.uclouvain.be/book/users/rest.html&quot;&gt;https://orthanc.uclouvain.be/book/users/rest.html&lt;/a&gt; (REST API 매핑)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Dev/DICOM</category>
      <category>dicom</category>
      <category>개발</category>
      <category>네트워크통신</category>
      <category>의료데이터</category>
      <author>odod00</author>
      <guid isPermaLink="true">https://chaechae0.tistory.com/43</guid>
      <comments>https://chaechae0.tistory.com/43#entry43comment</comments>
      <pubDate>Wed, 10 Jun 2026 13:40:03 +0900</pubDate>
    </item>
    <item>
      <title>[DICOM] Patient/Study/Series/Image 4계층 + IOD &amp;mdash; DICOM 정보 모델의 완성</title>
      <link>https://chaechae0.tistory.com/42</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oleg Pianykh, Digital Imaging and Communications in Medicine (DICOM) (Springer, 2008) 정리 3편&lt;br /&gt;참고 챕터: Ch 5.6 &amp;ndash; 5.7&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Patient-Study-Series-Image &amp;mdash; DICOM의 4계층 정보 모델&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM은 모든 영상 데이터를 &lt;b&gt;4단계 계층&lt;/b&gt;으로 조직한다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;Patient (환자)
  └── Study (검사) &amp;mdash; 1명에게 여러 검사 가능
       └── Series (시리즈) &amp;mdash; 1검사에 여러 시리즈
            └── Image (영상) &amp;mdash; 1시리즈에 여러 영상 (= Instance)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.1 실제 임상 워크플로우 매핑&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;  환자 John Smith (Patient)
   │
   ├──   2026-05-26 검사 (Study 1)
   │    ├──   MR T2W axial (Series 1)
   │    │    ├── slice 1
   │    │    ├── slice 2
   │    │    └── ... slice 30
   │    ├──   MR DWI (Series 2)
   │    └──   MR ADC (Series 3)
   │
   └──   2026-08-15 추적검사 (Study 2)
        └──   MR T2W axial (Series 1)
             └── ...&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;1 환자&lt;/b&gt; &amp;rarr; 평생 동안 여러 번 병원 옴 (Study가 쌓임)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;1 검사&lt;/b&gt; &amp;rarr; 한 번의 방문에서 여러 modality, 여러 sequence를 찍을 수 있음 (Series로 나뉨)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;1 시리즈&lt;/b&gt; &amp;rarr; 같은 protocol로 찍은 영상 묶음 (slice들이 Image로)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.2 각 계층의 식별자&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;계층&lt;/th&gt;
&lt;th&gt;식별자&lt;/th&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;VR&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Patient&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Patient ID&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(0010, 0020)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LO&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Study&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Study Instance UID&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(0020, 000D)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Series&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Series Instance UID&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(0020, 000E)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image&lt;/td&gt;
&lt;td&gt;&lt;b&gt;SOP Instance UID&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(0008, 0018)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  Patient ID만 &lt;code&gt;LO&lt;/code&gt;(Long String)이고 나머지는 다 &lt;code&gt;UI&lt;/code&gt;(globally unique identifier). 왜? Patient ID는 사람이 손으로 입력하기 때문에 자유 형식이 필요. 나머지는 장비가 자동 생성하니까 엄격한 UID 형식 사용.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.3 핵심 규칙&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;같은 UID = 같은 객체&lt;/b&gt;&lt;br /&gt;Study UID가 같으면 같은 검사. Series UID가 같으면 같은 시리즈.&lt;br /&gt;&lt;span style=&quot;color: #666666; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;이게 깨지면 PACS가 데이터를 못 묶음.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Patient ID의 현실적 문제들 ★&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름 대신 Patient ID를 쓰는 이유는 명확하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이름은 오타 가능 (&lt;code&gt;John Smith&lt;/code&gt; vs &lt;code&gt;Jhon Smith&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;결혼/개명으로 바뀜&lt;/li&gt;
&lt;li&gt;영문 시스템에 한글/일본어 입력 어려움&lt;/li&gt;
&lt;li&gt;프라이버시 위반&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 Patient ID에도 문제가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 표준화 부재&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전 세계 통일 Patient ID 체계가 없다.&lt;/b&gt; 각 병원이 자기 정책으로 부여:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사회보장번호 사용 (재방문 시 일관)&lt;/li&gt;
&lt;li&gt;단순 일련번호 (이 병원에서만 유효)&lt;/li&gt;
&lt;li&gt;환자 이름 자체를 ID로 사용 (의미 없음)&lt;/li&gt;
&lt;li&gt;검사 종류/판독의에 따라 &lt;code&gt;123.ForDrSmith&lt;/code&gt;, &lt;code&gt;123.Followup&lt;/code&gt; 등으로 변형&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 실제 사고 사례&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자가 경험한 케이스들:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Case 1: &quot;W/I&quot; 환자&lt;/b&gt;&lt;br /&gt;한 병원이 ID 없는 환자를 모두 &lt;code&gt;&quot;W/I&quot;&lt;/code&gt; (Without ID)로 등록 &amp;rarr; &lt;b&gt;DICOM은 다 같은 환자로 봄&lt;/b&gt; &amp;rarr; 수백 명이 한 명으로 merge.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Case 2: 3자리 ID 한계&lt;/b&gt;&lt;br /&gt;ID를 3자리(&lt;code&gt;000&amp;ndash;999&lt;/code&gt;)로만 부여하던 영상센터 &amp;rarr; 1000명 넘어가니 ID 재사용 &amp;rarr; 서로 다른 환자가 merge.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Case 3: 쌍둥이 자매&lt;/b&gt;&lt;br /&gt;같은 의사에게 같은 발목 문제로 동시 방문. 성이 20자 길이 한국식 풀네임이라 first name이 잘림. 의사도 누구 영상인지 구분 불가.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3 PACS의 방어 로직&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 PACS는 &lt;b&gt;Patient ID 하나만 믿지 않는다.&lt;/b&gt; 추가 검증 로직:&lt;/p&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;# 의사코드
def is_same_patient(record_a, record_b):
    if record_a.patient_id == record_b.patient_id:
        # ID 같다고 끝이 아니라 cross-check
        if (record_a.name == record_b.name and
            record_a.birth_date == record_b.birth_date and
            record_a.sex == record_b.sex):
            return True
        else:
            flag_for_human_review()  # 같은 ID인데 다른 사람?

    # ID 다르지만 다른 정보 일치 시
    if (record_a.name == record_b.name and
        record_a.birth_date == record_b.birth_date):
        suggest_merge()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;patient merge / split&lt;/b&gt; 기능이 모든 PACS의 필수.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;자동 merge/split은 금지.&lt;/b&gt; 사람이 확인해야 함. 잘못 merge하면 진단 정보 오염.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.4 AI 추론 앱 입장에서&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 추론 앱은 PACS에서 영상을 받아 처리할 때:&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;[PACS] ──C-Move──&amp;gt; [AI 앱] ──추론──&amp;gt; [Orthanc] ──C-Store──&amp;gt; [PACS]
                       │
                       └── Patient ID + Name + Birth Date 다 보고
                           &quot;동일 환자&quot; 검증 후 처리&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;받은 영상의 Patient ID만 믿지 말고 cross-check&lt;/li&gt;
&lt;li&gt;추론 결과를 PACS에 보낼 때 &lt;b&gt;원본 Study/Patient UID 그대로 유지&lt;/b&gt; (그래야 PACS가 같은 검사에 묶어줌)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Study/Series/Image UID의 문제들&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Patient ID와 달리 이 셋은 &lt;b&gt;장비가 자동 생성&lt;/b&gt;한다. 그래서 비교적 안정적이지만 함정도 있음.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 흔한 사고: Series UID 깨짐&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CT 한 시리즈가 2,000장인데, 어떤 기술적 이유로 각 슬라이스마다 &lt;b&gt;Series UID가 다르게 생성&lt;/b&gt;되는 경우 발생.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;❌ 잘못된 경우:
slice 1 &amp;rarr; Series UID: 1.2.3.4.1
slice 2 &amp;rarr; Series UID: 1.2.3.4.2   &amp;larr; 달라짐!
slice 3 &amp;rarr; Series UID: 1.2.3.4.3
...

&amp;rarr; PACS가 2,000개의 &quot;1장짜리 시리즈&quot;로 인식
&amp;rarr; 3D 재구성, 뷰어에서 슬라이스 묶음 안 됨&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결책은 거의 없음. &lt;b&gt;modality(장비) 쪽에서 고쳐야&lt;/b&gt; 한다. PACS는 Series UID만 보고 묶기 때문에 사후 복구가 어려움. &lt;br /&gt;(Patient ID와 달리 Series에는 merge 기능이 없는 경우가 많음)&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 UID는 인스턴스마다 달라야 한다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상을 &lt;b&gt;조금이라도 수정&lt;/b&gt;하면 (crop, rotate, lossy compression):&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;임상 정보는 같아 보여도&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SOP Instance UID 새로 부여 필요&lt;/b&gt; (2편 10.2 참조)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;원본:        SOP UID = ...1.1
JPEG 압축:   SOP UID = ...1.2  &amp;larr; 새 UID!
크롭됨:     SOP UID = ...1.3   &amp;larr; 또 새 UID!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PACS에 똑같이 생긴 영상이 두 개 따로 저장돼 있다면 &amp;rarr; 둘 중 하나가 수정본일 가능성.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3 Secondary Capture의 함정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필름을 스캔하거나 외부 영상을 DICOM으로 변환할 때:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디지타이저는 &quot;이 영상들이 같은 환자/검사/시리즈인지&quot; 모름&lt;/li&gt;
&lt;li&gt;사용자가 &lt;b&gt;수동으로 Study/Series UID 부여&lt;/b&gt; 해야 함&lt;/li&gt;
&lt;li&gt;&amp;rarr; 이 기능이 부실한 SC 장비를 사면 영상이 다 흩어짐&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 추론 앱이 secondary capture(추론 결과 영상)를 만들 때도 같은 문제.&lt;b&gt; 원본 Study UID를 유지하고, Series UID는 새로 생성&lt;/b&gt;해야 같은 검사 하위에 묶임.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Hierarchical vs Relational Query&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM은 데이터 조회 방식을 두 가지 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1 Hierarchical Query (계층적, 필수)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서부터 차근차근 내려가야 한다.&lt;/p&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;&quot;John Smith의 지난달 CT 영상 찾기&quot;

1. Patient Level:  Patient Name=&quot;Smith*&quot; &amp;rarr; Patient ID 획득
2. Study Level:    그 Patient ID + StudyDate=last month &amp;rarr; Study UID 획득
3. Series Level:   그 Study UID + Modality=&quot;CT&quot; &amp;rarr; Series UID 획득
4. Image Level:    그 Series UID &amp;rarr; Image UID 목록&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모든 DICOM 장비 필수 지원.&lt;/b&gt; 간단하고 효율적이지만 4번 왕복.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2 Relational Query (관계형, 선택)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상위 정보 없이 바로 검색:&lt;/p&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;&quot;Modality=CT AND Date=last month AND Series Description='axial'&quot;
&amp;rarr; 바로 매칭되는 Series UID 반환&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB의 WHERE 절처럼 자유롭게 조건 조합. 한 번에 끝.&lt;/p&gt;
&lt;table style=&quot;height: 95px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;th style=&quot;height: 19px;&quot;&gt;&amp;nbsp;&lt;/th&gt;
&lt;th style=&quot;height: 19px;&quot;&gt;Hierarchical&lt;/th&gt;
&lt;th style=&quot;height: 19px;&quot;&gt;Relational&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;지원&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;b&gt;필수 (Mandatory)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;옵션 (Optional)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;쿼리 단계&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;4단계&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;1단계&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;효율&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;단순함&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;유연함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;Conformance Statement&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;항상 있음&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;명시되어야 함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;PACS 모듈 개발 시&lt;/b&gt;: PACS 벤더의 Conformance Statement에서 &lt;b&gt;&quot;Relational Query 지원하는지&quot;&lt;/b&gt; 꼭 확인. 지원 안 하면 무조건 hierarchical로 짜야 함.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. Module, Information Entity, IOD &amp;mdash; 데이터 조직화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2,000개의 데이터 element를 그냥 막 쓸 수는 없다. 의미 있는 단위로 묶어야 함. DICOM은 3계층 조직화를 정의:&lt;/p&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;┌─────────────────────────────────────────────┐
│  IOD (Information Object Definition)         │  &amp;larr; 가장 큰 단위
│  ┌─────────────────────────────────────────┐ │
│  │ IE (Information Entity)                  │ │  &amp;larr; 실세계 엔티티
│  │  ┌──────────────────────────────────┐    │ │
│  │  │ Module                            │   │ │  &amp;larr; 속성 묶음
│  │  │   ├─ Data Element                │   │ │
│  │  │   ├─ Data Element                │   │ │
│  │  │   └─ Data Element                │   │ │
│  │  └──────────────────────────────────┘    │ │
│  └─────────────────────────────────────────┘ │
└─────────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1 Macro Attributes &amp;mdash; &quot;함수처럼 재사용&quot;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 곳에서 똑같이 쓰이는 속성 묶음. 매번 풀어 쓰지 않고 &lt;b&gt;매크로처럼 참조&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: &quot;Referenced Series Sequence&quot; 매크로&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;(0008, 1115)  Referenced Series Sequence    SQ
   &amp;gt;(0020, 000E) Series Instance UID
   &amp;gt;(0008, 114A) Referenced Instance Sequence  SQ
      &amp;gt;&amp;gt;(0008, 1150) Referenced SOP Class UID
      &amp;gt;&amp;gt;(0008, 1155) Referenced SOP Instance UID&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;&amp;gt;&lt;/code&gt; 깊이로 중첩 표현. 다른 IOD에서 &quot;이 매크로 포함&quot; 한 줄로 가져올 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.2 Information Module &amp;mdash; 기본 빌딩 블록&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 속성을 묶은 단위. 약 &lt;b&gt;100개의 표준 모듈&lt;/b&gt; 존재.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시 1: Patient Identification Module&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;height: 145px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;th style=&quot;height: 19px;&quot;&gt;Attribute&lt;/th&gt;
&lt;th style=&quot;height: 19px;&quot;&gt;Tag&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Patient Name&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0010, 0010)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Patient ID&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0010, 0020)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Other Patient IDs&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0010, 1000)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Other Patient Names&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0010, 1001)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Patient's Birth Name&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0010, 1005)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Patient's Mother's Birth Name&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0010, 1060)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Medical Record Locator&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0010, 1090)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &quot;환자 식별과 관련된 모든 속성&quot;을 한 묶음으로.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시 2: Cine Module&lt;/b&gt; (동영상 재생용)&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attribute&lt;/th&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frame Time&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(0018, 1063)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;프레임 간 시간 (ms)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cine Rate&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(0018, 0040)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;FPS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Preferred Playback Sequencing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(0018, 1244)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Loop or Sweep&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Start Trim / Stop Trim&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(0008, 2142/2143)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;재생 시작/끝 프레임&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 초음파 cine loop 같은 multiframe 영상에서만 필요. CT/MR에는 없음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.3 Module의 사용 분류&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;코드&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;M&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Mandatory&lt;/b&gt; (필수)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;C&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Conditional (조건부 필수)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;U&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;User-defined (선택, 옵션)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; Modality(영상 종류)마다 어떤 Module이 M/C/U인지 정의.&lt;br /&gt;예: Patient Identification Module은 &lt;b&gt;모든 modality에서 M&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.4 ⚠️ Module은 정규화돼 있지 않다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB 설계자라면 놀랄 부분: &lt;b&gt;여러 모듈이 같은 attribute를 중복으로 포함&lt;/b&gt;한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;Patient Name (0010,0010)&lt;/code&gt; 이 Patient Module, Patient Identification Module 등 여러 곳에 등장&lt;/li&gt;
&lt;li&gt;Cine Module 안에 Frame Time과 Cine Rate가 둘 다 있음 (&lt;code&gt;Cine Rate = 1000 / Frame Time&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 좋은 설계는 아니지만, 표준이 25년에 걸쳐 진화하면서 누적된 결과.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #666666;&quot;&gt;  &lt;b&gt;DICOM 개발자 조언 (저자 인용)&lt;/b&gt;:&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #666666;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&quot;DICOM 모듈을 기본 데이터 빌딩 블록으로 사용하라. base Module 클래스를 만들고, 각 모듈마다 자식 클래스로 확장. 객체지향의 힘을 활용하면 코드가 깔끔해진다.&quot;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;대부분의 DICOM 소프트웨어가 모듈 무시하고 element 직접 다루다가 버그 양산 중.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. Information Entity (IE) &amp;mdash; 실세계 엔티티&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Module이 &quot;속성 묶음&quot;이라면, &lt;b&gt;IE는 실세계 엔티티(객체)&lt;/b&gt; 다.&lt;/p&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;Common Patient IE     =  Patient Module
                         + Specimen Identification Module
                         + Clinical Trial Subject Module

Common Study IE       =  General Study Module
                         + Patient Study Module
                         + Clinical Trial Study Module&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.1 DICOM의 IE들 (약 20개)&lt;/h3&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;Patient ─── Study ─── Series ─── Image
                   │            │
                   │            ├── Waveform (음성/심전도)
                   │            ├── SR Document (구조화 리포트)
                   │            └── Presentation State
                   │
                   ├── Frame of Reference (3D 좌표계)
                   └── Equipment (장비 정보)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 박스가 IE. 이 모델이 바로 DICOM의 &quot;세계관&quot;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.2 4계층 vs IE&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5.1에서 본 Patient/Study/Series/Image 4계층은 &lt;b&gt;IE 중 핵심 4개의 hierarchy&lt;/b&gt;. 실제로는 더 많은 IE가 존재 (Waveform, SR, Frame of Reference 등).&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. IOD (Information Object Definition) &amp;mdash; 최종 객체&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 IE를 모아 &lt;b&gt;실제 DICOM 객체 타입&lt;/b&gt;을 정의한 것이 IOD.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.1 CT Image IOD 분해 예시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CT 영상 하나를 만들기 위해 필요한 IE + Module 조합:&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;IE&lt;/th&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;Usage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Patient&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Patient&lt;/td&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;Clinical Trial Subject&lt;/td&gt;
&lt;td&gt;U&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Study&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;General Study&lt;/td&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;Patient Study&lt;/td&gt;
&lt;td&gt;U&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;Clinical Trial Study&lt;/td&gt;
&lt;td&gt;U&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Series&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;General Series&lt;/td&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;Clinical Trial Series&lt;/td&gt;
&lt;td&gt;U&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Frame of Reference&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Frame of Reference&lt;/td&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Equipment&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;General Equipment&lt;/td&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Image&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;General Image&lt;/td&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;Image Plane&lt;/td&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;Image Pixel&lt;/td&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;Contrast/Bolus&lt;/td&gt;
&lt;td&gt;C (조영제 사용 시)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;CT Image&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;Overlay Plane&lt;/td&gt;
&lt;td&gt;U&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;VOI LUT&lt;/td&gt;
&lt;td&gt;U&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;SOP Common&lt;/td&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 이 모든 모듈을 합쳐서 &lt;b&gt;하나의 CT Image IOD&lt;/b&gt; 완성.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MR Image IOD는 이 중 &lt;code&gt;CT Image&lt;/code&gt; 모듈만 &lt;code&gt;MR Image&lt;/code&gt; 모듈로 교체하면 거의 됨. NM(핵의학)은 multiframe 등 더 많이 바꿔야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.2 Normalized vs Composite IOD&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM은 IOD를 두 종류로 분류.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Normalized IOD&lt;/b&gt;: 단일 실세계 엔티티만 표현&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: Study IOD &amp;rarr; Study 고유 속성(검사 날짜, 시간 등)만&lt;/li&gt;
&lt;li&gt;&quot;그 Study의 환자 이름&quot;은 포함 안 함 (그건 Patient의 속성)&lt;/li&gt;
&lt;li&gt;DB 정규화 개념과 같음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Composite IOD&lt;/b&gt;: 여러 엔티티를 섞어 통합&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: CT Image IOD &amp;rarr; 환자 정보 + Study 정보 + 장비 정보 + 영상 자체&lt;/li&gt;
&lt;li&gt;한 객체 안에 다 들어있어서 자기 완결적&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DICOM 영상 객체는 거의 다 Composite&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;[Composite CT Image IOD]
├── Patient 정보 (Name, ID, Birth Date)
├── Study 정보 (Study UID, Date, Description)
├── Series 정보 (Series UID, Modality)
├── Equipment 정보 (제조사, 모델)
├── Image 정보 (Rows, Columns, Pixel Spacing)
└── Pixel Data &amp;larr; 실제 영상&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 그래서 CT 영상 한 장(.dcm 파일 하나)에 환자 이름까지 다 들어있는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.3 IOD &amp;harr; Class / Instance 관계&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;IOD            =  추상 클래스 (e.g., &quot;CT Image 타입&quot;)
DICOM Object   =  그 클래스의 인스턴스 (실제 영상 데이터)
SOP Class UID  =  어떤 IOD 타입인지 가리키는 UID
SOP Instance UID = 그 인스턴스의 UID (= Image UID와 동일)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향 비유&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;class CTImageIOD:           # IOD = Class
    patient_name: str
    study_uid: str
    pixel_data: bytes
    # ... 약 50~100개 속성

my_image = CTImageIOD()     # DICOM Object = Instance
my_image.patient_name = &quot;Smith^John&quot;
my_image.pixel_data = b&quot;...&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;2편에서 본 &quot;DICOM Object&quot;는 사실 모두 IOD의 instance.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.4 SOP Class UID로 IOD 식별&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM 영상마다 &lt;code&gt;(0008, 0016) SOP Class UID&lt;/code&gt; 가 있어서 &quot;이게 어떤 IOD인지&quot; 알려준다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SOP Class UID&lt;/th&gt;
&lt;th&gt;IOD&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CT Image Storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;MR Image Storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.6.1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;US Image Storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.88.22&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enhanced SR Storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1.2.840.10008.5.1.4.1.1.7&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Secondary Capture Image Storage&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; AI 추론 앱이 추론 결과를 PACS에 보낼 때, &lt;b&gt;올바른 SOP Class UID를 선택&lt;/b&gt;해야 함. CT 결과를 &lt;code&gt;MR Image Storage&lt;/code&gt;로 보내면 PACS가 reject.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 전체 그림 &amp;mdash; 모든 개념의 연결&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────┐
│              DICOM Information Model                    │
└─────────────────────────────────────────────────────────┘

    Data Dictionary (2,000+ 표준 attribute)
        │
        ▼
    Module (관련 attribute 100여 묶음)
        │
        ▼
    Information Entity (Patient, Study, Series, Image, ...)
        │
        ▼
    IOD (CT Image, MR Image, SR, ...)
        │  (추상 Class)
        ▼
    DICOM Object = IOD Instance
        │
        ▼
    DICOM File (.dcm) &amp;larr; 디스크에 저장됨
        OR
    DICOM Network &amp;larr; Association으로 전송됨

┌─────────────────────────────────────────────────────────┐
│  계층 구조 (조회 시 사용)                                  │
│  Patient ID &amp;rarr; Study UID &amp;rarr; Series UID &amp;rarr; SOP Instance UID │
└─────────────────────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. AI 추론 앱 관점에서의 정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 추론 앱이 PACS와 상호작용하는 시나리오 정리&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9.1 영상 수신 (PACS &amp;rarr; AI 앱)&lt;/h3&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;PACS                                AI 앱
 │                                   │
 │  ① C-Find: Modality=MR            │
 │     &amp;larr;──────────────────────────── │
 │  ② Study UID 목록 응답              │
 │  ──────────────────────────────&amp;rarr;  │
 │  ③ C-Move: Study UID 지정          │
 │     &amp;larr;──────────────────────────── │
 │  ④ C-Store: 영상 전송 (Composite IOD)│
 │  ──────────────────────────────&amp;rarr;  │
                                        │
                                        ▼
                          [Orthanc 또는 로컬 디스크]
                          Patient/Study/Series 계층으로 저장
                          &amp;rarr; SOP Class UID 확인
                          &amp;rarr; Pixel Data 추출 &amp;rarr;  입력&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9.2 추론 결과 전송 (AI 앱 &amp;rarr; PACS)&lt;/h3&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;   결과
    │
    ▼
[Secondary Capture IOD 또는 SR IOD 생성]
    │
    ├─ Patient ID: 원본과 동일 ✅
    ├─ Study UID: 원본과 동일 ✅      &amp;larr; 같은 검사 하위로 묶이게
    ├─ Series UID: 새로 생성 ✅       &amp;larr; 별도 시리즈로 구분
    ├─ SOP Instance UID: 새로 생성 ✅
    └─ SOP Class UID: 1.2.840.10008.5.1.4.1.1.7 (SC) 또는 SR
    │
    ▼
C-Store &amp;rarr; PACS&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심 원칙&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;상위 식별자(Patient, Study)는 절대 바꾸지 말 것&lt;/b&gt; &amp;rarr; 안 그러면 같은 검사로 묶이지 않음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Series/Image UID는 새로 생성&lt;/b&gt; &amp;rarr; 원본과 구분&lt;/li&gt;
&lt;li&gt;그래야 PACS 뷰어에서 환자 검사 펼쳐보면 &quot;원본 시리즈들 + AI 결과 시리즈&quot; 가 같이 보임&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. 핵심 정리&amp;nbsp;&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;개념&lt;/th&gt;
&lt;th&gt;한 줄&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;4계층&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Patient &amp;rarr; Study &amp;rarr; Series &amp;rarr; Image. 모든 PACS 데이터의 뼈대&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Patient ID&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;표준화 안 됨. 병원/장비마다 천차만별. &lt;b&gt;Cross-check 필수&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Study/Series/Image UID&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;장비 자동 생성. globally unique. 한번 부여되면 불변&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Hierarchical Query&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;4단계로 내려가는 필수 쿼리 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Relational Query&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;DB WHERE처럼 자유 쿼리. 옵션&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Module&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;관련 attribute 묶음 (약 100개). M/C/U 분류&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Information Entity (IE)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;실세계 엔티티 (Patient, Study, Image 등). 약 20개&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;IOD&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;여러 IE를 조합한 최종 객체 타입 (= 추상 Class)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;DICOM Object&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;IOD의 instance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Normalized IOD&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;단일 엔티티만 (정규화)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Composite IOD&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;여러 엔티티 통합. &lt;b&gt;영상 IOD는 대부분 이것&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;SOP Class UID&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&quot;이게 어떤 IOD인지&quot; 알려주는 UID&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. 다음 글에서 다룰 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4편: DICOM SOP &amp;mdash; C-Echo, C-Store, C-Find&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AE Title (Application Entity Title) &amp;mdash; PACS 등록 시 필수&lt;/li&gt;
&lt;li&gt;DIMSE (DICOM Message Service Elements)&lt;/li&gt;
&lt;li&gt;Service-Object Pair (SOP) 의 정확한 의미&lt;/li&gt;
&lt;li&gt;C-Echo &amp;mdash; 연결 테스트&lt;/li&gt;
&lt;li&gt;C-Store &amp;mdash; 영상 저장&lt;/li&gt;
&lt;li&gt;C-Find &amp;mdash; 쿼리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pianykh, O.S. &lt;i&gt;Digital Imaging and Communications in Medicine (DICOM)&lt;/i&gt;. Springer, 2008.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Dev/DICOM</category>
      <author>odod00</author>
      <guid isPermaLink="true">https://chaechae0.tistory.com/42</guid>
      <comments>https://chaechae0.tistory.com/42#entry42comment</comments>
      <pubDate>Tue, 2 Jun 2026 17:23:51 +0900</pubDate>
    </item>
    <item>
      <title>[DICOM] Tag, Data Dictionary, Object Encoding &amp;mdash; DICOM 데이터를 바이트로 푸는 법</title>
      <link>https://chaechae0.tistory.com/41</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oleg Pianykh, Digital Imaging and Communications in Medicine (DICOM) (Springer, 2008) 정리 2편&lt;br /&gt;참고 챕터: Ch 5.4 &amp;ndash; 5.5&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글에서는 &lt;b&gt;&quot;데이터가 무엇을 의미하는지&quot;&lt;/b&gt; 를 알려주는 &lt;b&gt;Tag&lt;/b&gt;와 &lt;b&gt;Data Dictionary&lt;/b&gt;, 그리고 &lt;b&gt;실제 바이트로 어떻게 직렬화되는지&lt;/b&gt; 까지 본다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Tag &amp;mdash; DICOM의 &quot;주소&quot;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM의 모든 데이터 요소(element)는 &lt;b&gt;16진수 4자리 두 개&lt;/b&gt;로 식별된다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;(0010, 0020)
  &amp;uarr;      &amp;uarr;
 Group  Element&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Group (2 byte)&lt;/b&gt;: 비슷한 속성들의 묶음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Element (2 byte)&lt;/b&gt;: 그 그룹 안에서 개별 항목&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;(0010, 0010)&lt;/code&gt; = Patient Name (환자 이름)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(0010, 0020)&lt;/code&gt; = Patient ID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(0008, 0060)&lt;/code&gt; = Modality (CT, MR ...)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(7FE0, 0010)&lt;/code&gt; = Pixel Data (실제 이미지)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;그룹은 주제별로 묶임&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Group&lt;/th&gt;
&lt;th&gt;주제&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0008&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SOP Common, 검사 식별 정보&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0010&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Patient&lt;/b&gt; (환자)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0018&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Acquisition (촬영 파라미터)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0020&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Image (인스턴스/슬라이스 위치 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0028&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Image Pixel (가로/세로/비트 깊이)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;7FE0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Pixel Data&lt;/b&gt; (픽셀 데이터)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;✅&lt;/span&gt; 짝수 group = 표준 / ❌ 홀수 group = Private(제조사 독자)&lt;br /&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;&amp;rarr; 그래서 GE 장비에서 &lt;/span&gt;&lt;code style=&quot;letter-spacing: 0px;&quot;&gt;(0009, ...)&lt;/code&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt; 같은 odd-group이 나오면, &quot;아, GE 사설 태그구나&quot; 알 수 있음.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Data Dictionary &amp;mdash; DICOM의 &quot;사전&quot;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DICOM Data Dictionary&lt;/b&gt;는 약 &lt;b&gt;2,000개 이상의 표준 속성&lt;/b&gt;을 모은 사전.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;height: 126px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;th style=&quot;height: 18px;&quot;&gt;(Group, Element)&lt;/th&gt;
&lt;th style=&quot;height: 18px;&quot;&gt;Attribute Name&lt;/th&gt;
&lt;th style=&quot;height: 18px;&quot;&gt;VR&lt;/th&gt;
&lt;th style=&quot;height: 18px;&quot;&gt;VM&lt;/th&gt;
&lt;th style=&quot;height: 18px;&quot;&gt;Retired&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0008, 0005)&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Specific Character Set&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;CS&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;1-n&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0010, 0010)&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Patient Name&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;PN&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0010, 0020)&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Patient ID&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;LO&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0010, 0030)&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Patient's Birth Date&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;DA&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0010, 0040)&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Patient's Sex&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;CS&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;(0010, 1001)&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Other Patient Names&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;PN&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;1-n&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 항목은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Tag&lt;/b&gt;: 식별자&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Attribute Name&lt;/b&gt;: 사람이 읽는 이름&lt;/li&gt;
&lt;li&gt;&lt;b&gt;VR&lt;/b&gt;: 값의 형식 (1편 참조)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;VM (Value Multiplicity)&lt;/b&gt;: 값 개수 (&lt;code&gt;1&lt;/code&gt;, &lt;code&gt;1-n&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3-5&lt;/code&gt; 등)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;RET&lt;/b&gt;: 폐기된 속성 표시&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&quot;DICOM 문장&quot; 만들어보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;환자 John Smith, 남자, 1954년 8월 6일 출생&quot; 을 DICOM 표현으로 옮기면,&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;(0010,0010) Smith^John          &amp;larr; PN
(0010,0030) 19540806            &amp;larr; DA
(0010,0040) M                   &amp;larr; CS&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 바로 DICOM이 데이터를 인코딩하는 방식. 단순한 (tag, value) 쌍의 나열이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;VM (Value Multiplicity) &amp;mdash; 한 속성에 여러 값&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VM이 &lt;code&gt;1-n&lt;/code&gt;인 경우 여러 값을 &lt;b&gt;백슬래시(&lt;code&gt;\&lt;/code&gt;)&lt;/b&gt; 로 구분해서 한 필드에 넣는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: 환자의 가명이 둘이면&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;(0010,1001) Dr^Jekyll\Mr^Hide   &amp;larr; VM=2&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1편에서 본 와일드카드 &lt;code&gt;\&lt;/code&gt; = OR이 여기 다시 등장. &lt;code&gt;\&lt;/code&gt;는 무조건 구분자 역할이라 파일명&amp;middot;텍스트에 쓰면 안 됨.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;VM (Value Multiplicity) 표기법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VM은 한 데이터 요소에 들어갈 수 있는 값의 개수를 나타내. 의료 데이터는 종류에 따라 값 개수가 천차만별이라 단순히 &quot;1개&quot; 가 아니라 다양한 패턴을 표현해야 함.&lt;/p&gt;
&lt;pre id=&quot;code_1779868606094&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  ┌──────┬─────────────────────────────────┬─────────────────────────────────────────────────────┐
  │  VM  │              의미               │                        예시                         │
  ├──────┼─────────────────────────────────┼─────────────────────────────────────────────────────┤
  │ 1    │ 정확히 1개 (가장 흔함)           │ Patient Name                                        │
  ├──────┼─────────────────────────────────┼─────────────────────────────────────────────────────┤
  │ 2    │ 정확히 2개                       │ Patient Orientation (row, column)                   │
  ├──────┼─────────────────────────────────┼─────────────────────────────────────────────────────┤
  │ 3    │ 정확히 3개                       │ Image Position (x, y, z 좌표)                       │
  ├──────┼─────────────────────────────────┼─────────────────────────────────────────────────────┤
  │ 6    │ 정확히 6개                       │ Image Orientation (row vector 3개 + col vector 3개) │
  ├──────┼─────────────────────────────────┼─────────────────────────────────────────────────────┤
  │ 1-n  │ 1개 이상 무제한                  │ Other Patient Names                                 │
  ├──────┼─────────────────────────────────┼─────────────────────────────────────────────────────┤
  │ 0-n  │ 0개 이상 무제한 (있어도 없어도)   │ 보통 retired 속성                                   │
  ├──────┼─────────────────────────────────┼─────────────────────────────────────────────────────┤
  │ 1-2  │ 1개 또는 2개                     │ (드물게 사용)                                       │
  ├──────┼─────────────────────────────────┼─────────────────────────────────────────────────────┤
  │ 2-n  │ 2개 이상 무제한                  │                                                     │
  ├──────┼─────────────────────────────────┼─────────────────────────────────────────────────────┤
  │ 3-3n │ 3의 배수만 (3, 6, 9, 12 ...)     │ 여러 3D 좌표 묶음                                   │
  ├──────┼─────────────────────────────────┼─────────────────────────────────────────────────────┤
  │ 2-2n │ 2의 배수만 (2, 4, 6 ...)         │ 여러 쌍 데이터                                      │
  └──────┴─────────────────────────────────┴─────────────────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Private Data Dictionary (제조사 사설 사전)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표준 2,000개로 부족할 때 제조사는 자기 &lt;b&gt;odd group&lt;/b&gt;에 사설 속성을 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: 우리가 환자 &quot;중간 이름&quot;을 추가하고 싶다면&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;(0009, 0010) Patient's Middle Name   PN   1   &amp;larr; 우리 사설 사전&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 다른 회사도 &lt;code&gt;(0009, 0010)&lt;/code&gt;을 다른 의미로 쓸 수 있다는 것. &amp;rarr; &lt;b&gt;사설 태그 충돌(private tag collision)&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM은 이를 막기 위해 &lt;b&gt;Private Creator Element&lt;/b&gt; 라는 메커니즘을 두지만, 실무에서는 여전히 PACS 호환성 문제의 단골손님.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;PACS 모듈 개발 시 명심&lt;/b&gt;: 알 수 없는 사설 태그를 받으면 &lt;b&gt;무조건 무시(skip)&lt;/b&gt;. 절대 추측해서 해석하지 말 것.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Command Dictionary &amp;mdash; DICOM의 &quot;명령어&quot;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Print&lt;/code&gt;, &lt;code&gt;Store&lt;/code&gt;, &lt;code&gt;Move&lt;/code&gt;, &lt;code&gt;Get&lt;/code&gt; 같은 &lt;b&gt;명령&lt;/b&gt;은 어디 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;Group &lt;code&gt;0000&lt;/code&gt;&lt;/b&gt; 이 명령 전용 그룹. Data Dictionary와 똑같은 형식이지만 명령용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;(0000, 0100)&lt;/code&gt; = Command Field (명령 타입)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(0000, 0110)&lt;/code&gt; = Message ID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(0000, 0800)&lt;/code&gt; = Command Data Set Type&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 명령들은 뒤에서 자세히 다룸.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Element Encoding &amp;mdash; 실제 바이트로 어떻게 쓰이나&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 이번 글의 핵심. DICOM은 두 가지 인코딩 방식이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1 Implicit VR Encoding (암묵적)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VR을 명시하지 않음. 받는 쪽이 Data Dictionary를 찾아봐서 알아내야 함.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;┌─────────┬──────────┬──────────┬──────────────┐
│  Group  │ Element  │  Length  │    Value     │
│ 2 bytes │ 2 bytes  │ 4 bytes  │  L bytes     │
└─────────┴──────────┴──────────┴──────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시&lt;/b&gt;: Patient Name = &lt;code&gt;&quot;Smith^Joe&quot;&lt;/code&gt; (9자 &amp;rarr; 짝수 맞추려 공백 패딩 &amp;rarr; 10자)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;height: 278px; width: 761px;&quot; width=&quot;827&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;th style=&quot;width: 82px; height: 18px;&quot;&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Byte#&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;width: 88px; height: 18px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;1&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;width: 35px; height: 18px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;width: 100px; height: 18px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;3&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;width: 74px; height: 18px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;4&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;width: 93px; height: 18px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;5&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;width: 132px; height: 18px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;6&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;width: 62px; height: 18px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;7&lt;/span&gt;&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;width: 41px; height: 18px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;8&lt;/span&gt;&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;width: 54px; height: 18px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;9&lt;/span&gt;&lt;/p&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 27px;&quot;&gt;
&lt;td style=&quot;width: 82px; height: 27px; text-align: center;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Hex&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 88px; height: 27px; text-align: center;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;code&gt;10&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 35px; height: 27px; text-align: center;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;code&gt;00&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 100px; height: 27px; text-align: center;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;code&gt;10&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 74px; height: 27px; text-align: center;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;code&gt;00&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 93px; height: 27px; text-align: center;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;code&gt;0A&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 132px; height: 27px; text-align: center;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;code&gt;00&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 62px; height: 27px; text-align: center;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;code&gt;00&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 41px; height: 27px; text-align: center;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;code&gt;00&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 54px; height: 27px; text-align: center;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;code&gt;53&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 70px;&quot;&gt;
&lt;td style=&quot;width: 82px; height: 70px; text-align: center;&quot;&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;의미&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 88px; height: 70px; text-align: center;&quot;&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Group &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;code&gt;0010&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 35px; height: 70px; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 100px; height: 70px; text-align: center;&quot;&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Element &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;code&gt;0010&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 74px; height: 70px; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 93px; height: 70px; text-align: center;&quot;&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Length &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;code&gt;0x0A&lt;/code&gt;=10&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 132px; height: 70px; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 62px; height: 70px; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 41px; height: 70px; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 54px; height: 70px; text-align: center;&quot;&gt;&lt;span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;code&gt;'S'&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 82px; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt; &lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333; text-align: center;&quot;&gt;9&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 88px; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;10&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 35px; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;11&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 100px; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;12&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 74px; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;13&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 93px; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;14&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 132px; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;15&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 62px; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;16&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 41px; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;17&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 54px; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;18&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 82px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;53&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 88px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;53&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 35px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;69&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 100px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;74&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 74px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;68&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 93px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;5E&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 132px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;4A&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 62px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;6F&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 41px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;65&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 54px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;20&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 82px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt; &lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;'S'&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 88px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt; &lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;'m'&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 35px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;'i'&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 100px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt; &lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;'t'&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 74px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;'h'&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 93px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt; &lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;'^'&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 132px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;'J'&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 62px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;'o'&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 41px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;' e'&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 54px; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;' '&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  Little Endian이라 group &lt;code&gt;0010&lt;/code&gt;이 메모리에는 &lt;code&gt;10 00&lt;/code&gt; 으로 거꾸로 쓰임. 헷갈리지 말 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2 Explicit VR Encoding (명시적) &amp;mdash; 일반 VR&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VR을 직접 같이 보냄.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;┌─────────┬──────────┬────┬────────┬──────────────┐
│  Group  │ Element  │ VR │ Length │    Value     │
│ 2 bytes │ 2 bytes  │ 2  │   2    │  L bytes     │
└─────────┴──────────┴────┴────────┴──────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시&lt;/b&gt;: 같은 &lt;code&gt;&quot;Smith^Joe &quot;&lt;/code&gt; 를 Explicit으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Byte#&lt;/th&gt;
&lt;th&gt;1&lt;/th&gt;
&lt;th&gt;2&lt;/th&gt;
&lt;th&gt;3&lt;/th&gt;
&lt;th&gt;4&lt;/th&gt;
&lt;th&gt;5&lt;/th&gt;
&lt;th&gt;6&lt;/th&gt;
&lt;th&gt;7&lt;/th&gt;
&lt;th&gt;8&lt;/th&gt;
&lt;th&gt;9~18&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hex&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;00&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;00&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;50&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;4E&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0A&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;00&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Smith^Joe&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;의미&lt;/td&gt;
&lt;td&gt;Group&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;Element&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;'P'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;'N'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Length=10&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;Value&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VR 자리에 &lt;code&gt;&quot;PN&quot;&lt;/code&gt; 의 ASCII 코드 &lt;code&gt;50 4E&lt;/code&gt; 가 들어감.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.3 Explicit VR Encoding &amp;mdash; 특수 VR (&lt;code&gt;OB&lt;/code&gt;, &lt;code&gt;OW&lt;/code&gt;, &lt;code&gt;OF&lt;/code&gt;, &lt;code&gt;SQ&lt;/code&gt;, &lt;code&gt;UT&lt;/code&gt;, &lt;code&gt;UN&lt;/code&gt;)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 6가지 VR은 데이터가 클 수 있어서 Length를 4 byte로 늘리고 그 앞에 2-byte 예약 공간을 둔다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;┌─────────┬──────────┬────┬──────────┬──────────┬──────────────┐
│  Group  │ Element  │ VR │ Reserved │  Length  │    Value     │
│ 2 bytes │ 2 bytes  │ 2  │ 2(=0000) │ 4 bytes  │  L bytes     │
└─────────┴──────────┴────┴──────────┴──────────┴──────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시&lt;/b&gt;: 256&amp;times;256 픽셀 이미지 (&lt;code&gt;OB&lt;/code&gt;, 1 byte/pixel = 65,536 bytes = &lt;code&gt;0x00010000&lt;/code&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;height: 65px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 23px;&quot;&gt;
&lt;th style=&quot;height: 23px; width: 44px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;Byte#&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;height: 23px; width: 70px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;1&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;height: 23px; width: 29px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;2&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;height: 23px; width: 70px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;3&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;height: 23px; width: 34px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;4&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;height: 23px; width: 70px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;5&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;height: 23px; width: 30px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;6&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;height: 23px; width: 88px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;7&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;height: 23px; width: 20px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;8&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;height: 23px; width: 194px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;9~12&lt;/p&gt;
&lt;/th&gt;
&lt;th style=&quot;height: 23px; width: 125px;&quot;&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;13~65548&lt;/p&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 44px; text-align: center;&quot;&gt;Hex&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 70px; text-align: center;&quot;&gt;&lt;code&gt;E0&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 29px; text-align: center;&quot;&gt;&lt;code&gt;7F&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 70px; text-align: center;&quot;&gt;&lt;code&gt;10&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 34px; text-align: center;&quot;&gt;&lt;code&gt;00&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 70px; text-align: center;&quot;&gt;&lt;code&gt;'O'&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 30px; text-align: center;&quot;&gt;&lt;code&gt;'B'&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 88px; text-align: center;&quot;&gt;&lt;code&gt;00&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 20px; text-align: center;&quot;&gt;&lt;code&gt;00&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 194px; text-align: center;&quot;&gt;&lt;code&gt;00 00 01 00&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 125px; text-align: center;&quot;&gt;(픽셀 65536개)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 44px; text-align: center;&quot;&gt;의미&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 70px; text-align: center;&quot;&gt;Group &lt;code&gt;7FE0&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 29px; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 70px; text-align: center;&quot;&gt;Elem &lt;code&gt;0010&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 34px; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 70px; text-align: center;&quot;&gt;VR=OB&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 30px; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 88px; text-align: center;&quot;&gt;reserved&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 20px; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 194px; text-align: center;&quot;&gt;Length=&lt;code&gt;0x00010000&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 125px; text-align: center;&quot;&gt;Pixel Data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;code&gt;(7FE0, 0010) Pixel Data&lt;/code&gt; 가 어떻게 바이트로 표현되는지 보였음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.4 Implicit vs Explicit &amp;mdash; 언제 뭘 쓰나?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&amp;nbsp;&lt;/th&gt;
&lt;th&gt;Implicit&lt;/th&gt;
&lt;th&gt;Explicit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;디폴트 여부&lt;/td&gt;
&lt;td&gt;&lt;b&gt;DICOM 기본값&lt;/b&gt; (Little Endian + Implicit)&lt;/td&gt;
&lt;td&gt;옵션&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;크기&lt;/td&gt;
&lt;td&gt;작음&lt;/td&gt;
&lt;td&gt;약간 큼&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;안전성&lt;/td&gt;
&lt;td&gt;사전 의존&lt;/td&gt;
&lt;td&gt;&lt;b&gt;VR 정보 보존&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사설 태그&lt;/td&gt;
&lt;td&gt;UN으로 처리해야&lt;/td&gt;
&lt;td&gt;VR 명시 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;두 방식을 한 객체에서 섞을 수 없음.&lt;/b&gt; 한 가지로 통일해야 함. 어느 걸 쓸지는 &lt;b&gt;Association 단계에서 합의&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.5 Implicit &amp;harr; Explicit 변환&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Explicit &amp;rarr; Implicit&lt;/b&gt;: VR만 떼면 됨 &amp;rarr; 쉬움&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Implicit &amp;rarr; Explicit&lt;/b&gt;: 모든 태그를 사전 lookup &amp;rarr; &lt;b&gt;어렵고, 사설 태그는 &lt;code&gt;UN&lt;/code&gt;으로 처리&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PACS 게이트웨이나 변환 도구 만들 때 이 비대칭성 주의.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. Group 단위 인코딩 + 정렬 규칙&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1 element는 tag 순서대로 정렬&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM object 안의 element는 &lt;b&gt;(group, element) 오름차순&lt;/b&gt;으로 정렬돼야 한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;(0008, 0012) &amp;rarr; (0008, 0014) &amp;rarr; (0010, 0010) &amp;rarr; (0010, 0020) &amp;rarr; (0028, 0010) &amp;rarr; ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 깨지면 &amp;rarr; &lt;b&gt;데이터 손상&lt;/b&gt;으로 간주, 거부.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;PACS 개발 팁&lt;/b&gt;: 파일 읽다가 tag 번호가 역행하면 즉시 reject. validation의 첫 단계.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.2 Group Length Tag &lt;code&gt;(gggg, 0000)&lt;/code&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 그룹의 첫 element는 그 그룹 전체 길이를 담는 &lt;b&gt;group length&lt;/b&gt; 용으로 예약돼 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: &lt;code&gt;(0010, 0000)&lt;/code&gt; = group &lt;code&gt;0010&lt;/code&gt; (Patient) 의 총 byte 수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점&lt;/b&gt;: 그룹 통째로 skip 가능 &amp;rarr; &lt;b&gt;partial parsing&lt;/b&gt; (사설 그룹 무시할 때 유용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&lt;/b&gt;:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;on-the-fly로 객체를 쓰기 어려움 (먼저 length 계산 필요)&lt;/li&gt;
&lt;li&gt;element 하나만 바꿔도 group length 다시 계산 &amp;rarr; 귀찮음&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;현실&lt;/b&gt;: 대부분의 DICOM 소프트웨어는 group length를 무시하거나 잘못 쓴다. &lt;b&gt;표준상으로도 group length는 optional&lt;/b&gt;. 그래도 &lt;b&gt;읽을 줄은 알아야&lt;/b&gt; 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;PACS 개발 팁&lt;/b&gt;: group length는 쓰지 말고 (덜 깨짐), 받을 때는 무시하고 직접 파싱. 이게 가장 안전한 패턴.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. DICOM Object 전체 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DICOM Object = data element들의 정렬된 시퀀스&lt;/b&gt;.&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;┌──────────────────────────────────────────────────┐
│  (0008, 0005)  CS   &quot;ISO_IR 100&quot;                 │
│  (0008, 0016)  UI   &quot;1.2.840.10008.5.1.4.1.1.2&quot;  │   &amp;larr; SOP Class
│  (0008, 0018)  UI   &quot;1.2.3.4.5...&quot;               │   &amp;larr; SOP Instance
│  (0008, 0060)  CS   &quot;CT&quot;                         │   &amp;larr; Modality
│  (0010, 0010)  PN   &quot;Smith^John&quot;                 │   &amp;larr; Patient Name
│  (0010, 0020)  LO   &quot;12345&quot;                      │   &amp;larr; Patient ID
│  (0028, 0010)  US   512                          │   &amp;larr; Rows
│  (0028, 0011)  US   512                          │   &amp;larr; Columns
│  (7FE0, 0010)  OB   &amp;lt;pixel data&amp;gt;                 │   &amp;larr; Pixel Data
└──────────────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM 파일(.dcm)도 본질적으로는 이 object를 디스크에 dump한 것. 따로 &quot;DICOM header&quot; + &quot;DICOM image&quot; 가 나뉘어 있는 게 &lt;b&gt;아니다&lt;/b&gt;. 처음부터 끝까지 element의 연속일 뿐.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. SQ (Sequence) &amp;mdash; 객체 안에 객체&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VR &lt;code&gt;SQ&lt;/code&gt; 는 &lt;b&gt;DICOM object를 통째로 또 담는&lt;/b&gt; 특수 VR. 이걸로 &lt;b&gt;트리 구조&lt;/b&gt; 표현 가능.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Parent Object
├─ (0008, 0005) Specific Character Set
├─ (0008, 1115) Referenced Series Sequence   &amp;larr; SQ!
│   ├─ Item 1
│   │   ├─ (0020, 000E) Series Instance UID
│   │   └─ (0008, 114A) Referenced Instance Sequence  &amp;larr; 또 SQ
│   │       └─ Item 1
│   │           ├─ (0008, 1150) Referenced SOP Class UID
│   │           └─ (0008, 1155) Referenced SOP Instance UID
│   └─ Item 2
└─ ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.1 SQ 인코딩 &amp;mdash; 핵심 마커들&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;마커&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(FFFE, E000)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Item 시작&lt;/b&gt; (sequence 안의 각 객체)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(FFFE, E00D)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Item 종료 (Item Delimitation)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(FFFE, E0DD)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Sequence 종료 (Sequence Delimitation)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.2 길이 지정 방법 두 가지&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) Explicit Length (명시적 길이)&lt;/h4&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;SQ ─ Length: 0x00000A00 (2560 byte)
   ├─ (FFFE,E000) ─ Length: 0x04F8 ─ DICOM object
   └─ (FFFE,E000) ─ Length: 0x04F8 ─ DICOM object&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  빨리 skip 가능&lt;br /&gt;  미리 길이 계산 필요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) Undefined Length (미정 길이) &amp;mdash; &lt;code&gt;0xFFFFFFFF&lt;/code&gt;&lt;/h4&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;SQ ─ Length: 0xFFFFFFFF (undefined)
   ├─ (FFFE,E000) ─ Length: 0x1234 ─ DICOM object
   ├─ (FFFE,E000) ─ Length: 0xFFFFFFFF ─ DICOM object ─ (FFFE,E00D) ─ 0x00000000
   └─ (FFFE,E0DD) ─ 0x00000000   &amp;larr; Sequence Delim.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  streaming 가능, 구현 쉬움&lt;br /&gt;  skip은 불가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.3 SQ는 XML과 같다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각해보면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;(gggg, eeee) SQ&lt;/code&gt; &amp;asymp; &lt;code&gt;&amp;lt;sequence&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(FFFE, E0DD)&lt;/code&gt; &amp;asymp; &lt;code&gt;&amp;lt;/sequence&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(FFFE, E000)&lt;/code&gt; &amp;asymp; &lt;code&gt;&amp;lt;item&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(FFFE, E00D)&lt;/code&gt; &amp;asymp; &lt;code&gt;&amp;lt;/item&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; DICOM SQ는 사실상 XML의 nested 구조와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;PACS 개발 팁&lt;/b&gt;:&lt;br /&gt;쓸 때는 &lt;b&gt;undefined length&lt;/b&gt; (간단하고 안전)&lt;br /&gt;읽을 때는 &lt;b&gt;둘 다&lt;/b&gt; 지원해야 함 (다른 벤더의 것)&lt;br /&gt;재귀(recursion)로 구현하면 깔끔&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. Attribute Type &amp;mdash; Required / Optional&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 데이터를 다 넣을 필요는 없다. PS3.3 (IOD)에서 각 SOP Class마다 어떤 속성이 필수인지 정의.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Required, 값 필수&lt;/b&gt; (비울 수 없음)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;1C&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Required, 조건 충족 시 (Conditional)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Required, 모르면 빈 값 OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;2C&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Required, 조건 충족 시, 모르면 빈 값 OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Optional (있어도 되고 없어도 됨)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 (CT Image SOP)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;(0010, 0020)&lt;/code&gt; Patient ID &amp;rarr; &lt;b&gt;Type 1&lt;/b&gt; (필수)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(0010, 0010)&lt;/code&gt; Patient Name &amp;rarr; &lt;b&gt;Type 2&lt;/b&gt; (필수지만 모르면 빈 값)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(0028, 2110)&lt;/code&gt; Lossy Compression &amp;rarr; &lt;b&gt;Type 1C&lt;/b&gt; (압축한 경우에만)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;⚠️ 위험한 함정: 빈 Patient ID&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Patient ID가 &lt;b&gt;빈 값&lt;/b&gt;으로 들어오면 DICOM 검색에서 &lt;b&gt;와일드카드(any)&lt;/b&gt; 로 해석될 수 있음. &lt;br /&gt;&amp;rarr; 서로 다른 환자가 한 명으로 merge되는 사고 발생.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PACS 운영자가 가장 많이 겪는 사고 중 하나.&lt;/b&gt; Patient ID는 절대 빈값으로 두면 안 됨.&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #333333; letter-spacing: 0px;&quot;&gt;  &lt;/span&gt;&lt;b&gt;검증 도구 추천&lt;/b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #333333; letter-spacing: 0px;&quot;&gt;: &lt;/span&gt;&lt;b&gt;DVTk (DICOM Validation Toolkit)&lt;/b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #333333; letter-spacing: 0px;&quot;&gt; &amp;mdash; &lt;/span&gt;&lt;a style=&quot;font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot; href=&quot;http://www.dvtk.org&quot;&gt;http://www.dvtk.org&lt;/a&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #333333; letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. Image Data &amp;mdash; 픽셀은 어떻게 저장되나&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지도 일반 element와 똑같이 저장됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심 속성&lt;/b&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Attribute&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0028, 0010)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rows&lt;/td&gt;
&lt;td&gt;세로 픽셀 수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(0028, 0011)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Columns&lt;/td&gt;
&lt;td&gt;가로 픽셀 수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(7FE0, 0010)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Pixel Data&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;실제 픽셀&lt;/b&gt; (보통 &lt;code&gt;OB&lt;/code&gt; 또는 &lt;code&gt;OW&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  Pixel Data가 &lt;b&gt;DICOM object 전체 크기의 95%&lt;/b&gt; 정도 차지. 의료 영상은 크다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Multi-frame (동영상도 됨!)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 프레임을 한 객체에 담을 수 있음. 초음파 cine loop, fluoroscopy 등.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;(0028, 0008)&lt;/code&gt; Number of Frames&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(0018, 0040)&lt;/code&gt; Frames Per Second&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: 10초짜리 25 FPS US cine = 250 프레임을 한 DICOM 객체에 저장.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  단, DICOM 자체는 비디오 코덱이 아님. 250장의 정지영상 + &quot;FPS&quot; 메타데이터를 같이 저장할 뿐. 재생은 viewer의 몫.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. UID (Unique Identifier) &amp;mdash; 글로벌 식별자&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM에서 가장 중요한 개념 중 하나.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10.1 UID란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전 세계적으로 유일한&lt;/b&gt; 문자열 식별자. VR은 &lt;code&gt;UI&lt;/code&gt;, 형식은:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;UID = &amp;lt;org root&amp;gt; . &amp;lt;suffix&amp;gt;

예: 1.2.840.10008.1.2&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;&amp;lt;org root&amp;gt;&lt;/code&gt;&lt;/b&gt;: 조직 식별자 (NEMA가 발급/관리)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;&amp;lt;suffix&amp;gt;&lt;/code&gt;&lt;/b&gt;: 조직 내에서 유일하게 부여&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예약&lt;/b&gt;: &lt;code&gt;1.2.840.10008&lt;/code&gt; = DICOM 표준 트랜잭션 전용 (남의 UID prefix로 못 씀)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10.2 인스턴스(Instance) 개념&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 영상이라도 어디 저장돼 있느냐, 누가 편집했느냐에 따라 별개의 &lt;b&gt;instance&lt;/b&gt;.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;원본 영상 (UID: ...1.1)
  ├── 복사본 1 (UID: ...1.2)   &amp;larr; 다른 곳에 저장
  ├── 크롭한 버전 (UID: ...1.3) &amp;larr; 편집됨
  └── 어노테이션 추가 (UID: ...1.4)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 모두 다른 UID. 인스턴스마다 UID는 반드시 새로 발급.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10.3 DICOM에서 UID가 쓰이는 곳&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Study Instance UID&lt;/b&gt; &lt;code&gt;(0020, 000D)&lt;/code&gt; &amp;mdash; 검사 단위&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Series Instance UID&lt;/b&gt; &lt;code&gt;(0020, 000E)&lt;/code&gt; &amp;mdash; 시리즈 단위&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SOP Instance UID&lt;/b&gt; &lt;code&gt;(0008, 0018)&lt;/code&gt; &amp;mdash; 개별 이미지&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SOP Class UID&lt;/b&gt; &lt;code&gt;(0008, 0016)&lt;/code&gt; &amp;mdash; &quot;어떤 종류 객체인지&quot; (CT, MR ...)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Transfer Syntax UID&lt;/b&gt; &amp;mdash; 인코딩 방식&lt;/li&gt;
&lt;li&gt;그 외 거의 모든 글로벌 식별자&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10.4 UID 생성 규칙&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조직 내 유일성을 보장하기 위한 흔한 패턴&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;org root&amp;gt;.&amp;lt;patient ID&amp;gt;.&amp;lt;study ID&amp;gt;.&amp;lt;current date&amp;gt;.&amp;lt;timestamp ms&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;절대 UID를 파싱하지 말 것.&lt;/b&gt; 환자 정보가 들어있는 것처럼 보여도 추출 금지. DICOM 표준이 명시적으로 금지함. UID의 유일한 용도는 &lt;b&gt;인스턴스 구별&lt;/b&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10.5 UID로 DICOM 파일 식별하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;알 수 없는 파일이 DICOM인지 확인하는 법&lt;/b&gt;:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;DICM 매직 헤더&lt;/b&gt;: 파일 129~132 byte 위치에 &lt;code&gt;&quot;DICM&quot;&lt;/code&gt; 4글자&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UID prefix 검색&lt;/b&gt;: 파일 안에서 &lt;code&gt;&quot;1.2.840.10008&quot;&lt;/code&gt; 문자열 찾기&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Windows라면 WordPad나 hex editor로 열어서 둘 중 하나 확인.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부에서 파일명을 UID로 짓는 경우도 흔함&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;1.2.804.114118.2.20040909.125423.3692976692.1.1.1.dcm&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 파일명 보이면 거의 100% DICOM.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. 핵심 정리&lt;/h2&gt;
&lt;table style=&quot;height: 255px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 24px;&quot;&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;개념&lt;/th&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;한 줄 요약&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;Tag&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;code&gt;(group, element)&lt;/code&gt; 16진수 4자리 두 개. 짝수 group=표준, 홀수=사설&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;Data Dictionary&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;2,000개 표준 속성 사전. 각 항목에 VR/VM/Type 정의&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;Command Dictionary&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Group &lt;code&gt;0000&lt;/code&gt; 전용. DIMSE 명령들&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;Implicit VR&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;code&gt;(g,e) + length(4) + value&lt;/code&gt;. DICOM 기본값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;Explicit VR&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;code&gt;(g,e) + VR(2) + length(2/4) + value&lt;/code&gt;. 안전성&amp;uarr;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;정렬 규칙&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;tag 오름차순. 위반 시 corrupted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;Group Length&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;옵션, 쓰지 말고 읽을 줄만 알 것&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;SQ&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;객체 중첩. &lt;code&gt;(FFFE,E000)&lt;/code&gt; item, &lt;code&gt;(FFFE,E0DD)&lt;/code&gt; seq 끝&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;Type 1/1C/2/2C/3&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;필수/조건부필수/필수(빈값)/조건부빈값/옵션&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;Pixel Data&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;code&gt;(7FE0, 0010)&lt;/code&gt;. 보통 &lt;code&gt;OB&lt;/code&gt;/&lt;code&gt;OW&lt;/code&gt;, 객체의 95%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;UID&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;글로벌 유일 식별자. &lt;code&gt;&amp;lt;org root&amp;gt;.&amp;lt;suffix&amp;gt;&lt;/code&gt;. 파싱 금지&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12. 다음 글에서 다룰 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DICOM Information Hierarchy (Patient/Study/Series/Image 4계층)&lt;/b&gt; 와 &lt;b&gt;IOD (Information Object Definition)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;왜 4계층인가? 실제 임상 워크플로우와 매핑&lt;/li&gt;
&lt;li&gt;Patient ID, Study UID, Series UID, SOP Instance UID &amp;mdash; 각각의 역할&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Module / Macro / Information Entity / IOD&lt;/b&gt; &amp;mdash; 어떻게 조합되나&lt;/li&gt;
&lt;li&gt;CT Image IOD를 예제로 끝까지 분해&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 가면 &lt;b&gt;&quot;왜 C-Find가 4단계로 쿼리하는지&quot;, &quot;왜 SOP Class라는 단위가 필요한지&quot;&lt;/b&gt; 가 자연스럽게 이해될 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pianykh, O.S. &lt;i&gt;Digital Imaging and Communications in Medicine (DICOM)&lt;/i&gt;. Springer, 2008.&lt;/li&gt;
&lt;li&gt;공식 표준 매핑: &lt;b&gt;PS3.5&lt;/b&gt; (Data Structures and Encoding), &lt;b&gt;PS3.6&lt;/b&gt; (Data Dictionary), &lt;b&gt;PS3.7&lt;/b&gt; (Command set)&lt;/li&gt;
&lt;li&gt;DVTk (DICOM Validation Toolkit): &lt;a href=&quot;http://www.dvtk.org&quot;&gt;http://www.dvtk.org&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Dev/DICOM</category>
      <author>odod00</author>
      <guid isPermaLink="true">https://chaechae0.tistory.com/41</guid>
      <comments>https://chaechae0.tistory.com/41#entry41comment</comments>
      <pubDate>Wed, 27 May 2026 17:14:53 +0900</pubDate>
    </item>
    <item>
      <title>[DICOM] DICOM이란 무엇인가? &amp;mdash; 데이터 표현(VR)까지</title>
      <link>https://chaechae0.tistory.com/40</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;어쩌다 의료영상 데이터를 계속 접하고 개발하는 일을 하다보니..&lt;br /&gt;DICOM 관련 문서를 제대로 읽고 정리해보고자 한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oleg Pianykh, *Digital Imaging and Communications in Medicine (DICOM): A Practical Introduction and Survival Guide* (Springer, 2008) 정리&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 챕터: Ch 1&amp;ndash;4 + Ch 5.1&amp;ndash;5.3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 &lt;b&gt;&quot;DICOM이 도대체 뭔가?&quot;&lt;/b&gt; 부터 시작해서,&lt;br /&gt;DICOM의 가장 기본 단위인 &lt;b&gt;VR (Value Representation, 데이터 표현 방식)&lt;/b&gt; 까지 정리할 예정이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. DICOM이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DICOM&lt;/b&gt; = &lt;b&gt;D&lt;/b&gt;igital &lt;b&gt;I&lt;/b&gt;maging and &lt;b&gt;CO&lt;/b&gt;mmunications in &lt;b&gt;M&lt;/b&gt;edicine&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔한 오해부터 짚자. &lt;b&gt;DICOM은 단순히 이미지 파일 포맷이 아니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM은 의료영상의&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;저장 (Storage)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;전송 (Transfer)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;표시 (Display)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모든 것을 다루는 &lt;b&gt;종합 프로토콜&lt;/b&gt;이다. 파일 포맷은 그 결과물 중 하나일 뿐.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;DICOM is an all-encompassing data transfer, storage, and display protocol built and designed to cover all functional aspects of digital medical imaging.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;왜 만들어졌나?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1980년대만 해도 CT, MR 제조사마다 자기들만의 독점 포맷을 썼다. GE 영상은 GE 워크스테이션에서만, Siemens 영상은 Siemens에서만 볼 수 있는 식이었고, 환자가 다른 병원으로 가면 영상이 무용지물이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결하려고 ACR(American College of Radiology) + NEMA(National Electrical Manufacturers Association)가 1983년에 위원회를 만들어 DICOM을 탄생시켰다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. DICOM과 PACS&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PACS&lt;/b&gt; = &lt;b&gt;P&lt;/b&gt;icture &lt;b&gt;A&lt;/b&gt;rchiving and &lt;b&gt;C&lt;/b&gt;ommunication &lt;b&gt;S&lt;/b&gt;ystem (영상 저장 전송 시스템)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PACS는 다음 세 구성요소로 이뤄진 시스템이다&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;┌─────────────┐      ┌─────────────┐      ┌─────────────┐
│  Modality   │ ───&amp;rarr; │   Archive   │ ───&amp;rarr; │ Workstation │
│ (CT, MR..)  │      │ (저장소/DB)  │      │  (판독실)   │
└─────────────┘      └─────────────┘      └─────────────┘
       &amp;uarr;                                          &amp;darr;
    영상 촬영                                  영상 판독&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Modality&lt;/b&gt;: 영상 획득 장치 (CT, MR, US, X-ray ...)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Archive&lt;/b&gt;: 디지털 저장소 (PACS 서버)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Workstation&lt;/b&gt;: 판독의가 영상을 보는 단말&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 세 요소를 연결하는 &lt;b&gt;언어가 DICOM&lt;/b&gt;. PACS는 DICOM으로 작동하고, DICOM은 PACS를 통해 현실에 구현된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비유: 디지털카메라(modality)로 사진 찍어서 &amp;rarr; 컴퓨터(archive)에 저장 &amp;rarr; 친구(reviewer)에게 보내기. 같은 모델인데 의료용으로 훨씬 복잡해진 것.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;핵심 문서: Conformance Statement&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 DICOM 장비/소프트웨어는 &lt;b&gt;DICOM Conformance Statement(적합성 명세서)&lt;/b&gt; 라는 문서를 제공해야 한다. 이 문서가 말한다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 DICOM 기능을 지원하는지&lt;/li&gt;
&lt;li&gt;어디까지 지원하는지 (SCU만? SCP만? 둘 다?)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PACS 벤더와 통신 모듈 개발 시 가장 먼저 받아야 할 문서.&lt;/b&gt; 이거 없이는 어떤 호환성 문제도 해결 못 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. DICOM은 어떻게 동작하는가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM의 핵심 개념을 압축하면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 모든 것은 &quot;객체(Object)&quot;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM은 현실의 모든 것을 &lt;b&gt;객체(Object) + 속성(Attribute)&lt;/b&gt; 으로 본다. 객체지향 프로그래밍의 것과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;현실 객체&lt;/th&gt;
&lt;th&gt;DICOM 속성 예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;환자(Patient)&lt;/td&gt;
&lt;td&gt;이름, ID, 성별, 생년월일, 체중&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;스터디(Study)&lt;/td&gt;
&lt;td&gt;검사일, 검사 종류, 의뢰의&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이미지(Image)&lt;/td&gt;
&lt;td&gt;가로, 세로, 픽셀 데이터, 슬라이스 두께&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 객체의 속성 모음을 표준화한 것이 &lt;b&gt;IOD (Information Object Definition)&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 표준 사전: Data Dictionary&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM은 의료에 필요한 약 &lt;b&gt;2,000개 이상의 표준 속성&lt;/b&gt;을 정의한 &lt;b&gt;DICOM Data Dictionary&lt;/b&gt; 를 유지한다. 모든 속성은 27가지 &lt;b&gt;VR(Value Representation, 값 표현 방식)&lt;/b&gt; 중 하나로 표현된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3 통신 모델: SCU / SCP&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM 네트워크에서 통신하는 단위를 &lt;b&gt;AE (Application Entity)&lt;/b&gt; 라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AE끼리 서비스를 주고받는 모델:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;SCU (Service Class User)&lt;/b&gt;: 서비스를 &lt;b&gt;요청&lt;/b&gt;하는 쪽 (클라이언트)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SCP (Service Class Provider)&lt;/b&gt;: 서비스를 &lt;b&gt;제공&lt;/b&gt;하는 쪽 (서버)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시: CT 스캐너가 영상을 PACS 서버에 저장&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CT 스캐너 = &lt;b&gt;Storage SCU&lt;/b&gt; (저장해줘!)&lt;/li&gt;
&lt;li&gt;PACS 서버 = &lt;b&gt;Storage SCP&lt;/b&gt; (저장해줄게)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.4 SOP (Service-Object Pair)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스(Service)와 객체(Object)를 묶은 게 &lt;b&gt;SOP&lt;/b&gt;. 예를 들어 &quot;CT 이미지를 저장&quot; = &lt;code&gt;CT Image Storage SOP&lt;/code&gt;. 이런 SOP들이 모여 &lt;b&gt;SOP Class&lt;/b&gt; 를 이룬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.5 Association: 통신의 시작&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 AE가 통신하려면 먼저 &lt;b&gt;Association(연결)&lt;/b&gt; 을 맺어야 한다. TCP 연결 후 &quot;나는 누구고, 이런 서비스 지원하고, 이런 인코딩 쓴다&quot; 하고 서로 자기소개를 한다. 이걸 &lt;b&gt;Presentation Context&lt;/b&gt; 라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 이게 맞으면 통신 시작, 안 맞으면 연결 거부.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Association은 DICOM 디버깅의 80%가 일어나는 곳.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. &quot;DICOM-Compatible&quot; vs &quot;DICOM-Ready&quot; 함정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장비를 살 때 주의할 점.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;DICOM-Compatible&lt;/b&gt;: 실제로 DICOM 기능이 탑재됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DICOM-Ready&lt;/b&gt;: 돈을 추가로 내면 DICOM 기능을 켤 수 있음 (= 안 사면 못 씀)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장비 제조사들은 종종 DICOM 기능을 &lt;b&gt;유료 옵션&lt;/b&gt;으로 판매한다. &quot;DICOM-Ready 장비를 샀더니 정작 DICOM은 못 쓰더라&quot; 가 흔한 함정.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;장비 살 때 견적서에 &lt;b&gt;&quot;DICOM functionality&quot;가 명시적으로 포함됐는지&lt;/b&gt; 확인할 것.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666; font-family: 'Noto Serif KR'; letter-spacing: 0px;&quot;&gt;또한 직접 패치하려 하지 말 것. 무조건 제조사를 통해 해결. (보증 날아감)&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 간략한 역사&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연도&lt;/th&gt;
&lt;th&gt;이벤트&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1983&lt;/td&gt;
&lt;td&gt;ACR + NEMA 위원회 발족&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1985&lt;/td&gt;
&lt;td&gt;ACR-NEMA 1.0 발표&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1988&lt;/td&gt;
&lt;td&gt;ACR-NEMA 2.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1993&lt;/td&gt;
&lt;td&gt;&lt;b&gt;DICOM 3.0&lt;/b&gt; (현재까지 사용 중)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이후~현재&lt;/td&gt;
&lt;td&gt;DICOM 3.0의 연간 개정판 (PS3.X-YYYY 형식)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM 4.0은 없다. DICOM 3.0이 매년 개정될 뿐. 그래서 &quot;DICOM 2008&quot;은 정확히는 &quot;DICOM 3.0의 2008년 개정판&quot;을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;중요&lt;/b&gt;: 의료기기는 수명이 길기 때문에 (15~20년) 1990년대 기능 세트를 가진 장비가 아직도 현역에서 돌아간다. &lt;b&gt;하위 호환성이 항상 최우선&lt;/b&gt; 이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 컴퓨터 기초 복습 (DICOM 이해를 위한)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM을 이해하려면 비트/바이트/16진수에 익숙해야 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Bit / Byte&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;bit&lt;/b&gt;: 0 또는 1&lt;/li&gt;
&lt;li&gt;&lt;b&gt;byte&lt;/b&gt;: 8 bit = 256가지 값 (0~255)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;16진수 (Hexadecimal)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2바이트(16비트) = 4자리 16진수 (예: &lt;code&gt;0x007F&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;표기: &lt;code&gt;0x&lt;/code&gt; 접두사 또는 &lt;code&gt;H&lt;/code&gt; 접미사&lt;/li&gt;
&lt;li&gt;DICOM의 거의 모든 숫자 식별자는 &lt;b&gt;16진수&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;0x007F  =  0&amp;times;16&amp;sup3; + 0&amp;times;16&amp;sup2; + 7&amp;times;16&amp;sup1; + 15&amp;times;16⁰  =  127&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Endian (바이트 순서) ⚠️&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Little Endian&lt;/b&gt;: 낮은 자리 바이트 먼저 (Intel/Windows)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Big Endian&lt;/b&gt;: 높은 자리 바이트 먼저 (구 Mac, 네트워크 표준)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 숫자 &lt;code&gt;0x007F&lt;/code&gt; (127)가&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Little Endian: &lt;code&gt;7F 00&lt;/code&gt; 으로 저장&lt;/li&gt;
&lt;li&gt;Big Endian: &lt;code&gt;00 7F&lt;/code&gt; 으로 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 두 시스템이 통신할 때 이게 안 맞으면 &lt;code&gt;127&lt;/code&gt;이 &lt;code&gt;32,512&lt;/code&gt;로 잘못 읽힘.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DICOM 기본값은 Little Endian.&lt;/b&gt; 모든 DICOM 구현체는 무조건 Little Endian을 지원해야 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Text vs Binary&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DICOM은 두 가지 데이터 형식을 다 쓴다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Text&lt;/b&gt;: 이름, ID, 날짜 등 &amp;rarr; Endian 영향 없음, 사람이 읽기 쉬움&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Binary&lt;/b&gt;: 픽셀 데이터, 좌표 등 &amp;rarr; 공간 효율적이지만 Endian 영향 받음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM 파일을 메모장에서 열면 텍스트와 깨진 문자가 섞여 보이는 이유.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. VR (Value Representation) &amp;mdash; DICOM의 어휘&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DICOM은 모든 데이터를 27가지 VR 중 하나로 표현&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 VR은:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;2글자 약어&lt;/b&gt; (예: &lt;code&gt;PN&lt;/code&gt;, &lt;code&gt;DA&lt;/code&gt;, &lt;code&gt;UI&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;허용되는 문자&lt;/li&gt;
&lt;li&gt;최대 길이&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 정해두고 있다. PACS 호환성 문제의 상당수가 &quot;VR 길이 초과&quot; 또는 &quot;VR 형식 위반&quot;에서 나온다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.1 텍스트형 VR (Text VRs)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;VR&lt;/th&gt;
&lt;th&gt;이름&lt;/th&gt;
&lt;th&gt;최대 길이&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Code String&lt;/td&gt;
&lt;td&gt;16자&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;CT&quot;&lt;/code&gt;, &lt;code&gt;&quot;MR&quot;&lt;/code&gt;, &lt;code&gt;&quot;CD123_4&quot;&lt;/code&gt; (대문자/숫자/_/공백만)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SH&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Short String&lt;/td&gt;
&lt;td&gt;16자&lt;/td&gt;
&lt;td&gt;전화번호, ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LO&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Long String&lt;/td&gt;
&lt;td&gt;64자&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;Introduction to DICOM&quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Short Text&lt;/td&gt;
&lt;td&gt;1,024자&lt;/td&gt;
&lt;td&gt;1~수 문단&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Long Text&lt;/td&gt;
&lt;td&gt;10,240자&lt;/td&gt;
&lt;td&gt;긴 문단&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unlimited Text&lt;/td&gt;
&lt;td&gt;거의 무제한&lt;/td&gt;
&lt;td&gt;매우 긴 텍스트&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.2 이름과 식별자&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;VR&lt;/th&gt;
&lt;th&gt;이름&lt;/th&gt;
&lt;th&gt;최대&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Application Entity (장비/프로그램 이름)&lt;/td&gt;
&lt;td&gt;16자&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;MYPACS01&quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Person Name (사람 이름)&lt;/td&gt;
&lt;td&gt;64자&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;SMITH^JOHN&quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UI&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unique Identifier (UID)&lt;/td&gt;
&lt;td&gt;64자&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;1.2.840.10008.1.1&quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PN의 표준 형식&lt;/b&gt; (caret &lt;code&gt;^&lt;/code&gt; 로 구분)&lt;/p&gt;
&lt;pre class=&quot;cos&quot;&gt;&lt;code&gt;FamilyName^GivenName^MiddleName^NamePrefix^NameSuffix&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 임상 환경에서는 &lt;code&gt;&quot;John Smith&quot;&lt;/code&gt;, &lt;code&gt;&quot;Smith^John&quot;&lt;/code&gt;, &lt;code&gt;&quot;Smith, John&quot;&lt;/code&gt; 가 막 섞여서 들어와 혼란이 잦다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;rarr; 환자 식별은 항상 Name이 아니라 Patient ID로 해라.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.3 날짜와 시간&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;VR&lt;/th&gt;
&lt;th&gt;이름&lt;/th&gt;
&lt;th&gt;형식&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DA&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Date&lt;/td&gt;
&lt;td&gt;&lt;code&gt;YYYYMMDD&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;20050822&quot;&lt;/code&gt; (2005년 8월 22일)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TM&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Time&lt;/td&gt;
&lt;td&gt;&lt;code&gt;HHMMSS.FRAC&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;183200.00&quot;&lt;/code&gt; (18:32:00.00)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Date Time&lt;/td&gt;
&lt;td&gt;&lt;code&gt;YYYYMMDDHHMMSS.FFFFFF&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;20050812183000.00&quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Age String&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nnnD/W/M/Y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;018M&quot;&lt;/code&gt; (18개월)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;DICOM은 시간대(Time Zone)를 지원하지 않는다.&lt;/b&gt; 텔레라디올로지에서 여러 나라를 연결할 때 함정이 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.4 숫자 (텍스트 형식)&lt;/h3&gt;
&lt;table style=&quot;height: 60px;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 24px;&quot;&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;VR&lt;/th&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;이름&lt;/th&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;IS&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Integer String&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;&quot;-1234567&quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;DS&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;Decimal String&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;&lt;code&gt;&quot;12345.67&quot;&lt;/code&gt;, &lt;code&gt;&quot;-5.0e3&quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.5 숫자 (바이너리 형식)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;VR&lt;/th&gt;
&lt;th&gt;이름&lt;/th&gt;
&lt;th&gt;크기&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Signed Short&lt;/td&gt;
&lt;td&gt;2 byte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;US&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unsigned Short&lt;/td&gt;
&lt;td&gt;2 byte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Signed Long&lt;/td&gt;
&lt;td&gt;4 byte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unsigned Long&lt;/td&gt;
&lt;td&gt;4 byte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Floating Point Single&lt;/td&gt;
&lt;td&gt;4 byte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FD&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Floating Point Double&lt;/td&gt;
&lt;td&gt;8 byte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Attribute Tag (group, element 쌍)&lt;/td&gt;
&lt;td&gt;4 byte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OB&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Other Byte String (1 byte씩)&lt;/td&gt;
&lt;td&gt;가변&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OW&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Other Word String (2 byte씩)&lt;/td&gt;
&lt;td&gt;가변&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OF&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Other Float String (4 byte씩)&lt;/td&gt;
&lt;td&gt;가변&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OB, OW, OF 가 픽셀 데이터(이미지) 를 담는 데 쓰임. 압축 영상은 보통 OB 사용.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.6 특수 VR&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;VR&lt;/th&gt;
&lt;th&gt;이름&lt;/th&gt;
&lt;th&gt;용도&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SQ&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sequence of Items&lt;/td&gt;
&lt;td&gt;&lt;b&gt;객체 안에 객체&lt;/b&gt; (중첩 구조)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unknown&lt;/td&gt;
&lt;td&gt;알 수 없는 데이터 (가능하면 쓰지 말 것)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;SQ&lt;/code&gt; 는 DICOM의 트리 구조를 만들 때 사용. 예를 들어 &quot;여러 시리즈를 참조하는 리스트&quot; 같은 것. 처리가 복잡해서 버그가 자주 발생하는 부분이기도 함.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. VR의 중요한 규칙들&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.1 짝수 길이 규칙&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모든 DICOM 데이터 요소는 짝수 바이트 길이여야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;홀수 길이면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;텍스트 &amp;rarr; 공백(&lt;code&gt;' '&lt;/code&gt;) 한 칸 패딩&lt;/li&gt;
&lt;li&gt;바이너리 &amp;rarr; NULL(&lt;code&gt;0x00&lt;/code&gt;) 한 바이트 패딩&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: &lt;code&gt;&quot;Smith^Joe&quot;&lt;/code&gt; (9자) &amp;rarr; 내부 저장은 &lt;code&gt;&quot;Smith^Joe &quot;&lt;/code&gt; (10자, 끝에 공백 추가)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비DICOM 시스템(SQL DB 등)으로 데이터 옮길 때 trailing space를 안 잘라내면&lt;/b&gt; &lt;code&gt;&quot;Smith^Joe&quot;&lt;/code&gt; 와 &lt;code&gt;&quot;Smith^Joe &quot;&lt;/code&gt; 가 다른 환자로 인식되는 사고 발생.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.2 와일드카드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DICOM 텍스트 검색에서&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;*&lt;/code&gt; : 임의 문자열 (asterisk)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;?&lt;/code&gt; : 임의 한 글자&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\&lt;/code&gt; : OR 연산자&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: 모달리티 검색 &lt;code&gt;&quot;CT\MR&quot;&lt;/code&gt; = &quot;CT 또는 MR&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 따라서 &lt;b&gt;파일명이나 텍스트에 &lt;code&gt;\&lt;/code&gt; 를 쓰면 안 됨.&lt;/b&gt; 검색 쿼리로 오해받음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.3 단위&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DICOM은 &lt;b&gt;미터법(SI 단위)&lt;/b&gt; 만 쓴다 (mm, kg, ...)&lt;/li&gt;
&lt;li&gt;화면 표시는 사용자가 알아보기 쉽게 변환할 것 (예: &lt;code&gt;20080201&lt;/code&gt; &amp;rarr; &lt;code&gt;2008-02-01&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 다음 글에서 다룰 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VR이 DICOM의 &quot;어휘&quot;라면, &lt;b&gt;Tag와 Data Dictionary&lt;/b&gt;는 &quot;단어장&quot;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 글(2편)에서는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DICOM &lt;b&gt;Tag&lt;/b&gt; &lt;code&gt;(group, element)&lt;/code&gt; 구조&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Data Dictionary&lt;/b&gt; &amp;mdash; 2,000개 표준 속성&lt;/li&gt;
&lt;li&gt;Private Tag (제조사 독자 확장)&lt;/li&gt;
&lt;li&gt;DICOM &lt;b&gt;Object Encoding&lt;/b&gt; &amp;mdash; Implicit/Explicit VR&lt;/li&gt;
&lt;li&gt;Patient/Study/Series/Image 4계층&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;까지 정리한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;핵심 정리&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;DICOM = 의료영상 통신/저장/표시 종합 프로토콜&lt;/b&gt; (단순 파일 포맷 X)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PACS = DICOM으로 작동하는 영상 시스템&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;객체지향 모델: &lt;b&gt;IOD = 객체 + 속성&lt;/b&gt;, 통신은 &lt;b&gt;SCU&amp;harr;SCP&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;통신 단위는 &lt;b&gt;AE&lt;/b&gt;, 서비스+객체 쌍은 &lt;b&gt;SOP&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Conformance Statement&lt;/b&gt;가 모든 DICOM 작업의 출발점&lt;/li&gt;
&lt;li&gt;모든 데이터는 27가지 &lt;b&gt;VR&lt;/b&gt; 중 하나로 표현&lt;/li&gt;
&lt;li&gt;기본 Endian은 &lt;b&gt;Little Endian&lt;/b&gt;, 모든 길이는 &lt;b&gt;짝수&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;환자 식별은 &lt;b&gt;이름이 아니라 Patient ID&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pianykh, O.S. &lt;i&gt;Digital Imaging and Communications in Medicine (DICOM)&lt;/i&gt;. Springer, 2008.&lt;/li&gt;
&lt;li&gt;DICOM 공식: &lt;a href=&quot;http://medical.nema.org&quot;&gt;http://medical.nema.org&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Dev/DICOM</category>
      <author>odod00</author>
      <guid isPermaLink="true">https://chaechae0.tistory.com/40</guid>
      <comments>https://chaechae0.tistory.com/40#entry40comment</comments>
      <pubDate>Tue, 26 May 2026 17:54:21 +0900</pubDate>
    </item>
    <item>
      <title>[디지털 하나로]  금융 서비스개발 수료 후기</title>
      <link>https://chaechae0.tistory.com/39</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;졸업유예를 하기로 결정하고 요놈의 공백기를 어떻게 보내야할까.. 라는 고민끝에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;금융권 부트캠프에 지원했었고, 6개월 간 기나긴 대장정이 끝나 수료후기를 써본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신한DS, KB 등등 많은 금융권 부트캠프가 존재했고 내 상황과 시기상 알맞았던 '디지털 하나로'에 지원했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6개월 과정이고 수료했을때 최우수, 우수 수료생에 있어서 하나은행 서류면제 또는 코딩테스트 면제권이 주어진다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 같은 시기에 이런 기회를 놓칠 수 없었고 사실상 혜택을 보고 지원한거나 다름 없다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;1010&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Un2OL/btsQH3E75rR/aqNcUUKOyKLK4eWSMTteW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Un2OL/btsQH3E75rR/aqNcUUKOyKLK4eWSMTteW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Un2OL/btsQH3E75rR/aqNcUUKOyKLK4eWSMTteW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUn2OL%2FbtsQH3E75rR%2FaqNcUUKOyKLK4eWSMTteW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1214&quot; height=&quot;1010&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;1010&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부트캠프 지원이라 그런지 생각했던 것보다 1차 서류는 무난하게 붙었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기초역량평가는 html, css, java, python 등이 나온다고 적혀있었지만 오히려 적혀있지 않았던 js 문제가 많이 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;html, css, java, python, js 에서 다룰 수 있는 헷갈릴 수 있는 문제들이랑 코테 3문제가 나왔고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각했던 것보다 어려웠어서 합격할 수 있을지 불안했다...&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-09-20 오후 10.41.24.png&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rvZp0/btsQJXDXM7Q/YaQ9nzYFOGk7Md5AUuJ5yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rvZp0/btsQJXDXM7Q/YaQ9nzYFOGk7Md5AUuJ5yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rvZp0/btsQJXDXM7Q/YaQ9nzYFOGk7Md5AUuJ5yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrvZp0%2FbtsQJXDXM7Q%2FYaQ9nzYFOGk7Md5AUuJ5yk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1214&quot; height=&quot;408&quot; data-filename=&quot;스크린샷 2025-09-20 오후 10.41.24.png&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 합격! 막상 합격하고보니 지원자들 전부 실력적으로 비슷비슷하지 않았을까라는 생각이 들었다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너무 쫄지 않아도 됐을듯?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_6100.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8xMry/btsQHtqCcqT/bkfKVHrUPTLvjeL8Z2kPH0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8xMry/btsQHtqCcqT/bkfKVHrUPTLvjeL8Z2kPH0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8xMry/btsQHtqCcqT/bkfKVHrUPTLvjeL8Z2kPH0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8xMry%2FbtsQHtqCcqT%2FbkfKVHrUPTLvjeL8Z2kPH0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3024&quot; height=&quot;4032&quot; data-filename=&quot;IMG_6100.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;면접을 위해 하나은행 본사를 방문했다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;면접이라는걸 본지 너무 오래돼서 사시나무 떨듯 떨면서 봤던 면접..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dxbhVJ/btsQIw1oQQb/1Kf5QLItfi96AM3bRn7ypK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dxbhVJ/btsQIw1oQQb/1Kf5QLItfi96AM3bRn7ypK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dxbhVJ/btsQIw1oQQb/1Kf5QLItfi96AM3bRn7ypK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdxbhVJ%2FbtsQIw1oQQb%2F1Kf5QLItfi96AM3bRn7ypK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스타벅스 쿠폰까지 야무지게 받고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 프로젝트에 대한 질문, 기술적인 질문이 많이 나올거라 예상하고 봤던 면접인데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 기술질문은 아예 들어오지 않았다. 근데 다른 동기들은 기술질문도 있었다고 하니 면접관 바이 면접관이 아니었을까..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대충 기억해보자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'하나은행은 영업점 근무가 1년에서 1년반정도 필수인데 이런 부분에 있어 괜찮은지?'&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'6개월이 꽤 긴 시간인데 중간에 취업해서 나갈 생각이 있는지?'&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'이 부트캠프를 통해 얻어가고 싶은부분이 무엇인지 (기술적인 성장 제외하고)'&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'금융권 부트캠프를 지원한 이유가 무엇인지'&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등등 이었고 막 어려운 질문은 아니었어서 그냥그냥 무난하게 대답했었던 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래는 6:1 면접이었는데 사람들이 많이 안와서 2:1 면접으로 진행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그덕에 면접시간이 남들보다 2배는 길었던 것 같은데 대신 분위기는 조금 더 편했던 부분도 있었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;1108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tZOrI/btsQJbWWV77/AOehn9WpkpD0jTq7PUW3Uk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tZOrI/btsQJbWWV77/AOehn9WpkpD0jTq7PUW3Uk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tZOrI/btsQJbWWV77/AOehn9WpkpD0jTq7PUW3Uk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtZOrI%2FbtsQJbWWV77%2FAOehn9WpkpD0jTq7PUW3Uk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1214&quot; height=&quot;1108&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;1108&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히 합격!!!&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIK23r/btsQGd99ppC/L4KgE6UyvmK3T4PpNrhUv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIK23r/btsQGd99ppC/L4KgE6UyvmK3T4PpNrhUv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIK23r/btsQGd99ppC/L4KgE6UyvmK3T4PpNrhUv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIK23r%2FbtsQGd99ppC%2FL4KgE6UyvmK3T4PpNrhUv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1330&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설레는 마음으로 입학식도 들었었다..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_7479.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3273E/btsQG0JbDTk/EeJwNK11phInHRa0rHkxo1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3273E/btsQG0JbDTk/EeJwNK11phInHRa0rHkxo1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3273E/btsQG0JbDTk/EeJwNK11phInHRa0rHkxo1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3273E%2FbtsQG0JbDTk%2FEeJwNK11phInHRa0rHkxo1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3024&quot; height=&quot;4032&quot; data-filename=&quot;IMG_7479.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간에 2번의 프로젝트를 진행했다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2개월 반정도 js, ts, next.js 등을 배우고 1개월간 next.js 로 진행하는 풀스택 개발 프로젝트와&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1개월 반정도 java, spring 등을배우고 1개월간 next.js 와 spring으로 진행하는 풀스택 개발 프로젝트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두개의 프로젝트를 진행했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 과정은 나한테 기술적인 성장에 있어서 매우 유익했던 것 같다. 원래 프론트엔드 쪽이기도 했고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백엔드보다는 프론트엔드를 좀 더 깊이 있게 배우는 느낌이라 내 커리어에는 잘 맞았던 교육이 아니었나 라고 생각했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 나는 무조건 백엔드개발자!! 프론트는 필요없다 이런 사람은 안듣는게 좋을지도....&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;1428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDBfZN/btsQHBWrtxx/DkB9B5YZttCxC52Z0M2391/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDBfZN/btsQHBWrtxx/DkB9B5YZttCxC52Z0M2391/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDBfZN/btsQHBWrtxx/DkB9B5YZttCxC52Z0M2391/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDBfZN%2FbtsQHBWrtxx%2FDkB9B5YZttCxC52Z0M2391%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;1428&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;1428&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길고 길었던 6개월이 지나고 마지막 수료식..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정을 다른 사람에게 추천하는가? 라고 물었을때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공백기를 줄이고 싶다, 금융권 스펙 한줄이라도 추가하고싶다. 라고 한다면 추천&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아니면 추천하지 않을 것 같다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 6개월이라는 시간이 정말 너무 길다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 과정 하나하나가 시간도 들고 노력도 드는 거라 취준을 병행하기도 힘들다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 다같이 으쌰으쌰해서 나름 자격증도 3개나 따고 유익했지만 당장 취업이 급한사람에게는 굳이.. 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그시간에 내 실력을 갈고닦는게 더 빠른 길일지도..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 일반, 우수, 최우수를 가리는 기준이 정말 모호하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실력적으로 우수하거나 성실하거나 내가 얼마나 프로젝트를 열심히 임했는지는 중요하지 않다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강사님에게 내가 얼마나 어필할 수 있는가, 얼마나 맘에 들었는가 밉보이지는 않았는가 가 더 중요한 과정이었던 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트에 있어서도 공식적으로 정해진 기준이 아니라 강사의 선호도에 따라 팀별로 평가기준이 달라진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 팀은 단순구현만으로 칭찬을 받는 반면 어떤 팀은 엄격한 평가기준으로 진행된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따지자면, 얼마든지 강사의 입맛에 따라 1, 2, 3등을 뒤바꿀 수 있다는 뜻이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모든 과정들을 견디고 사회생활을 배운다는 마음으로 열심히 어필한다면 좋은 성적을 받을 수 있다고 생각한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 실력으로 평가받고 공정하게 평가받고 싶은 분들은 듣지 않는 것을 추천한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 것이 끝나고 나니 깨달은 것은 내가 뒤에서 아무리 열심히 한다고 한들 아무도 알아주지 않는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본인 어필을 하고 내가 뭘했는지 얼마나 적극적인지 드러내야 알아준다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참 사회생활이 이런건가.. 라는 걸 깨달은 것도 배운거라면 배운거라고 볼 수 있을 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 과정에서 만난 동기들과도 너무 즐거운 시간을 보냈고 좋은 사람들을 얻었다는 점에서 후회되지는 않는 6개월이었던 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제는 진짜 취업시장으로 뛰어들어갈 일만 남았다... 아자잇!&lt;/p&gt;</description>
      <category>Etc</category>
      <category>디지털 하나로</category>
      <category>부트캠프</category>
      <category>수료</category>
      <category>하나은행</category>
      <author>odod00</author>
      <guid isPermaLink="true">https://chaechae0.tistory.com/39</guid>
      <comments>https://chaechae0.tistory.com/39#entry39comment</comments>
      <pubDate>Sat, 20 Sep 2025 23:49:50 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] Suspense</title>
      <link>https://chaechae0.tistory.com/38</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Suspense가 무엇인고...?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Suspense란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Suspense는 React 컴포넌트를 잠시멈추고 기다릴 수 있도록하는 기능이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로딩 중인 컴포넌트 대신 사용자에게 일시적인 UI(fallback)을 보여주고 준비가 되었을 때 실제 컴포넌트를 보여준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Suspense 기본 문법&lt;/h2&gt;
&lt;pre id=&quot;code_1748248170596&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Suspense } from 'react';

&amp;lt;Suspense fallback={&amp;lt;p&amp;gt;로딩 중...&amp;lt;/p&amp;gt;}&amp;gt;
  &amp;lt;MyComponent /&amp;gt;
&amp;lt;/Suspense&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MyComponent 가 로드 중일 경우 대신 fallback{&amp;lt;p&amp;gt;로딩 중...&amp;lt;/p&amp;gt;}을 대신 보여주고 로드가 완료되면 &amp;lt;MyComponent /&amp;gt; 로 대체된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Suspense가 사용되는 경우&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1️⃣ React.lazy()로 지연 로딩을 하는 경우&amp;nbsp;&lt;/h3&gt;
&lt;pre id=&quot;code_1748248340356&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Suspense, lazy } from 'react'

const LazyComponent = lazy(() =&amp;gt; import('./HeavyComponent'))

function App() {
  return (
    &amp;lt;Suspense fallback={&amp;lt;p&amp;gt;Loading...&amp;lt;/p&amp;gt;}&amp;gt;
      &amp;lt;LazyComponent /&amp;gt;
    &amp;lt;/Suspense&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2️⃣ Next.js 의 use() 사용 시 (비동기)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Suspense를 명시하지 않고도 자동으로 사용할 수 있는 방법이 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;loading.tsx를 만들어 해당 loading을 사용할 page.tsx 와 같은 파일경로 내에 위치시키면 use()호출이 Promise Pending 상태일 때 loading.tsx를 자동으로 fallback으로 사용한다. =&amp;gt; &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;Suspense를 내부적으로 자동 사용&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1748248906301&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app/
├─ dashboard/
│  ├─ page.tsx
│  ├─ loading.tsx&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1748248942299&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// page.tsx
export default function DashboardPage() {
  const data = use(fetchData())  // 서버에서 데이터 fetch
  return &amp;lt;div&amp;gt;{data.title}&amp;lt;/div&amp;gt;
}

//loading.tsx
export default function Loading() {
  return &amp;lt;p&amp;gt;로딩 중입니다...&amp;lt;/p&amp;gt;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3️⃣ RCC와 함께 쓰일 경우&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React Client Component는 서버에서 렌더링 되지 않기 때문에 서버 컴포넌트가 Suspense로 감싸야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Suspense로 감싸면 Client Component가 JS로 로딩될 때까지 fallback UI가 먼저 보여진다.&lt;/p&gt;
&lt;pre id=&quot;code_1748249083539&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// layout.tsx
&amp;lt;Suspense fallback={&amp;lt;h1&amp;gt;로딩 중...&amp;lt;/h1&amp;gt;}&amp;gt;
  &amp;lt;ReactClientComponent /&amp;gt;
&amp;lt;/Suspense&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Dev/Next.js</category>
      <category>Next.js</category>
      <category>RCC</category>
      <category>suspense</category>
      <author>odod00</author>
      <guid isPermaLink="true">https://chaechae0.tistory.com/38</guid>
      <comments>https://chaechae0.tistory.com/38#entry38comment</comments>
      <pubDate>Mon, 26 May 2025 17:46:29 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] Next.js 는 뭘까..?</title>
      <link>https://chaechae0.tistory.com/37</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;Next.js 란?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;React 기반의 FullStack 웹 프레임워크이다. React 는 오직 화면을 그리는 렌더링 로직만 담당하기 때문에 &lt;u&gt;라이브러리&lt;/u&gt;지만 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Next.js 는 React 위에 서버 사이드 렌더링, 라우팅, 데이터 로딩, 정적 생성 등을 얹은 풀스택 도구를 제공하기 때문에 &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;프레임워크&lt;/span&gt;이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;특징&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;React 기반의 풀스택 프레임워크로 프론트와 백엔드를 통합해서 개발이 가능하다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;PageRouter 와 AppRouter 를 모두 지원한다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;Nested Layout (layout.tsx - page.tsx) 구성이 가능하다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;다양한 렌더링 방식을 지원한다. (SSG, CSR, SSR, ISR)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;Tailwind, Typescript를 지원하며, Core Web Vitals에 최적화되어있다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;PageRouter vs AppRouter&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;PageRouter&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;pages/ 폴더 기반 라우팅 시스템이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;421&quot; data-start=&quot;196&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;264&quot; data-start=&quot;196&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;파일 기반 라우팅 (pages/index.js, pages/about.js &amp;rarr; /, /about) 이다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;344&quot; data-start=&quot;265&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;getStaticProps, getServerSideProps, getInitialProps 등 데이터 페칭 메서드를 사용한다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;396&quot; data-start=&quot;345&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;useEffect, useState 등 기본 React Hook 사용 가능하다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;421&quot; data-start=&quot;397&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Next.js 13 이전까지의 기본 방식이다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;파일구조&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1748219000297&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pages/
├── index.tsx       =&amp;gt; /
├── about.tsx       =&amp;gt; /about
└── blog/[id].tsx   =&amp;gt; /blog/:id (동적 라우팅)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;AppRouter&lt;/span&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;app/ 폴더 기반의 컴포넌트 중심 라우팅이며,&amp;nbsp; 서버 컴포넌트를 지원한다.&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;960&quot; data-start=&quot;652&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;678&quot; data-start=&quot;652&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;기본이 Server Component 이다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;718&quot; data-start=&quot;679&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;폴더 기반 중첩 라우팅(Nested Routing) 구조 이다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;809&quot; data-start=&quot;719&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;layout.tsx, page.tsx, loading.tsx, error.tsx, template.tsx 등 구성요소를 명확하게 분리한다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;897&quot; data-start=&quot;810&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;fetch()와 revalidate 등으로 데이터 처리를 한다. (getStaticProps, getServerSideProps는 사용 불가)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;960&quot; data-start=&quot;898&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;RSC (React Server Components) 기반&lt;/span&gt;으로 클라이언트에 불필요한 JS 전송을 최소화 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1748221111865&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app/
├── layout.tsx          &amp;larr; 전체 레이아웃
├── page.tsx            &amp;larr; /
├── about/
│   └── page.tsx        &amp;larr; /about
├── blog/
│   ├── [id]/
│   │   └── page.tsx    &amp;larr; /blog/:id
│   └── layout.tsx      &amp;larr; /blog 관련 공통 레이아웃&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #666666;&quot;&gt;❓ &lt;b&gt;React Server Component란? (RSC)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;React 컴포넌트를 서버에서 렌더링하고 HTML만 클라이언트에 보내는 방식이다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;브라우저에 JS 가 번들되지 않으며 더 가볍고 빠르다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;DB 쿼리, 파일 시스템 접근, API 호출 등 서버 전용 작업이 가능하다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;클라이언트와는 달리 useState, useEffect 같은 hook 사용이 불가능하다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Next.js App Router에선 기본이 Server Component이다.&amp;nbsp;&lt;br /&gt;따라서 &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;인터렉션이 필요없는 부분&lt;/span&gt;에서만 Server Component 를 사용하는 것이 가장 이상적이다.&amp;nbsp;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #666666;&quot;&gt;❓&lt;b&gt; React Client Component란? (RCC)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #666666;&quot;&gt;컴포넌트 상단에 'use client' 선언이 필요하다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #666666;&quot;&gt;클라이언트에서 실행되므로 Hook 사용과 이벤트 처리가 가능하다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #666666;&quot;&gt;fs 접근이나 직접적인 DB fetch도 불가능하다.&amp;nbsp;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #666666;&quot;&gt;cf. &lt;b&gt;Server Action&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;클라이언트에서 서버 함수를 직접 호출할 수 있게 해주는 Next.js 기능이다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #666666;&quot;&gt;POST API 를 따로 만들지 않고도 서버에서 실행되는 함수를 클라이언트에서 바로 호출하거나 &amp;lt;form&amp;gt;으로 전송할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/blockquote&gt;
&lt;pre id=&quot;code_1748246518517&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// server action 예시

// app/actions.ts (Server Action)
'use server'

import { revalidatePath } from 'next/cache'

export async function addTodo(prevState: any, formData: FormData) {
  const title = formData.get('title') as string
  await db.todo.create({ data: { title } })
  revalidatePath('/')
}


// app/page.tsx (Server Component)
'use client'

import { useFormState } from 'react-dom'
import { addTodo } from './actions'

export default function Page() {
  const [state, formAction] = useFormState(addTodo, null)

  return (
    &amp;lt;form action={formAction}&amp;gt;
      &amp;lt;input type=&quot;text&quot; name=&quot;title&quot; /&amp;gt;
      &amp;lt;button type=&quot;submit&quot;&amp;gt;추가&amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;Next.js 의 렌더링 방식 4가지&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;✔️ SSG (Static Site Generation)&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;정적페이지를 미리 생성하여, 빌드 시점에 HTML을 만들어 배포한다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;사용자 요청 시 HTML 파일을 즉시 응답할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;빠르고 CDN 캐싱이 가능하고 성능과 SEO에 매우 유리하다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;PageRouter에서만 getStaticProps()를 사용할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #666666;&quot;&gt;❓ getStaticProps() 가 뭔데?&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #666666;&quot;&gt;해당 페이지에서 사용할 데이터를 미리 가져와 HTML 에 반영하는 함수이다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #666666;&quot;&gt;빠른 페이지 로딩과 SEO 최적화에 매우 유리하다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #666666;&quot;&gt;대신 AppRouter 에서는 사용이 불가하다.&amp;nbsp;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;✔️ SSR (Server Side Rendering)&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;매 요청마다 서버에서 HTML을 생성한다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;항상 최신데이터를 보여줄 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;요청마다 서버 렌더링이 필요하므로, 상대적으로 느리다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;PageRouter에서만 gerServerSideProps()를 사용할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;✔️ ISR (Incremental Static Regeneration)&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;정적페이지를 일정 주기마다 갱신한다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;SSG의 성능과 SSR의 최신성 장점을 절충하였다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;835&quot; data-start=&quot;767&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;초기엔 SSG처럼 정적 생성하고&amp;nbsp;이후에는 revalidate 설정에 따라 주기적으로 새 HTML을 생성한다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;897&quot; data-start=&quot;836&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;App Router에서는 fetch(..., { next: { revalidate: n } })로 설정한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;✔️ CSR (Client Side Rendering)&lt;/span&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;브라우저에서 React가 JS를 통해 직접 렌더링한다.&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1167&quot; data-start=&quot;1013&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1048&quot; data-start=&quot;1013&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;HTML은 텅 빈 상태로 전달하고&amp;nbsp; 자바스크립트로 렌더링을 진행한다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1078&quot; data-start=&quot;1049&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;클라이언트에서 fetch 요청하여 데이터를 처리한다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1106&quot; data-start=&quot;1079&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;초기 로딩은 느릴 수 있고, SEO에 불리하다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1135&quot; data-start=&quot;1107&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;대신 사용자 상호작용이 많은 부분에 적합하다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1167&quot; data-start=&quot;1136&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;'use client'로 클라이언트 컴포넌트를 명시해야한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Dev/Next.js</category>
      <author>odod00</author>
      <guid isPermaLink="true">https://chaechae0.tistory.com/37</guid>
      <comments>https://chaechae0.tistory.com/37#entry37comment</comments>
      <pubDate>Mon, 26 May 2025 17:04:59 +0900</pubDate>
    </item>
  </channel>
</rss>