본문 바로가기
Various Developments/3D Moire Scanner

3D Moire Scanner 개발 - 높이 맵(Height Map) 계산

by 토담이아빠 2023. 2. 10.

 

이번 포스팅에서는 지난 시간 계산 했던 위상 맵에 이어 이를 활용한 최종 높이 맵을 계산하는 과정에 대해서 정리했습니다.


위상 펼침(Phase Unwrapping)

 

지난 시간 계산했던 위상맵은 한 가지 문제점이 있습니다. 그것은 위상이 주기적으로 반복된다는 것입니다. 위상맵의 한 단면을 Profiling 해보면 다음과 같습니다.


위상맵 단면 Profile


위상과 높이의 관계는 서로 비례 관계라서 위 위상처럼 주기적으로 나타나게 되면 높이 또한 주기적으로 변하는 모습을 갖게 됩니다. 따라서 이런 주기적인 위상들을 서로 이어서 주기성을 없애야 합니다. 이것을 위상펼침(Phase Unwrapping)이라고 합니다.


위상펼침 개념도


개념은 매우 간단해 보이나 실제 적용 시에는 2D map의 노이즈와 주변 픽셀과의 관계들도 고려해야 하는 등 상당히 고급 알고리즘이 적용됩니다. 아래는 github.com에서 찾은 'C'언어로 작성된 unwrap 알고리즘 코드입니다. 


https://github.com/geggo/phase-unwrap/blob/master/unwrap/unwrap2D.c

 

GitHub - geggo/phase-unwrap

Contribute to geggo/phase-unwrap development by creating an account on GitHub.

github.com


아래는 위 링크에 있는 unwrap을 수행하는 함수 코드입니다. (먼가 복잡해 보이지만 유저 입장에서는 input/output 만 잘 설정하면 되니 사용 시 문제는 없을 거라고 봅니다.^^;)


void unwrap2D(float* wrapped_image, float* UnwrappedImage, unsigned char* input_mask,
	 int image_width, int image_height,
	 int wrap_around_x, int wrap_around_y)
{
	params_t params = { 2*PI, wrap_around_x, wrap_around_y, 0 };
	unsigned char *extended_mask;
	PIXELM *pixel = nullptr;
	EDGE *edge = nullptr;
	int image_size = image_height * image_width;
	int No_of_Edges_initially = 2 * image_width * image_height;
	
	extended_mask = (unsigned char *)calloc(image_size, sizeof(unsigned char));
	pixel = (PIXELM *)calloc(image_size, sizeof(PIXELM));
	edge = (EDGE *)calloc(No_of_Edges_initially, sizeof(EDGE));
	
	extend_mask(input_mask, extended_mask, image_width, image_height, &params);
	initialisePIXELs(wrapped_image, input_mask, extended_mask, pixel, image_width, image_height);
	calculate_reliability(wrapped_image, pixel, image_width, image_height, &params);
	horizontalEDGEs(pixel, edge, image_width, image_height, &params);
	verticalEDGEs(pixel, edge, image_width, image_height, &params);
	
	if (params.no_of_edges > 0)
	{
		quicker_sort(edge, edge + params.no_of_edges - 1);
 		gatherPIXELs(edge, &params);
 		unwrapImage(pixel, image_width, image_height);
		maskImage(pixel, input_mask, image_width, image_height);
 		returnImage(pixel, UnwrappedImage, image_width, image_height);
	}
 	
	free(edge);
	free(pixel);
	free(extended_mask);
}

위 함수를 이용하여 앞서 구한 동전 위상맵을 unwrapping 하였습니다. 


위상 펼침 적용


높이 맵(Height Map) 계산

 

이제 높이 맵을 구하면 될 것 같은데... 이 상태로도 문제가 있습니다.  위에서 언급했듯이 높이와 위상의 관계는 비례관계(g, L, d 전부 상수)로 아래 수식에 그대로 적용해도 위상 펼침 맵처럼 기울어져 나타난다는 것입니다. 



다시 말해서 수평으로 평평한 면을 측정해도 사선으로 기울어진 면이 나타납니다. 따라서 이런 기울기 속성을 없애기 위해 Reference면을 새로 측정해서 빼주는 추가적인 작업을 진행했습니다.


동전 위상에서 Reference 위상을 빼준다

결과

 

높이 맵(Height Map)


중간중간 노이즈에 대한 처리도 했지만 완벽하게 처리가 되지는 않았습니다. 아무래도 광포화가 일어나서 데이터가 손상된 부분이 노이즈 처리 영역보다 크기 때문인 것 같습니다.


노이즈 영역 - 광포화


경험적으로 금속성 재질은 반사율이 높아서 모아레 방식으로 측정하기에는 불리한 점이 있는 것 같습니다. (이렇게 만들어 보면서 하나씩 알아가게 되네요.)

 

여기에서 구한 높이 맵은 높이 정보가 있을 뿐 완전한 3D는 아닙니다 (2.5D가 적당할 것 같네요.). 다음 개발은 이 높이 맵을 3D로 볼 수 있게 간단한 3D viewer를 만들어 볼까 생각 중입니다. 

댓글