프로그래밍

c언어/c++ 메디안필터

업글 2020. 12. 14. 00:04

안녕하세요 업글입니다! 이번 포스팅에서는 메디안 필터에 대해서 설명드리겠습니다.

 

메디안필터에 대한 설명

 

메디안필터는 데이터가 있을 때 데이터의 실제 값을 보다 정확하게 추정하기 위해서 사용됩니다.

신호는 실제 값에 노이즈들이 포함된 값을 가지게됩니다. 여기에서 노이즈들을 최대한 제거하고 신호의 실제 값을 획득하기위해서 사용되는필터입니다.

 

메디안필터는 주로 영상처리에서 많이 사용되지만 이번포스팅에서는 일반적인 신호처리 관점에서 설명드리겠습니다. 영상처리와 신호처리 둘다 개념은 동일함으로 이번포스팅으로 메디안필터에 대해서 이해하시면 영상처리의 응용에서도 쉽게 이해하실 수 있을거라 생각합니다.

 

이전 이동평균필터 포스팅에서 이동평균필터가 신호의 실제 값을 비슷하게 추정하는 것을 확인하실 수 있었습니다.

메디안필터는 노이즈를 제거하여 실제 값에 근사한 값을 추정하는 점에서 이동평균필터와 비슷하지만 메디안필터는 임펄스 잡음(순간적으로 값이 튀는 잡음)을 제거하는데에서 큰 효과를 가지게 됩니다.

 

메디안필터 결과는 메디안필터 구간의 값들을 정렬한 후 가운데 값을 선택하여 얻어지게 됩니다.

임펄스 잡음은 정렬 시 최소, 최대값 근처에 위치하게 될 확률이 높습니다. 이를 통해서 직관적으로 임펄스 잡음을 제거하는데 효과적이라는 것을 알 수 있습니다.

 

메디안필터 예시

 

메디안필터 예

예를 들어 위의 그림에서 메디안필터 구간의 크기가 3일 때 처음에 60,48,53을 정렬하여 중간에 위치하게 되는 값은 53이고 다음 1개 이동하여 48,53,57을 정렬하여 중간에 위치하는 값은 53이 되게 됩니다. 그 다음 1개씩 이동시켜가면서 정렬하여 중간에 위치하는 값을 구하여 메디안 필터 결과를 얻게됩니다.

 

메디안필터 적용 결과

 

메디안필터 적용 결과

위의 그림에서 파란색은 로우데이터인 센서값을 나타냅니다. 여기서 실제 값은 50이고 로우데이터는 실제 값에서 -10 ~ 10까지의 오차를 가지게됩니다. 주황색은 메디안필터의 구간을 10으로 적용한 결과입니다. 그림에서 보시는바와 같이 주황색의 경우 5개 이후부터 메디안필터의 값이 실제 값과 유사합니다. 초기에 메디안필터 배열의 값은 모두 0이고 센서값이 1개씩 들어올 마다 배열의 값이 1개씩 채워지기 때문입니다. 여기서 메디안필터 배열의 크기는 구간의 크기와 같습니다. 즉 구간이 10인 경우 배열의 크기는 10이 되게 됩니다.

 

메디안필터를 사용했을 때 실제 값인 50에 잡음이 섞인 센서값 보다 근사하게 추정됨을 확인하실 수 있습니다. 

 

메디안필터와 이동평균필터 결과 비교

 

메디안필터와 이동평균필터 결과

센서값의 실제 값은 50이고 5개 단위로 실제 값에 +50정도의 임펄스잡음이 발생한다고 가정하였습니다.

메디안필터와 이동평균필터의 구간은 동일하게 10으로 적용하였습니다.

결과에서 보시는바와 같이 이동평균필터의 경우 임펄스잡음으로 인해서 오차가 크게 발생하게됩니다. 반면에 메디안필터의 경우 임펄스잡음이 있음에도 불구하고 임펄스잡음 영향없이 실제값인 50에 근사하게 추정함을 확인하실수있습니다.

 

