몇 달 전부터 올릴려고 했던 글인데... 회사 법무팀의 허락을 받느라 좀 지체되었다. 드디어 올려도 된다는 허락을 받았으니.. 아싸 -_-;
배경
NVidia 텍스처 툴(NVTT)에 컨벌루션 영상처리 기법을 추가하게 된 계기는 회사에서 아티스트들의 요청 때문이었다. NVTT 1.0은 밉맵에 샤프닝(sharpening) 필터를 적용하는 옵션이 있었는데, NVTT 2.0에서는 삭제... (추후 추가할 예정이었으니 1년이 넘도록 추가되지 않음... -_-) NVTT가 오픈소스 프로젝트가 된 이후로는 개발도 뜸해서 이 기능이 추가되길 기다리기 보다는 직접 추가하기로 맘을 먹었다.
어차피 샤프닝 필터는 2D 커널을 이용한 컨벌루션에 지나지 않으니 차라리 보다 범용적인 컨벌루션 필터를 추가해서 아무 계수나 받는 게 낫다고 생각했다. 이러면 샤프닝 뿐만이 아니라 컨벌루션을 이용하는 영상처리 기법은 모두 돌릴 수 있으니....
NVTT 소스 코드 수정
자 그럼 본격적으로.. 실제 코드를 들여다 볼 시간.. 사실 별로 추가할 코드가 많진 않다. 6개 파일에 코드 몇줄만 추가하면 되니까...
Step 1. NVidia 텍스처 툴 프로젝트 웹페이지에서 revision 1277을 받는다.
최근 revision에서 이 코드를 테스트해보진 않았는데 별 차이는 없을거라 생각한다. NVTT 개발자가 소스코드 전체를 뒤집이 엎진 않은 이상... -_-;
Step 2. src/nvimage/Filter.h 파일을 열고 다음의 생성자를 추가한다.
Kernel2(uint width, const float * data);
Step 3. src/nvimage/Filter.cpp 파일 안에 다음의 함수를 추가한다.
Kernel2::Kernel2(uint ws, const float* data) : m_windowSize(ws)
{
m_data = new float[m_windowSize * m_windowSize];
memcpy(m_data, data, sizeof(float) * m_windowSize * m_windowSize);
}
Step 4. src/nvimage/FloatImage.h 파일 안에 다음 함수를 선언한다.
NVIMAGE_API void doConvolution(uint size, const float* data);
Step 5. src/nvimage/FloatImage.cpp 파일 안에 다음 함수를 구현한다.
void FloatImage::doConvolution(uint size, const float* data)
{
Kernel2 k(size, data);
AutoPtr tmpImage = clone();
for(uint y = 0; y < height(); y++)
{
for(uint x = 0; x < width(); x++)
{
for (uint c = 0; c < 4; ++c )
{
pixel(x, y, c) = tmpImage->applyKernel(&k, x, y, c, WrapMode_Clamp);
}
}
}
}
Step 6. src/nvtt/nvtt.h 파일 안에서 struct TexImage를 찾아 다음의 함수를 선언한다.
NVTT_API void doConvolution(unsigned int size, const float* data);
Step 7. src/nvtt/TexImage.cpp 파일 안에 다음 함수를 구현한다.
void TexImage::doConvolution(unsigned int size, const float* data)
{
if (m->image == NULL) return;
detach();
m->image->doConvolution(size, data);
}
사용법
새로 추가된 컨벌루션 필터를 사용하는 법은 매우 간단하다. 이미 image 라는 TexImage 개체가 있다면 간다히 이렇게 사용한다.
const int kernelSize = 3; // 3 x 3 커널을 사용한다.
// 대충 내 맘대로 찾아낸 샤프닝 계수.
const float sharpenKernel [] =
{
-1/16.0f, -2/16.0f, -1/16.0f,
-2/16.0f, 1 + 12/16.0f, -2/16.0f,
-1/16.0f, -2/16.0f, -1/16.0f,
};
image.doConvolution(kernelSize, sharpenKernel);
끝! (정말 간단하지? -_-)