* Volume의 특성
- 차원(dimension)
- 범위(extent)
- Voxel 크기(size)/공간(spacing)
- 데이터 타입(data type)
- 데이터 범위(data range)
- GPU에서의 data
* 차원(Dimensions)
- Volume의 차원(각 축에 대한 Voxel의 수)은 보통 데이터 파일에서의 정보로부터 Volume 리더에 의해 결정
- 스택에서의 이미지 수
- 데이터 필드를 이용해서 Volume 차원을 쿼리할 수 있다
SbVec3i32 volumeDimension = pVolumeData->data.getSize();
* 범위(Extent)
- 3D에서 Volume의 기하학적 범위는 Volume 리더에 의해 초기에 결정
- extent 필드를 사용하여 설정 가능
- Volume 범위는 월드 공간에서 Volume의 경계 박스(bounding box)
- 종종 3D에서 Volume 범위는 Volume의 차원과 같게 설정됨
- 또는 Volume 차원에 비례하여 값을 설정
- Volume 범위는 어떤 범위든 될 수 있음
- Volume 범위는 간접적으로 Voxel 크기/공간을 지정
- extent 필드를 사용하여 Volume 범위를 쿼리
SbBox3f volumeExtent = pVolumeData->extent.getValue();
* Voxel 크기(size)/공간(spacing)
- 만약 Volume 데이터가 균일하게 샘플링되면, Voxel 크기는 Volume 범위를 Volume 차원으로 나눈 값
- Voxel 크기는 각 축에 따라 여전히 균일하지만, 최소한 한 축에 따라 다름
- 이것은 Volume Z 축을 따라 더 큰 공간을 가지는 의료 스캐너 Volume 의 전형
- 그러나 Volume 범위는 응용 프로그램에 의해 정해지고 심지어 실시간으로 바뀜
- VolumeViz는 균일적으로 Voxel에 한계가 있지 않음
- VolumeViz는 또한 "직사각 좌표"(rectilinear coordinates) 를 지원
여기서 각축에 따라 비균일(non-uniform) voxel위치가 구체적으로 주어짐
- 이 정보는 Volume 리더에 의해 제공
- 쿼리 방법
SoVolumeData의 함수 getCoordinateType() 과 getRectilinearCoordinates() 함수를 사용
* 데이터 타입(Data Type)
- VolumeViz는 부호 있고(signed)와 부호 없는(unsigned) 정수 값
(byte, short, int) 또는 부동 소수점 값을 지원
- VolumeViz는 32비트에 알파 값을 포함하는 RGBA Volume 을 지원
- 데이터 타입은 리더(reader)에 의해 결정 (data 필드를 설정할 때)
- 쿼리 방법(데이터 타입, Voxel당 바이트 수)
int bytesPerVoxel = pVolumeData->getDataSize();
SoDataSet::DataType type = pVolumeData->getDataType();
* 데이터 범위(Data Range)
- 바이트보다 더 큰 데이터 타입을 사용하는 Volume에서, 데이터 값의 실제 범위는 보통 데이터 타입의 범위보다 더 작음
- 응용프로그램은 transfer function에 매핑될 값의 범위를 정하기 위해 SoDataRange 노드를 사용
- 쿼리 방법
double minVal, maxVal;
SbBool ok = pVolumeData->getMinMax(minVal, maxVal);
- 만약 getMinMax( ) 쿼리가 반응하지 않으면, 이 함수는 전체 데이터 집합을 메모리로 로딩시키는 것을 VolumeViz에 강제시키고,
최소, 최대 값을 계산하기 위해 모든 voxel을 통해 스캔함
* GPU에서의 데이터
- 디폴트적으로, VolumeViz는 8비트보다 더 큰 모든 타입의 데이터 값을 8 비트 부호없는 정수(8-bit unsigned integer) 값으로 GPU에 스케일링함
- 렌더링 목적을 위해 이것은 보통 충분하고
작은 데이터 타입을 사용하는 것은 GPU 위의 사용가능한 메모리에서
로딩될 수 있는 데이터의 양을 최대화함
- 만약 필요하다면 SoVolumeData 노드의 texturePrecision 필드를
설정함으로써 12 비트 정수 값을 사용할 수 있음
- 주의 : 12 비트 옵션은 실질적으로 데이터를 저장하기 위해 16비트 텍스처를 사용한다. 그래서 이 경우에는 GPU에서 필요한 메모리는 2배가 됨
- 개념적으로 고려할 이슈는 (데이터 타입과 데이터 범위(range)에 의존하여) 실질적인 데이터 값의 범위는 각 GPU 값 위에 "aliased" 될 수 있음
- 예를 들어 32 에서 47까지의 범위에 있는 모든 데이터 값은 GPU 메모리에서 32로 끝날 수 있음
- 렌더링을 위해 GPU에서 더 큰 데이터 타입을 사용하는 것의 주요 장점은 더 크고 더 정확한 컬러 맵을 이용하기 위해서임
- 요약하면, 디폴트 데이터 저장공간은 256개의 다른 값을 허락하고 12 비트 저장공간은 4096의 값을 허락한다
- 관련있는 노드, 필드, 함수와 관련 있는 다양한 특징의 링크
* Volume Data
- volume 데이터에 접근하기 위한 SoVolumeData 노드를 사용하라
* 데이터 Volume 은 다음에 의해 주어질 수 있다
- 파일 이름
- Volume 리더
- 메모리 블럭
- LDM 포맷으로 변경
* Volume 속성
- 크기(Size) : 각 축에서 Voxel의 개수
- 범위(Extent) : 3D 공간에서 Volume의 기하학적 범위
- Voxel 크기(size)/공간(spacing) : 각 축에 따라 균일할 수도 있고,
다를 수도 있음
- Data 타입 : 정수 또는 소수점 스칼라 값, RGBA 값, boolean 값(mask)
- 중요한(significant) 비트 들의 수 : 16 비트 워드 안에서 12 비트 값
- Data Range : 색상 테이블에 맵핑되는 값들의 실제 영역
* VolumeViz Scene Graph
* Volume 데이터를 로딩하는 가장 간단한 방법
- Volume은 디스크에 저장
- SoVolumeReader 클래스를 이용
- 응용 프로그램은 각자 자신의 Volume 리더 클래스를 생성할 수 있음
- 파일 확장자에 기초한 Volume 리더 클래스 선택
- ".ldm" 파일을 위해 SoVRLdmFileReader 클래스 사용
- SoVolumeData::filename 필드에 설정 예제
* 논의할 내용
- 파일 포맷
- 비표준 확장자를 가진 파일 로딩
- "raw" 데이터(no header) 로딩
- 이미지 스택 로딩
- RGBA 데이터
* 파일 포맷
- VolumeViz 파일 리더
- 파일 이름 확장자에 리더 클래스가 관련
File extension | Reader class | Description |
---|---|---|
.am | SoVRAmFileReader | Avizo Mesh file format |
.dc3, .dic, .dicom | SoVRDicomFileReader | DICOM file format |
.fld | SoVRAvsFileReader | AVS field file format |
.ldm | SoVRLdmFileReader | Large Data Management format |
.sgy or .segy | SoVRSegyFileReader | SEG Y revision 1 file format |
.vol | SoVRVolFileReader | Vol file format |
.vox | SoVRVoxFileReader | Vox file format |
.lst | SoVRRasterStackReader | Lst file format |
* 비표준 확장자
- 만약 파일 이름이 확장자를 가지고 있지 않거나 적당한 확장자를 가지고 있지 않다면, 응용 프로그램은 파일을 로딩하기 위해 여전히 특별한 Volume 리더를 사용할 수 있다
- 그러나 SoVolumeData 노드의 setReader() 함수를 이용하여 구체적으로 Volume 리더를 설정해야 한다
- 예를 들어 Volume 파일이 VOL 포맷을 가진 데이터를 포함하지만 파일 이름이 정확한 확장자를 가지고 있지 않다면,
VolumeViz는 VOL 포맷으로 데이터를 읽게 하기 위해 다음 코드는 강제한다
* Raw 데이터
- 만약 파일이 VolumeViz가 직접적으로 지원하는 포맷이 아니지만,
행 x 행 으로 조직된 값들의 연속적인 블럭으로 Volume 데이터를 포함하면
일반적인 리더 SoVRGenericFileReader 를 이용할 수 있다
- 이것은 보통 "raw" 데이터파일로 불린다
- Volume의 범위(extent), 데이터 타입, 차원(dimension)을 구체화할 필요
- 다음 코드는 일반 리더(generic reader)를 이용하여 데이터를 로드
* 이미지 스택
- Volume이 여러 개(multiple)의 이미지 파일로 저장되었다면,
SoVRRasterStackReader 클래스를 사용
- 이미지 스택을 로딩하는데 유용
- Open Inventor가 지원하는 이미지 파일 : JPEG, PNG, TIFF
- 이미지들의 포맷은 다를 수 있어도 같은 사이즈여야만 함
- 이미지 크기는 X, Y dimension
- Z dimension은 슬라이스의 수
- 이미지 스택을 로딩하기 위해 이미지 파일 이름들의 리스트를 포함하는 파일이 존재해야 함
- 이미지 파일 이름은 간단한 파일 이름이 될 수도 있고, 완전한 파일 경로가 될 수도 있다
- 만약 이미지 파일 이름이 간단한 파일 이름이라면, VolumeViz는 리스트 파일을 포함하는 디렉토리에서 오픈할 수 있다
- 리스트 파일에서 파일 이름의 순서는 어떻게 슬라이스를 로딩할지를 결정
- VolumeViz는 첫 번째 이미지가 슬라이스 0이고, Volume의 "뒤"이고 연속적인 슬라이스가 Z 값이 증가하는 순서로 로딩한다고 가정
- 테디 베어 예제 데이터
- 리스트 파일은 다음과 같고, 여기에서 "Size" 파라미터는 범위를 의미
Parameters { Size 10.000000 10.000000 10.000000 1250.000000 1250.000000 500.000000 } teddybear000.jpg teddybear001.jpg teddybear002.jpg teddybear003.jpg teddybear004.jpg ...
- 일단 리스트 파일을 가지면, 데이터를 로딩하는 것은 이전 예제와 같다
* RGBA 데이터
- RGBA Volume에서 Voxel은 UNSIGNED_INT32 값이다
- 각 값은 8bit Red, Green, Blue 그리고 Alpha 값을 포함
- 모든 렌더링 노드(slices, volume rendering, 등등)는 RGBA volume을 가지고 작업
- Region of Interest, Clipping 그리고 다른 특징들도 또한 RGBA volume을 가지고 작업
- Volume은 이미 렌더링에 사용될 색을 지정했기 때문에,
Data Range와 Transfer Function은 무시한다
void main()
{
#if defined(WIN32) || defined(WIN64)
#ifdef _DEBUG
#include <crtdbg.h>
// _CRTDBG_ALLOC_MEM_DF ==> _CLIENT_BLOCK 에 메모리를 할당에 대해서 덤프
// _CRTDBG_LEAK_CHECK_DF ==> 프로그램이 종료될 때 자동으로 _CrtDumpMemoryLeaks() 를 호출하여 메모리 누수시 덤프
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
// 해제 안되는 new 의 파일과 라인수를 파악한다.
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
// 메모리 누수시 블록숫자값(출력창의{1234})을 주면 메모리 공간을 확보하는 시점에 브레이크포인트가 걸린다.
_CrtSetBreakAlloc(1359);
#endif
#endif
}
문서 파일 객체 - 응용 프로그램이 생성
NewDocument() 함수
-> 운영체제가 어떤 응용 프로그램을 생성하던지 상관없이 똑같이 호출
NewDocument() 함수 구현
-> 응용 프로그램에 따라 고유한 문서 파일 객체를 생성
=> 운영체제가 호출하는 인터페이스는 응용 프로그램에 상관없이 동일하게 유지되면서, 응용 프로그램마다 생성되는 객체는 각 응용 프로그램마다 고유하게 만들어지도록 하는가?
=> 운영체제가 호출하는 NewDocument() 인터페이스를 어떻게 배치,
어떻게 구현
* HwpApplication 클래스 -> HwpDocument 객체 생성
* MsWordApplication 클래스 -> MsWordDocument 객체 생성
1. 응용 프로그램마다 NewDocument() 멤버 함수 구현