본문 바로가기
프로그래밍/ITK

버퍼로부터 이미지 데이터 가져오기

by 이재만박사 2016. 7. 2.

- 이 부분에 대한 소스 코드는 다음 파일에서 찾을 수 있다

- Examples/DataRepresentation/Image/Image5.cxx

 

- 이 예제는 itk::Image 클래스에서 데이터를 가져오는 방법을 보여준다

- 이것은 특별히 다른 소프트웨어 시스템과 인터페이스 하는데에 유용하다

- 많은 시스템은 이미지 픽셀 데이터에 대해 버퍼로 메모리의 인접한 블럭을 사용한다

- 현재의 예제는 이 경우라고 가정하고 버퍼를 itk::ImportImageFilter로 제공한다. 그렇게 함으로써 결과물로 이미지를 생성한다

 

- 재미를 위해 우리는 지역적으로 할당된 버퍼에서 중심에 구를 가진 합성 이미지를 생성하고 메모리의 이 블럭에 ImportImageFilter로 통과한다

- 이 예제는 실행을 위해 설정하고, 사용자는 명령어 라인 파라미터로 출력 파일의 이름을 제공해야 한다

 

- 첫째로, ImportImageFilter 클래스의 헤더 파일을 포함해야 한다

 

#include "itkImage.h"

#include "itkImportImageFilter.h"

 

- 다음에, 우리는 이미지 픽셀을 나타내기 위해 사용하는 데이터 타입을 선택한다

- 우리는 메모리의 외부 블럭이 픽셀을 나타내기 위해 같은 데이터 타입을 사용한다고 가정한다

 

typedef unsigned char PixelType;

const unsigned int Dimension = 3;

typedef itk::Image< PixelType, Dimension > ImageType;

 

- ImportImageFilter의 타입은 다음 줄에서 인스턴스화된다

 

typedef itk::ImportImageFilter< PixelType, Dimension > ImportFilterType;

 

- 그리고 나서 New() 메서드를 사용하여 생성된 필터 객체는 SmartPointer에 할당된다

 

ImportFilterType::Pointer importFilter = ImportFilterType::New();

 

- 이 필터는 사용자가 결과물로 생성된 이미지의 크기를 지정하는 것을 요구한다

- SetRegion() 메서드는 이 끝에 사용된다

- 이미지 크기는 정확히 지역적으로 할당된 버퍼 안에 사용 가능한 픽셀의 수와 매칭되어야 한다

 

ImportFilterType::SizeType size;

 

size[0] = 200;

size[1] = 200;

size[2] = 200;

 

ImportFilterType::IndexType start;

start.Fill( 0 );

 

ImportFilterType::RegionType region;

region.SetIndex( start );

region.SetSize( size );

 

importFilter->SetRegion( region );

 

- 결과 이미지의 원점은 SetOrigion() 메서드를 가지고 지정한다

 

double origin[ Dimension ];

origin[0] = 0.0;

origin[1] = 0.0;

origin[2] = 0.0;

 

importFilter->SetOrigin( origin );

 

- 이미지의 공간은 SetSpacing() 메서드를 가지고 통과된다

 

double spacing[ Dimension ];

spacing[0] = 1.0;

spacing[1] = 1.0;

spacing[2] = 1.0;

 

importFilter->SetSpacing( spacing );

 

- 다음에 우리는 ImportImageFilter에 전달하기 위한 픽셀 데이터를 포함하는 메모리 블럭을 할당한다

- 우리는 SetRegion() 메서드를 가지고 지정된 같은 크기를 정확히 사용한다는 것을 주목하라

- 실제 응용 프로그램에서 이미지를 나타내기 위해 다른 데이터 구조를 사용하여 일부 다른 라이브러리로부터 이 버퍼를 얻을 수 있다

 

const unsigned int numberOfPixels = size[0] * size[1] * size[2];

PixelType* localBuffer = new PixelType [ numberOfPixels ];

 

- 여기에서 우리는 바이너리 구로 버퍼를 채울 것이다

- ITK는 픽셀에 접근하기 위해 내부 코드 내에서 for 루프를 사용하지 않는 다는 것을 주목하라

- 모든 픽셀 접근 방법은 n 차원 이미지의 관리를 지원하는 itk::ImageIterator를 사용하여 대신 수행된다

 

const double radius2 = radius * radius;
PixelType * it = localBuffer;

for(unsigned int z=0; z < size[2]; z++)
{
    const double dz = static_cast<double>( z ) - static_cast<double>(size[2])/2.0;
    for(unsigned int y=0; y < size[1]; y++)
    {
        const double dy = static_cast<double>( y ) - static_cast<double>(size[1])/2.0;
        for(unsigned int x=0; x < size[0]; x++)

        {
            const double dx = static_cast<double>( x ) - static_cast<double>(size[0])/2.0;
            const double d2 = dx*dx + dy*dy + dz*dz;
            *it++ = ( d2 < radius2 ) ? 255 : 0;
        }
    }
}

 

- 그 버퍼는 SetImportPointer()를 가지고 ImportImageFilter에 전달된다

- 메모리 블럭을 적절하게 삭제하기 위해, 메모리는 C++ new() 연산자를 가지고 할당된 메모리여야 한다

- C malloc 또는 calloc 과 같은, 다른 메모리 할당 메커니즘을 가지고 할당된 메모리는 ImportImageFilter는 적절히 삭제될 수 업스을 것이다

- 다르게 말하면, C++ new 연산자로 할당된 메모리를 삭제하기 위한 ImportImageFilter가 오직 허가가 주어지는 것은 오직 응용 프로그램 프로그래머의 책임이다

 

const bool importImageFilterWillOwnTheBuffer = true;
importFilter->SetImportPointer(localBuffer, numberOfPixels, importImageFilterWillOwnTheBuffer);

 

- 마지막으로 우리는 파이프라인에 이 필터의 결과물을 연결할 수 있다

- 간단한 것을 위해 우리는 단지 여기에서 writer를 사용한다

- 그러나 그것은 어떤 다른 필터도 될 수 있다

 

writer->SetInput( importFilter->GetOutput() );

 

- 우리는 버퍼에 delete 를 호출하지 않는 것에 주목하라. 왜냐하면 SetImportPointer() 의 마지막 전달인자로 true를 넣기 때문이다

- 지금 그 버퍼는 ImportImageFilter에 의해 소유된다

댓글