여기서 이동평균필터 대신 무조건 메디안필터를 사용하는 것이 좋겠다는 생각이 드시는 분들이 계실 것 같습니다.

위에서 설명드린바와 같이 메디안필터를 사용하기 위해서는 메디안필터 배열의 값들을 정렬해야합니다.

정렬을 하기위해서는 연산량이 많이 필요하게 되므로 메디안필터를 적용했을 때 연산시간에 문제가 없는지 꼭 확인하셔야합니다. 또한, 신호의 특징을 파악한 후 임펄스잡음이 없는 경우에는 굳이 메디안필터를 적용하지않고 이동평균필터를 적용해도 비슷한 결과를 얻을수 있다고 생각합니다.

 

메디안필터 코드

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#define FALSE (0)
#define TRUE (!FALSE)

typedef struct {
	int32_t data;
	uint32_t idx;
}ST_MedianData;

typedef struct {
	ST_MedianData* buffer;
	uint32_t length;
	uint32_t currentIdx;
	uint32_t centerIdx;
}ST_MedianFilter;

int32_t MedianFilterInit(ST_MedianFilter* medianFilter, uint32_t length)
{
	int32_t i;
	int32_t result = TRUE;

	medianFilter->length = length;
	medianFilter->centerIdx = length / 2;
	medianFilter->currentIdx = 0;

	medianFilter->buffer = (ST_MedianData*)malloc(length * sizeof(ST_MedianData));
	if (medianFilter->buffer == NULL) {
		result = FALSE;
	}
	else {
		for (i = 0; i < length; i++) {
			medianFilter->buffer[i].data = 0;
			medianFilter->buffer[i].idx = i;
		}
	}

	return result;
}

void MedianFilterDelete(ST_MedianFilter* medianFilter)
{
	free(medianFilter->buffer);
}

int32_t Compare(const void* first, const void* second)
{
	int32_t result;

	if (((ST_MedianData*)first)->data > ((ST_MedianData*)second)->data) {
		result = 1;
	}
	else if (((ST_MedianData*)first)->data < ((ST_MedianData*)second)->data) {
		result = -1;
	}
	else {
		result = 0;
	}

	return result;
}

int32_t MedianFilter(ST_MedianFilter* medianFilter, int32_t value)
{
	int32_t i;
	int32_t result;

	for (i = 0; i < medianFilter->length; i++) {
		if (medianFilter->buffer[i].idx == medianFilter->currentIdx) {
			medianFilter->buffer[i].data = value;
		}
	}

	medianFilter->currentIdx++;
	medianFilter->currentIdx %= medianFilter->length;

	qsort(medianFilter->buffer, medianFilter->length, sizeof(medianFilter->buffer[0]), Compare);

	result = medianFilter->buffer[medianFilter->centerIdx].data;

	return result;
}

int main()
{
	int32_t InitResult = 0;
	int32_t sensorOutput = 0;
	ST_MedianFilter medianFilter;

	InitResult = MedianFilterInit(&medianFilter, 10);
	if (InitResult == FALSE) {
		printf("Fail MovingAverage[0] Init\n");
		return 0;
	}

	for (int i = 0; i < 100; i++) {
		if (i % 5 == 0) {
			sensorOutput = 50 + 50 + (rand() % 21);
		}
		else {
			sensorOutput = 50 + (rand() % 21 - 10);
		}

		printf("%d, %d, %d\n", i, sensorOutput, MedianFilter(&medianFilter, sensorOutput));
	}

	MedianFilterDelete(&medianFilter);

	return 0;
}

이상 메디안필터에 대한 설명을 마치겠습니다. 다음에는 연산시간을 줄이기 위한 메디안필터에 대해서 설명드리겠습니다.

'프로그래밍' 카테고리의 다른 글

c언어/c++ if 조건문  (0) 2020.12.17
c언어/c++ 속도 최적화 메디안필터  (0) 2020.12.16
c언어/c++ 이동평균필터  (0) 2020.12.13
c언어/c++ 함수포인터  (0) 2020.11.26
c언어/c++ sizeof  (0) 2020.11.12